/*
 * JBoss, Home of Professional Open Source
 * Copyright 2011, Red Hat, Inc. and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.mobicents.slee.container.component;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.slee.ComponentID;
import javax.slee.EventTypeID;
import javax.slee.SbbID;
import javax.slee.ServiceID;
import javax.slee.UnrecognizedComponentException;
import javax.slee.management.DeploymentMBean;
import javax.slee.management.LibraryID;
import javax.slee.profile.ProfileSpecificationID;
import javax.slee.resource.ResourceAdaptorID;
import javax.slee.resource.ResourceAdaptorTypeID;

import org.mobicents.slee.container.component.ComponentRepository;
import org.mobicents.slee.container.component.SleeComponent;
import org.mobicents.slee.container.component.event.EventTypeComponent;
import org.mobicents.slee.container.component.library.LibraryComponent;
import org.mobicents.slee.container.component.profile.ProfileSpecificationComponent;
import org.mobicents.slee.container.component.ra.ResourceAdaptorComponent;
import org.mobicents.slee.container.component.ratype.ResourceAdaptorTypeComponent;
import org.mobicents.slee.container.component.sbb.SbbComponent;
import org.mobicents.slee.container.component.service.ServiceComponent;

/**
 * Implementation of the repository to manage all SLEE components.
 *
 * @author martins
 *
 */
public class ComponentRepositoryImpl implements ComponentRepository {

	/**
	 * the {@link EventTypeComponent}s stored in the repository
	 */
	private final ConcurrentHashMap<EventTypeID, EventTypeComponent> eventTypeComponents = new ConcurrentHashMap<EventTypeID, EventTypeComponent>();

	/**
	 * the {@link ProfileSpecificationComponent}s stored in the repository
	 */
	private final ConcurrentHashMap<ProfileSpecificationID, ProfileSpecificationComponent> profileSpecificationComponents = new ConcurrentHashMap<ProfileSpecificationID, ProfileSpecificationComponent>();

	/**
	 * the {@link LibraryComponent}s stored in the repository
	 */
	private final ConcurrentHashMap<LibraryID, LibraryComponent> libraryComponents = new ConcurrentHashMap<LibraryID, LibraryComponent>();

	/**
	 * the {@link ResourceAdaptorTypeComponent}s stored in the repository
	 */
	private final ConcurrentHashMap<ResourceAdaptorID, ResourceAdaptorComponent> resourceAdaptorComponents = new ConcurrentHashMap<ResourceAdaptorID, ResourceAdaptorComponent>();

	/**
	 * the {@link ResourceAdaptorTypeComponent}s stored in the repository
	 */
	private final ConcurrentHashMap<ResourceAdaptorTypeID, ResourceAdaptorTypeComponent> resourceAdaptorTypeComponents = new ConcurrentHashMap<ResourceAdaptorTypeID, ResourceAdaptorTypeComponent>();

	/**
	 * the {@link SbbComponent}s stored in the repository
	 */
	private final ConcurrentHashMap<SbbID, SbbComponent> sbbComponents = new ConcurrentHashMap<SbbID, SbbComponent>();

	/**
	 * the {@link ServiceComponent}s stored in the repository
	 */
	private final ConcurrentHashMap<ServiceID, ServiceComponent> serviceComponents = new ConcurrentHashMap<ServiceID, ServiceComponent>();

	// ----

	public EventTypeComponent getComponentByID(EventTypeID id) {
		return eventTypeComponents.get(id);
	}

	public ProfileSpecificationComponent getComponentByID(
			ProfileSpecificationID id) {
		// avoid null-pointer exception with ConcurrentHashMap
		ProfileSpecificationComponent component = null;
		try {
			component = profileSpecificationComponents.get(id);
			return component;
		} catch (NullPointerException npe) {
			return null;
		}
	}

	public LibraryComponent getComponentByID(LibraryID id) {
		return libraryComponents.get(id);
	}

	public ResourceAdaptorComponent getComponentByID(ResourceAdaptorID id) {
		return resourceAdaptorComponents.get(id);
	}

	public ResourceAdaptorTypeComponent getComponentByID(
			ResourceAdaptorTypeID id) {
		return resourceAdaptorTypeComponents.get(id);
	}

	public SbbComponent getComponentByID(SbbID id) {
		return sbbComponents.get(id);
	}

	public ServiceComponent getComponentByID(ServiceID id) {
		return serviceComponents.get(id);
	}

	// ----

	public Set<EventTypeID> getEventComponentIDs() {
		return eventTypeComponents.keySet();
	}

	public Set<ProfileSpecificationID> getProfileSpecificationIDs() {
		return profileSpecificationComponents.keySet();
	}

	public Set<LibraryID> getLibraryIDs() {
		return libraryComponents.keySet();
	}

	public Set<ResourceAdaptorID> getResourceAdaptorIDs() {
		return resourceAdaptorComponents.keySet();
	}

	public Set<ResourceAdaptorTypeID> getResourceAdaptorTypeIDs() {
		return resourceAdaptorTypeComponents.keySet();
	}

	public Set<SbbID> getSbbIDs() {
		return sbbComponents.keySet();
	}

	public Set<ServiceID> getServiceIDs() {
		return serviceComponents.keySet();
	}

	public boolean isInstalled(ComponentID componentID) {

		SleeComponent component = null;
		if (componentID instanceof EventTypeID) {
			component = getComponentByID((EventTypeID) componentID);
		} else if (componentID instanceof LibraryID) {
			component = getComponentByID((LibraryID) componentID);
		} else if (componentID instanceof ProfileSpecificationID) {
			component = getComponentByID((ProfileSpecificationID) componentID);
		} else if (componentID instanceof ResourceAdaptorID) {
			component = getComponentByID((ResourceAdaptorID) componentID);
		} else if (componentID instanceof ResourceAdaptorTypeID) {
			component = getComponentByID((ResourceAdaptorTypeID) componentID);
		} else if (componentID instanceof SbbID) {
			component = getComponentByID((SbbID) componentID);
		} else if (componentID instanceof ServiceID) {
			component = getComponentByID((ServiceID) componentID);
		}

		return component != null;
	}

	/**
	 * @see DeploymentMBean#getReferringComponents(ComponentID)
	 * @param componentID
	 * @return
	 */
	public ComponentID[] getReferringComponents(ComponentID componentID)
			throws NullPointerException, UnrecognizedComponentException {
		if (componentID == null) {
			throw new NullPointerException("null componentID");
		} else {
			SleeComponent component = null;
			if (componentID instanceof EventTypeID) {
				component = getComponentByID((EventTypeID) componentID);
			} else if (componentID instanceof LibraryID) {
				component = getComponentByID((LibraryID) componentID);
			} else if (componentID instanceof ProfileSpecificationID) {
				component = getComponentByID((ProfileSpecificationID) componentID);
			} else if (componentID instanceof ResourceAdaptorID) {
				component = getComponentByID((ResourceAdaptorID) componentID);
			} else if (componentID instanceof ResourceAdaptorTypeID) {
				component = getComponentByID((ResourceAdaptorTypeID) componentID);
			} else if (componentID instanceof SbbID) {
				component = getComponentByID((SbbID) componentID);
			} else if (componentID instanceof ServiceID) {
				component = getComponentByID((ServiceID) componentID);
			}

			if (component == null) {
				throw new UnrecognizedComponentException(componentID.toString());
			} else {
				Set<SleeComponent> referringComponents = getReferringComponents(component);
				ComponentID[] result = new ComponentID[referringComponents.size()];
				int i = 0;
				for (SleeComponent referringComponent : referringComponents) {
					result[i] = referringComponent.getComponentID();
					i++;
				}
				return result;
			}
		}
	}

	/**
	 * Retrieves the component ids for components that refers the specified component
	 */
	public Set<SleeComponent> getReferringComponents(SleeComponent component) {

		Set<SleeComponent> result = new HashSet<SleeComponent>();
		for (EventTypeComponent otherComponent : eventTypeComponents.values()) {
			if (!otherComponent.getComponentID().equals(
					component.getComponentID())) {
				if (otherComponent.getDependenciesSet().contains(
						component.getComponentID())) {
					result.add(otherComponent);
				}
			}
		}
		for (LibraryComponent otherComponent : libraryComponents.values()) {
			if (!otherComponent.getComponentID().equals(
					component.getComponentID())) {
				if (otherComponent.getDependenciesSet().contains(
						component.getComponentID())) {
					result.add(otherComponent);
				}
			}
		}
		for (ProfileSpecificationComponent otherComponent : profileSpecificationComponents
				.values()) {
			if (!otherComponent.getComponentID().equals(
					component.getComponentID())) {
				if (otherComponent.getDependenciesSet().contains(
						component.getComponentID())) {
					result.add(otherComponent);
				}
			}
		}
		for (ResourceAdaptorComponent otherComponent : resourceAdaptorComponents
				.values()) {
			if (!otherComponent.getComponentID().equals(
					component.getComponentID())) {
				if (otherComponent.getDependenciesSet().contains(
						component.getComponentID())) {
					result.add(otherComponent);
				}
			}
		}
		for (ResourceAdaptorTypeComponent otherComponent : resourceAdaptorTypeComponents
				.values()) {
			if (!otherComponent.getComponentID().equals(
					component.getComponentID())) {
				if (otherComponent.getDependenciesSet().contains(
						component.getComponentID())) {
					result.add(otherComponent);
				}
			}
		}
		for (SbbComponent otherComponent : sbbComponents.values()) {
			if (!otherComponent.getComponentID().equals(
					component.getComponentID())) {
				if (otherComponent.getDependenciesSet().contains(
						component.getComponentID())) {
					result.add(otherComponent);
				}
			}
		}
		for (ServiceComponent otherComponent : serviceComponents.values()) {
			if (!otherComponent.getComponentID().equals(
					component.getComponentID())) {
				if (otherComponent.getDependenciesSet().contains(
						component.getComponentID())) {
					result.add(otherComponent);
				}
			}
		}
		return result;
	}

	// ----

	public boolean putComponent(EventTypeComponent component) {
		return eventTypeComponents.putIfAbsent(component.getEventTypeID(),
				component) == null;
	}

	public boolean putComponent(ProfileSpecificationComponent component) {
		return profileSpecificationComponents.putIfAbsent(component
				.getProfileSpecificationID(), component) == null;
	}

	public boolean putComponent(LibraryComponent component) {
		return libraryComponents.putIfAbsent(component.getLibraryID(),
				component) == null;
	}

	public boolean putComponent(ResourceAdaptorComponent component) {
		return resourceAdaptorComponents.putIfAbsent(component
				.getResourceAdaptorID(), component) == null;
	}

	public boolean putComponent(ResourceAdaptorTypeComponent component) {
		return resourceAdaptorTypeComponents.putIfAbsent(component
				.getResourceAdaptorTypeID(), component) == null;
	}

	public boolean putComponent(SbbComponent component) {
		return sbbComponents.putIfAbsent(component.getSbbID(), component) == null;
	}

	public boolean putComponent(ServiceComponent component) {
		return serviceComponents.putIfAbsent(component.getServiceID(),
				component) == null;
	}

	// ----

	public void removeComponent(EventTypeID componentID) {
		eventTypeComponents.remove(componentID);
	}

	public void removeComponent(ProfileSpecificationID componentID) {
		profileSpecificationComponents.remove(componentID);
	}

	public void removeComponent(LibraryID componentID) {
		libraryComponents.remove(componentID);
	}

	public void removeComponent(ResourceAdaptorID componentID) {
		resourceAdaptorComponents.remove(componentID);
	}

	public void removeComponent(ResourceAdaptorTypeID componentID) {
		resourceAdaptorTypeComponents.remove(componentID);
	}

	public void removeComponent(SbbID componentID) {
		sbbComponents.remove(componentID);
	}

	public void removeComponent(ServiceID componentID) {
		serviceComponents.remove(componentID);
	}

	@Override
	public String toString() {
		return "Component Repository: "
			+ "\n+-- Event Type Components: " + getEventComponentIDs()
			+ "\n+-- Library Components: " + getLibraryIDs()
			+ "\n+-- Profile Specification Components: " + getProfileSpecificationIDs()
			+ "\n+-- Resource Adaptor Components: " + getResourceAdaptorIDs()
			+ "\n+-- Resource Adaptor Type Components: " + getResourceAdaptorTypeIDs()
			+ "\n+-- Sbb Components: " + getSbbIDs()
			+ "\n+-- Service Components: " + getServiceIDs();
	}
}


/*
 * JBoss, Home of Professional Open Source
 * Copyright XXXX, Red Hat Middleware LLC, and individual contributors as indicated
 * by the @authors tag. All rights reserved.
 * See the copyright.txt in the distribution for a full listing
 * of individual contributors.
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU General Public License, v. 2.0.
 * This program is distributed in the hope that it will be useful, but WITHOUT A
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License,
 * v. 2.0 along with this distribution; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */
package org.mobicents.tools.twiddle.jslee;

import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;
import org.jboss.console.twiddle.command.CommandContext;
import org.jboss.console.twiddle.command.CommandException;
import org.jboss.logging.Logger;
import org.mobicents.slee.container.management.jmx.editors.ComponentIDPropertyEditor;
import org.mobicents.tools.twiddle.AbstractSleeCommand;
import org.mobicents.tools.twiddle.Utils;
import org.mobicents.tools.twiddle.op.AbstractOperation;

import javax.management.*;
import javax.slee.SbbID;
import javax.slee.ServiceID;
import java.io.PrintWriter;

/**
 * One bulky command to interact with usage MBeans.
 *
 * @author baranowb
 *
 */
public abstract class AbstractUsageCommand extends AbstractSleeCommand {

	/**
	 * @param commandName
	 * @param desc
	 */
	public AbstractUsageCommand(String commandName, String desc) {
		super(commandName,desc);

		try {
			this.PROFILE_PROVISIONING_MBEAN = new ObjectName(Utils.SLEE_PROFILE_PROVISIONING); // damn
			// annoying.
			this.RESOURCE_MANAGEMENT_MBEAN = new ObjectName(Utils.SLEE_RESOURCE_MANAGEMENT); // damn
			// annoying.
			this.SERVICE_MANAGEMENT_MBEAN = new ObjectName(Utils.SLEE_SERVICE_MANAGEMENT); // damn
			// annoying.
		} catch (MalformedObjectNameException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NullPointerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		this.provisioningMBeanName = getProvisioningMBeanName();
		this.getOperationName = getUsageMGMTMBeanOperation();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.tools.twiddle.AbstractSleeCommand#displayHelp()
	 */
	@Override
	public void displayHelp() {
		PrintWriter out = context.getWriter();

		out.println(desc);

		// out.println("usage: " + name +
		// " <-tprofileTableName> [-pprofileName] <operation> <arg>*");
		addHeaderDescription(out);
		out.println("'SetID' refers to SetName or SbbID and SetName.");
		out.println();
		out.println("operation:");
		out.println("    -l, --list                     Lists certain information about parameters sets. Requires one of options to be present:");
		out.println("           --sets                  Instructs command to list declared parameter sets. Does not require argument.");
		out.println("           --parameters            Instructs command to list parameters of parameter set. Does not require argument.");
		//TODO: make 'list' also list notification mngr conf for resource set.
		out.println("    -g, --get                      Fetches value of certain parameter in set. Does not take argument.");
		out.println("                                   Requires '--name' option to be present. Following options are supported: ");
		out.println("           --name                  Specifies name of parameter in a set for get operation. Requires parameter name as argument. This option is mandatory.");
		out.println("           --rst                   If present, indicates that 'get' operation should reset parameter value. Does not require argument.");
		out.println("    -r, --reset                    Resets assets in 'Usage' realm. Does not take argument. If 'SetID' is specified, reset command resets specific set, otherwise it acts on default one.");
		out.println("                                   If it is not present, reset command performs operation on default set. Following option is supported:");
		out.println("           --all                   Resets ALL parameters for 'ResourceName', ignores 'SetID'.");
		out.println("    -c, --create                   Creates usage parameter set for given 'SetID'. Does not require argument.");
		out.println("    -d, --delete                   Deletes usage parameter set with given 'SetID'. Does not require argument.");
		out.println("    -n, --notify                   This operation either turn on/off notifications for parameter or queries about state of notifications.");
		out.println("                                   Does not take parameter, supports following options:");
		out.println("           --name                  Specifies name of parameter. Requires parameter name as argument. It is mandatory.");
		out.println("           --value                 Specifies value of parameter. Requires boolean argument.");
		out.println("           --is                    Request information about notification(if its enabled). Does not require argument.");

		//out.println("    -i, --is-notify                Checks if notification is on for certain parameter in set. Following options are supported:");
		//out.println("           --name                  Specifies name of parameter. Requires parameter name as argument. It is mandatory.");
		out.println("");
		out.println("Examples: ");
		addExamples(out);
		out.flush();
	}

	protected abstract void addHeaderDescription(PrintWriter out);
	protected abstract void addExamples(PrintWriter out);

	// //////////////////////
	// Command essentials //
	// //////////////////////

	protected static final String GET_MANAGER_NAME_METHOD = "getUsageNotificationManagerMBean";
	protected static final String GET_MANAGER_NAME_SBB_METHOD = "getSbbUsageNotificationManagerMBean";

	//those are required to get bean on which we should invoke op.
	protected ObjectName PROFILE_PROVISIONING_MBEAN;
	protected final static String PROFILE_GET_METHOD = "getProfileTableUsageMBean";
	protected ObjectName RESOURCE_MANAGEMENT_MBEAN;
	protected final static String RESOURCE_GET_METHOD = "getResourceUsageMBean";
	protected ObjectName SERVICE_MANAGEMENT_MBEAN;
	protected final static String SERVICE_GET_METHOD = "getServiceUsageMBean";
	//used not only in operation
	protected final static String GET_SPECIFIC_BEAN_METHOD = "getUsageMBean";
	protected final static String GET_SPECIFIC_SBB_BEAN_METHOD = "getSbbUsageMBean";

	//name of provisioning mbean.
	protected ObjectName provisioningMBeanName;
	// get op from provisioning mbean.
	protected String getOperationName;
	// usage mgmt bean
	protected ObjectName usageMgmtMBeanName;
	// usage manager bean - notification
	protected ObjectName usageSetManagerMBeanName;
	// object name of
	protected ObjectName specificObjectName;
	// holds string resource name - ProfileTable, RA Entity, ServiceID
	protected String resourceName;
	// holds name, if default usage, it will be null.
	protected String usageSetName;

	//part for ServiceUsage params.
	protected ServiceID serviceID;

	protected SbbID sbbID;

	protected ComponentIDPropertyEditor editor = new ComponentIDPropertyEditor();

	protected final static String PREFIX_SERVICEID = "ServiceID";
	//protected final static String PREFIX_SBBID = "SbbID";
	// //////////////////////
	//    Set essentials   //
	// //////////////////////

	// list of fields, so we know what type they are?

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.tools.twiddle.AbstractSleeCommand#getBeanOName()
	 */
	@Override
	public ObjectName getBeanOName() throws MalformedObjectNameException, NullPointerException {
		// tricky, its kind of dynamic :)
		// this depends on op
		return specificObjectName;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.tools.twiddle.AbstractSleeCommand#processArguments(java
	 * .lang.String[])
	 */
	@Override
	protected void processArguments(String[] args) throws CommandException {

		//String sopts = "-:lgrcdni";
		String sopts = "-:lgrcdn";

		LongOpt[] lopts = {

				new LongOpt("noprefix", LongOpt.NO_ARGUMENT, null, 0x1000),
				// operration part
				new LongOpt("list", LongOpt.NO_ARGUMENT, null, 'l'),
					new LongOpt("sets", LongOpt.NO_ARGUMENT, null, ListOperation.sets),
					new LongOpt("parameters", LongOpt.NO_ARGUMENT, null, ListOperation.parameters),
				new LongOpt("get", LongOpt.NO_ARGUMENT, null, 'g'),
					new LongOpt("name", LongOpt.REQUIRED_ARGUMENT, null, GetOperation.name),
					new LongOpt("rst", LongOpt.NO_ARGUMENT, null, GetOperation.rst),
				new LongOpt("reset", LongOpt.NO_ARGUMENT, null, 'r'),
					new LongOpt("all", LongOpt.NO_ARGUMENT, null, ResetOperation.all),
				new LongOpt("create", LongOpt.NO_ARGUMENT, null, 'c'),
				new LongOpt("delete", LongOpt.NO_ARGUMENT, null, 'd'),

				//mgmt
				new LongOpt("notify", LongOpt.NO_ARGUMENT, null, 'n'),
					new LongOpt("value", LongOpt.REQUIRED_ARGUMENT, null, NotifyOperation.value),
					new LongOpt("is-notify", LongOpt.NO_ARGUMENT, null, NotifyOperation.is),
		};

		Getopt getopt = new Getopt(null, args, sopts, lopts);
		getopt.setOpterr(false);
		int nonOptArgIndex = 0;
		int code;
		while ((code = getopt.getopt()) != -1) {
			switch (code) {
			case ':':
				throw new CommandException("Option requires an argument: " + args[getopt.getOptind() - 1]);

			case '?':
				throw new CommandException("Invalid (or ambiguous) option: " + args[getopt.getOptind() - 1]);

			case 0x1000:
				break;

			case 1:
				// non opt args, table and profile name(maybe)
				switch (nonOptArgIndex) {
				case 0:
					resourceName = getopt.getOptarg();
					if(resourceName.startsWith(PREFIX_SERVICEID))
					{

						try{
							editor.setAsText(resourceName);
						}catch(Exception e)
						{
							throw new CommandException("Command: \"" + getName() + "\" failed to parse ServiceID.",e);
						}
						this.serviceID = (ServiceID) editor.getValue();

						this.resourceName = null;
					}
					nonOptArgIndex++;
					break;
				case 1:
					if(this.serviceID!=null)
					{

						try{
							this.editor.setAsText(getopt.getOptarg());
						}catch(Exception e)
						{
							throw new CommandException("Command: \"" + getName() + "\" failed to parse SbbID.",e);
						}
						this.sbbID = (SbbID) this.editor.getValue();
					}else
					{
						usageSetName = getopt.getOptarg();
					}
					nonOptArgIndex++;
					break;
				case 2:
					if(this.serviceID == null)
					{
						throw new CommandException("Command: \"" + getName() + "\" expects at most two non opt arguments!");
					}
					usageSetName = getopt.getOptarg();
					nonOptArgIndex++;
					break;
				default:
					throw new CommandException("Command: \"" + getName() + "\" expects at most three non opt arguments!");
				}
				break;

			case 'l':
				// list
				super.operation = new ListOperation(super.context, super.log, this);
				prepareCommand();
				super.operation.buildOperation(getopt, args);
				break;
			case 'g':
				// get
				super.operation = new GetOperation(super.context, super.log, this);
				prepareCommand();
				super.operation.buildOperation(getopt, args);
				break;
			case 'r':
				// reset
				super.operation = new ResetOperation(super.context, super.log, this);
				prepareCommand();
				super.operation.buildOperation(getopt, args);
				break;

			case 'c':
				// create
				super.operation = new CreateOperation(super.context, super.log, this);
				prepareCommand();
				super.operation.buildOperation(getopt, args);
				break;
			case 'd':
				// delete
				super.operation = new DeleteOperation(super.context, super.log, this);
				prepareCommand();
				super.operation.buildOperation(getopt, args);
				break;
			case 'n':
				// notify mngr
				super.operation = new NotifyOperation(super.context, super.log, this);
				prepareCommand();
				super.operation.buildOperation(getopt, args);
				break;
//			case 'i':
//				// check notify
//				super.operation = new IsNotifyOperation(super.context, super.log, this);
//				prepareCommand();
//				super.operation.buildOperation(getopt, args);
//				break;

			default:
				throw new CommandException("Command: \"" + getName() + "\", found unexpected opt: " + args[getopt.getOptind() - 1]);

			}
		}
	}

	protected void prepareCommand() throws CommandException {
		// get bean name and bean info.

		if(this.resourceName == null && this.serviceID == null)
		{
			throw new CommandException("Command: \"" + getName() + "\", expects 'ResourceName'!");
		}
		//in case of reset SbbID may be null.
		if(this.serviceID!=null && this.sbbID == null)
		{
			throw new CommandException("Command: \"" + getName() + "\", expects atleast 'SbbID' in 'SetID'!");
		}
		String[] sig = null;
		Object[] parms = null;

		if(this.serviceID == null)
		{
			sig = new String[]{"java.lang.String"};
			parms = new Object[]{resourceName};
		}else
		{
			sig = new String[]{"javax.slee.ServiceID"};
			parms = new Object[]{this.serviceID};
		}
		MBeanServerConnection server = super.context.getServer();
		//get usage mgmt bean.
		try {
			this.usageMgmtMBeanName = (ObjectName) server.invoke(this.provisioningMBeanName, this.getOperationName, parms, sig);
		} catch (Exception e) {
			throw new CommandException("Command: \"" + getName()+"\" failed to obtain usage management bean name. Resource does not exist in container?", e);
		}
	}

	protected ObjectName getSpecificUsageMBeanOName() throws CommandException
	{
		String[] sig = null;
		Object[] parms = null;
		if (this.serviceID == null) {
			if (usageSetName != null) {
				sig = new String[] { "java.lang.String" };
				parms = new Object[] { usageSetName };
			}else
			{
				sig = new String[] { };
				parms = new Object[] {  };
			}
		} else {
			if (usageSetName != null) {
				sig = new String[] { "javax.slee.SbbID","java.lang.String" };
				parms = new Object[] { this.sbbID,usageSetName };
			}else
			{
				sig = new String[] { "javax.slee.SbbID" };
				parms = new Object[] { this.sbbID };
			}
		}
		MBeanServerConnection server = super.context.getServer();
		//get usage mgmt bean.
		try {
			if(serviceID != null)
			{
				this.specificObjectName =  (ObjectName) server.invoke(this.usageMgmtMBeanName, GET_SPECIFIC_SBB_BEAN_METHOD, parms, sig);
			}else
			{
				this.specificObjectName =  (ObjectName) server.invoke(this.usageMgmtMBeanName, GET_SPECIFIC_BEAN_METHOD, parms, sig);
			}
			return this.specificObjectName;
		} catch (Exception e) {
			throw new CommandException("Command: \"" + getName()+"\" failed to obtain usage management bean name. Resource does not exist in container?", e);
		}
	}
	protected ObjectName getSpecificUsageNotificationMBeanOName() throws CommandException
	{
		String[] sig = null;
		Object[] parms = null;
		if(this.serviceID == null)
		{
			sig = new String[]{};
			parms = new Object[]{};
		}else
		{
			sig = new String[] { "javax.slee.SbbID" };
			parms = new Object[] { this.sbbID };
		}
		MBeanServerConnection server = super.context.getServer();
		//get usage mgmt bean.
		try {
			if(serviceID!=null)
			{
				this.specificObjectName =  (ObjectName) server.invoke(this.usageMgmtMBeanName, GET_MANAGER_NAME_SBB_METHOD, parms, sig);
			}else
			{
				this.specificObjectName =  (ObjectName) server.invoke(this.usageMgmtMBeanName, GET_MANAGER_NAME_METHOD, parms, sig);
			}
			return this.specificObjectName;
		} catch (Exception e) {
			throw new CommandException("Command: \"" + getName()+"\" failed to obtain usage management bean name. Resource does not exist in container?", e);
		}
	}
	public abstract ObjectName getProvisioningMBeanName();
	public abstract String getUsageMGMTMBeanOperation();
	/**
	 * Operation to perform list like actions. It does following:
	 *

	 *
list parameters sets

	 *
list parameters in parameter set

	 *

	 *

	 *
	 * @author baranowb
	 *
	 */
	protected class ListOperation extends AbstractOperation
	{
		public static final char sets = 'v';
		public static final char parameters = 'b';
		private final static String OPERTION_getUsageParameterSets = "getUsageParameterSets";
		public ListOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);

			// default
			super.operationName = OPERTION_getUsageParameterSets;
		}

		@Override
		public void buildOperation(Getopt opts, String[] args) throws CommandException {

			//add default value:
			specificObjectName = usageMgmtMBeanName;
			//check opts.
			int code;
			while ((code = opts.getopt()) != -1) {
				switch (code) {
				case ':':
					throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

				case '?':
					throw new CommandException("Invalid (or ambiguous) option: " + args[opts.getOptind() - 1] + " --> " + opts.getOptopt());

				case sets:
					super.operationName = OPERTION_getUsageParameterSets;

					break;
				case parameters:
					//this can be empty.
					if(serviceID!=null)
					{
						super.operationName = GET_SPECIFIC_SBB_BEAN_METHOD;
					}else
					{
						super.operationName = GET_SPECIFIC_BEAN_METHOD;
					}
					break;
				default:
					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
							+ "\", found unexpected opt: " + args[opts.getOptind() - 1]);

				}
			}
		}

		/* (non-Javadoc)
		 * @see org.mobicents.tools.twiddle.op.AbstractOperation#invoke()
		 */
		@Override
		public void invoke() throws CommandException {

			if(super.operationName.equals("getUsageParameterSets"))
			{
				if(serviceID!=null)
				{
					addArg(sbbID, "javax.slee.SbbID", false);
				}
				super.invoke();
			}else
			{
				try {
					String getMethod = super.operationName;

					MBeanServerConnection conn = context.getServer();

					Object[] parms = null;
					String[] sig = null;
					if(serviceID==null)
					{
						parms = new Object[]{};
						sig = new String[]{};
					}else
					{
						parms = new Object[]{sbbID};
						sig = new String[]{"javax.slee.SbbID"};

					}
					ObjectName on = (ObjectName) conn.invoke(usageMgmtMBeanName, getMethod, parms, sig);
					super.operationResult = conn.getMBeanInfo(on);
					displayResult();

				} catch (Exception e) {
					//add handle error here?
					throw new CommandException("Failed to invoke \"" + this.operationName + "\" due to: ", e);
				}
			}
		}

		/* (non-Javadoc)
		 * @see org.mobicents.tools.twiddle.op.AbstractOperation#displayResult()
		 */
		@Override
		public void displayResult() {
			if (!context.isQuiet()) {
				if (operationResult instanceof MBeanInfo) {

					PrintWriter out = context.getWriter();
					// dont look at operationResult, we want info

					MBeanOperationInfo[] infos = ((MBeanInfo) super.operationResult).getOperations();
					for (MBeanOperationInfo info : infos) {
						if (!info.getName().startsWith("get")) {
							continue;
						}
						out.println();
						// out.println("Class: "+info.getClass());
						out.println("Desc   : " + info.getDescription());
						out.println("Name   : " + info.getName().replaceFirst("get", ""));
						out.println("Sample : " + info.getReturnType().equals("javax.slee.usage.SampleStatistics"));

					}

					// render results to out
					out.flush();
				} else {
					super.displayResult();
				}
			}
		}

	}

	protected class GetOperation extends AbstractOperation
	{
		public static final char rst = 'x';
		public static final char name = 'z';
		private boolean reset = false;

		public GetOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			super.operationName = "get";
		}

		@Override
		public void buildOperation(Getopt opts, String[] args) throws CommandException {
			int code;
			while ((code = opts.getopt()) != -1) {
				switch (code) {
				case ':':
					throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

				case '?':
					throw new CommandException("Invalid (or ambiguous) option: " + args[opts.getOptind() - 1] + " --> " + opts.getOptopt());

				case rst:
					reset = true;
					break;
				case name:
					//TODO: check upper case?
					String opt = opts.getOptarg();
					if(!Character.isUpperCase(opt.charAt(0)))
					{
						throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
								+ "\", cannot proceed. Parameter name must start with upper case: " + opt);
					}
					super.operationName += opt;
					break;
				default:
					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
							+ "\", found unexpected opt: " + args[opts.getOptind() - 1]);

				}
			}
			if(super.operationName.equals( "get")) //empty, no name?
			{
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", requires atleast '--name' option.");
			}
			addArg(new Boolean(reset), boolean.class, false);

			//now we have to get proper bean name
			getSpecificUsageMBeanOName();

		}

		@Override
		public void invoke() throws CommandException {
			try {
				ObjectName on = sleeCommand.getBeanOName();
				MBeanServerConnection conn = context.getServer();

				Object[] parms = getOpArguments().toArray();
				String[] sig = new String[getOpSignature().size()];
				sig = getOpSignature().toArray(sig);

				operationResult = conn.invoke(on, this.operationName, parms, sig);
				displayResult();

			} catch(javax.management.InstanceNotFoundException infe) {
				//this means no slee running/deployed
				super.operationResult = "No JSLEE container deployed.";
				displayResult();

			} catch (Exception e) {
				//add handle error here?
				throw new CommandException("Failed to invoke \"" + this.operationName + "\" due to: ", e);
			}
		}
	}

	protected class ResetOperation extends AbstractOperation {
		public static final char all = 'a';

		private final static String OPERATION_resetAllUsageParameters = "resetAllUsageParameters";
		public boolean allIndication = false;

		public ResetOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			super.operationName = OPERATION_resetAllUsageParameters;
		}

		@Override
		public void buildOperation(Getopt opts, String[] args) throws CommandException {
			int code;
			while ((code = opts.getopt()) != -1) {
				switch (code) {
				case ':':
					throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

				case '?':
					throw new CommandException("Invalid (or ambiguous) option: " + args[opts.getOptind() - 1] + " --> " + opts.getOptopt());

				case all: //if all we need to act on mgmt bean

					specificObjectName = usageMgmtMBeanName;
					allIndication = true;
					break;

				default:
					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
							+ "\", found unexpected opt: " + args[opts.getOptind() - 1]);

				}

			}

			if(!allIndication)
			{
				//we need specific bean name
				getSpecificUsageMBeanOName();
			}else
			{
				if(serviceID!=null && sbbID!=null)
				{
					addArg(sbbID, "javax.slee.SbbID", false);
				}else
				{
					//ServiceID wide reset.
				}
			}

		}
	}
	protected class CreateOperation extends AbstractOperation
	{
		private final static String OPERATION_createUsageParameterSet = "createUsageParameterSet";
		public CreateOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			super.operationName = OPERATION_createUsageParameterSet;

		}

		@Override
		public void buildOperation(Getopt opts, String[] args) throws CommandException {
			//there is no more to that atm?
			if(usageSetName == null)
			{
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", requires 'SetID' to be present");
			}
			if(serviceID!=null)
			{
				if(sbbID == null)
				{
					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
							+ "\", requires SbbID in 'SetID' to be present");
				}
				addArg(sbbID, "javax.slee.SbbID", false);
			}
			addArg(usageSetName, String.class, false);
			specificObjectName = usageMgmtMBeanName;
		}

	}
	protected class DeleteOperation extends AbstractOperation
	{
		private final static String OPERATION_removeUsageParameterSet = "removeUsageParameterSet";
		public DeleteOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			super.operationName = OPERATION_removeUsageParameterSet;

		}

		@Override
		public void buildOperation(Getopt opts, String[] args) throws CommandException {
			if(usageSetName == null)
			{
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", requires 'SetID' to be present");
			}
			if(serviceID!=null)
			{
				if(sbbID == null)
				{
					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
							+ "\", requires SbbID in 'SetID' to be present");
				}
				addArg(sbbID, "javax.slee.SbbID", false);
			}
			addArg(usageSetName, String.class, false);
			specificObjectName = usageMgmtMBeanName;
		}

	}

	//mgr part :)

	protected class NotifyOperation extends AbstractOperation
	{
		public static final char value = 'o';
		public static final char is = 'i';
		private Boolean booleanValue;
		private String parameterName;
		private boolean isIndicated = false;

		public NotifyOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);

		}

		@Override
		public void buildOperation(Getopt opts, String[] args) throws CommandException {
			int code;
			while ((code = opts.getopt()) != -1) {
				switch (code) {
				case ':':
					throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

				case '?':
					throw new CommandException("Invalid (or ambiguous) option: " + args[opts.getOptind() - 1] + " --> " + opts.getOptopt());

				case value:
					this.booleanValue = Boolean.parseBoolean(opts.getOptarg());
					break;
				case GetOperation.name:
					String opt = opts.getOptarg();//this is name of param
					if(!Character.isUpperCase(opt.charAt(0)))
					{
						throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
								+ "\", cannot proceed. Parameter name must start with upper case: " + opt);
					}
					parameterName = opt;

					break;
				case is:
					isIndicated = true;
					break;
				default:
					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
							+ "\", found unexpected opt: " + args[opts.getOptind() - 1]);

				}
			}

			if(parameterName == null)
			{
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", requires '--name' option to be present.");
			}
			if( (booleanValue != null && isIndicated) ||(booleanValue == null && !isIndicated))
			{
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", requires either '--is' or '--value'.");
			}

			if(isIndicated)
			{
				super.operationName = "get"+parameterName+"NotificationsEnabled";
			}else
			{
				super.operationName = "set"+parameterName+"NotificationsEnabled";
				addArg(booleanValue, boolean.class, false);
			}

			//now we need mgmt bean
			getSpecificUsageNotificationMBeanOName();

		}

	}

//	protected class IsNotifyOperation extends AbstractOperation
//	{
//
//		public IsNotifyOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
//			super(context, log, sleeCommand);
//			// TODO Auto-generated constructor stub
//		}
//
//		@Override
//		public void buildOperation(Getopt opts, String[] args) throws CommandException {
//			int code;
//			while ((code = opts.getopt()) != -1) {
//				switch (code) {
//				case ':':
//					throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);
//
//				case '?':
//					throw new CommandException("Invalid (or ambiguous) option: " + args[opts.getOptind() - 1] + " --> " + opts.getOptopt());
//
//				case GetOperation.name:
//					String opt = opts.getOptarg();//this is name of param
//					if(!Character.isUpperCase(opt.charAt(0)))
//					{
//						throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
//								+ "\", cannot proceed. Parameter name must start with upper case: " + opt);
//					}
//					super.operationName = "get"+opt+"NotificationsEnabled";
//
//					break;
//				default:
//					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
//							+ "\", found unexpected opt: " + args[opts.getOptind() - 1]);
//
//				}
//			}
//
//			if(super.operationName == null)
//			{
//				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
//						+ "\", requires '--name' option to be present.");
//
//			}
//			//now we need mgmt bean
//			getSpecificUsageNotificationMBeanOName();
//
//		}
//
//	}
}


package javax.slee.facilities;

import java.io.Serializable;
import java.io.StreamCorruptedException;

/**
 * This class defines an enumerated type for the late-timer preservation options
 * suppored by the {@link TimerFacility Timer Facility}. A singleton instance of
 * each enumerated value is guaranteed (via an implementation of readResolve()
 * - refer {@link java.io.Serializable java.io.Serializable}), so that equality tests
 * using == are always evaluated correctly.  (This equality test is only
 * guaranteed if this class is loaded in the application's boot class path, rather
 * than dynamically loaded at runtime.)
 *

 * The late-timer preservation options are:
 *

 *
NONE - timer events for a late timer are not generated.
 *
ALL - timer events for a late timer are always generated.
 *
LAST - only one timer event is generated for a late timer, that event
 *       corresponding to the most recent firing of the timer.
 *

 */
public final class TimerPreserveMissed implements Serializable {
    /**
     * An integer representation of {@link #NONE}.
     */
    public static final int PRESERVE_NONE = 0;

    /**
     * An integer representation of {@link #ALL}.
     */
    public static final int PRESERVE_ALL = 1;

    /**
     * An integer representation of {@link #LAST}.
     */
    public static final int PRESERVE_LAST = 2;

    /**
     * A string representation of {@link #NONE}.
     */
    public static final String NONE_STRING = "None";

    /**
     * A string representation of {@link #ALL}.
     */
    public static final String ALL_STRING = "All";

    /**
     * A string representation of {@link #LAST}.
     */
    public static final String LAST_STRING = "Last";

    /**
     * Preserve-missed value for the NONE option.
     */
    public static final TimerPreserveMissed NONE = new TimerPreserveMissed(PRESERVE_NONE);

    /**
     * Preserve-missed value for the ALL option.
     */
    public static final TimerPreserveMissed ALL = new TimerPreserveMissed(PRESERVE_ALL);

    /**
     * Preserve-missed value for the LAST option.
     */
    public static final TimerPreserveMissed LAST = new TimerPreserveMissed(PRESERVE_LAST);

    /**
     * Get a TimerPreserveMissed object from an integer value.
     * @param option the preserve-missed option as an integer.
     * @return a TimerPreserveMissed object corresponding to option.
     * @throws IllegalArgumentException if option is not a valid
     *        preserve-missed option value.
     */
    public static TimerPreserveMissed fromInt(int option) throws IllegalArgumentException {
        switch (option) {
            case PRESERVE_NONE: return NONE;
            case PRESERVE_ALL: return ALL;
            case PRESERVE_LAST: return LAST;
            default: throw new IllegalArgumentException("Invalid preserve-missed value: " + option);
        }
    }

    /**
     * Get a TimerPreserveMissed object from a string value.
     * @param option the preserve-missed option as a string, for example as returned
              by the {@link #toString()} method (case insensitive).
     * @return a TimerPreserveMissed object corresponding to option.
     * @throws NullPointerException if option is null.
     * @throws IllegalArgumentException if option is not a valid
     *        preserve-missed option value.
     * @since SLEE 1.1
     */
    public static TimerPreserveMissed fromString(String option) throws NullPointerException, IllegalArgumentException {
        if (option == null) throw new NullPointerException("option is null");
        if (option.equalsIgnoreCase(NONE_STRING)) return NONE;
        if (option.equalsIgnoreCase(ALL_STRING)) return ALL;
        if (option.equalsIgnoreCase(LAST_STRING)) return LAST;
        throw new IllegalArgumentException("Invalid preserve-missed value: " + option);
    }

    /**
     * Get an integer value representation for this TimerPreserveMissed object.
     * @return an integer value representation for this TimerPreserveMissed object.
     */
    public int toInt() {
        return option;
    }

    /**
     * Determine if this TimerPreserveMissed object represents the NONE option.
     *

     * This method is effectively equivalent to the conditional test:
     * (this == NONE), ie. the code:
     *

     *     if (timerPreserveMissed.isNone()) ...
     *

     * is interchangeable with the code:
     *

     *    if (timerPreserveMissed == TimerPreserveMissed.NONE) ...
     *

     * @return true if this object represents the NONE option,
     *       false otherwise.
     */
    public boolean isNone() {
        return option == PRESERVE_NONE;
    }

    /**
     * Determine if this TimerPreserveMissed object represents the ALL option.
     *

     * This method is effectively equivalent to the conditional test:
     * (this == ALL), ie. the code:
     *

     *     if (timerPreserveMissed.isAll()) ...
     *

     * is interchangeable with the code:
     *

     *    if (timerPreserveMissed == TimerPreserveMissed.ALL) ...
     *

     * @return true if this object represents the ALL option,
     *       false otherwise.
     */
    public boolean isAll() {
        return option == PRESERVE_ALL;
    }

    /**
     * Determine if this TimerPreserveMissed object represents the LAST option.
     *

     * This method is effectively equivalent to the conditional test:
     * (this == LAST), ie. the code:
     *

     *     if (timerPreserveMissed.isLast()) ...
     *

     * is interchangeable with the code:
     *

     *    if (timerPreserveMissed == TimerPreserveMissed.LAST) ...
     *

     * @return true if this object represents the LAST option,
     *       false otherwise.
     */
    public boolean isLast() {
        return option == PRESERVE_LAST;
    }

    /**
     * Compare this preserve-missed option object for equality with another.
     * @param obj the object to compare this with.
     * @return true if obj is an instance of this class
     *        representing the same preserve-missed option as this, false
     *        otherwise.
     */
    public boolean equals(Object obj) {
        if (obj == this) return true;

        return (obj instanceof TimerPreserveMissed) && ((TimerPreserveMissed)obj).option == option;
    }

    /**
     * Get a hash code value for this preserve-missed option object.
     * @return a hash code value.
     */
    public int hashCode() {
        return option;
    }

    /**
     * Get the textual representation of the TimerPreserveMissed object.
     * @return the textual representation of the TimerPreserveMissed object.
     */
    public String toString() {
        switch (option) {
            case PRESERVE_NONE: return NONE_STRING;
            case PRESERVE_ALL: return ALL_STRING;
            case PRESERVE_LAST: return LAST_STRING;
            default: return "TimerPreserveMissed in Unknown and Invalid State";
        }
    }

    /**
     * Private constructor to prevent unauthorized object creation.
     */
    private TimerPreserveMissed(int option) {
        this.option = option;
    }

    /**
     * Resolve deserialisation references so that the singleton property of each
     * enumerated object is preserved.
     */
    private Object readResolve() throws StreamCorruptedException {
        try {
            return fromInt(option);
        }
        catch (IllegalArgumentException iae) {
            throw new StreamCorruptedException("Invalid internal state found");
        }
    }

    /**
     * The internal state representation of the enumerated type.
     */
    private final int option;
}


/*
 * JBoss, Home of Professional Open Source
 * Copyright 2011, Red Hat, Inc. and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.mobicents.slee.runtime.sbbentity;

import org.infinispan.tree.Fqn;
import org.infinispan.tree.Node;
import org.mobicents.slee.container.sbbentity.SbbEntityID;
import org.restcomm.cache.CacheData;
import org.restcomm.cache.FqnWrapper;
import org.restcomm.cluster.MobicentsCluster;

import javax.slee.ServiceID;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 *
 * Proxy object for activity context factory data management through JBoss Cache
 *
 * @author martins
 *
 */

public class SbbEntityFactoryCacheData extends CacheData {

	public static final String SBB_ENTITY_FACTORY_FQN_NAME = "sbbe";

	/**
	 * the fqn of the node that holds all activity context cache child nodes
	 */
	protected static final Fqn SBB_ENTITY_FACTORY_FQN = Fqn.fromElements(SBB_ENTITY_FACTORY_FQN_NAME);

	/**
	 *
	 * @param cluster
	 */
	public SbbEntityFactoryCacheData(MobicentsCluster cluster) {
		super(new FqnWrapper(SBB_ENTITY_FACTORY_FQN), cluster.getMobicentsCache());
	}

	/**
	 * Retrieves a set containing sbb entity ids in the factory
	 * cache data
	 *
	 * @return
	 */
	public Set<SbbEntityID> getSbbEntities() {
		final Node node = getNode();
		if (node == null) {
			return Collections.emptySet();
		}
		HashSet<SbbEntityID> result = new HashSet<SbbEntityID>();
		ServiceID serviceID = null;
		for (Object obj : node.getChildrenNames()) {
			serviceID = (ServiceID) obj;
			for (SbbEntityID sbbEntityID : getRootSbbEntityIDs(serviceID)) {
				result.add(sbbEntityID);
				collectSbbEntities(sbbEntityID,result);
			}
		}
		return result;
	}

	public Set<SbbEntityID> getRootSbbEntityIDs(ServiceID serviceID) {
		final Node node = getNode();
		if (node == null) {
			return Collections.emptySet();
		}
		final Node serviceNode = node.getChild(serviceID);
		if (serviceNode == null) {
			return Collections.emptySet();
		}
		HashSet<SbbEntityID> result = new HashSet<SbbEntityID>();
		RootSbbEntityID rootSbbEntityID = null;
		for (Object obj : serviceNode.getChildrenNames()) {
			rootSbbEntityID = new RootSbbEntityID(serviceID, (String)obj);
			result.add(rootSbbEntityID);
		}
		return result;
	}

	public void WAremove() {
		final Node node = getNode();
		if (node != null) {
			if (!node.getChildren().isEmpty()) {
				node.removeChildren();
			}
		}
	}

	private void collectSbbEntities(SbbEntityID sbbEntityID, Set<SbbEntityID> result) {
		final SbbEntityCacheData sbbEntityCacheData = new SbbEntityCacheData(sbbEntityID,super.getMobicentsCache());
		for (SbbEntityID childSbbEntityID : sbbEntityCacheData.getAllChildSbbEntities()) {
			result.add(childSbbEntityID);
			collectSbbEntities(childSbbEntityID,result);
		}
	}

}


/*
 * JBoss, Home of Professional Open Source
 * Copyright 2011, Red Hat, Inc. and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.mobicents.slee.runtime.sbb;

import java.util.ArrayList;
import java.util.List;

import javax.slee.ActivityContextInterface;
import javax.slee.InvalidArgumentException;
import javax.slee.NotAttachedException;
import javax.slee.SLEEException;
import javax.slee.SbbID;
import javax.slee.ServiceID;
import javax.slee.TransactionRequiredLocalException;
import javax.slee.UnrecognizedEventException;
import javax.slee.facilities.ActivityContextNamingFacility;
import javax.slee.facilities.AlarmFacility;
import javax.slee.facilities.TimerFacility;
import javax.slee.facilities.Tracer;
import javax.slee.management.NotificationSource;
import javax.slee.management.SbbNotification;
import javax.slee.management.UnrecognizedLinkNameException;
import javax.slee.nullactivity.NullActivityContextInterfaceFactory;
import javax.slee.nullactivity.NullActivityFactory;
import javax.slee.profile.ProfileFacility;
import javax.slee.profile.ProfileTableActivityContextInterfaceFactory;
import javax.slee.resource.ResourceAdaptorTypeID;
import javax.slee.serviceactivity.ServiceActivityContextInterfaceFactory;
import javax.slee.serviceactivity.ServiceActivityFactory;
import javax.transaction.SystemException;

import org.apache.log4j.Logger;
import org.mobicents.slee.SbbContextExt;
import org.mobicents.slee.SbbLocalObjectExt;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.activity.ActivityContext;
import org.mobicents.slee.container.activity.ActivityContextFactory;
import org.mobicents.slee.container.activity.ActivityContextHandle;
import org.mobicents.slee.container.management.ResourceManagement;
import org.mobicents.slee.container.sbb.SbbLocalObject;
import org.mobicents.slee.container.sbb.SbbObject;
import org.mobicents.slee.container.sbb.SbbObjectState;
import org.mobicents.slee.container.transaction.SleeTransactionManager;

/**
 * SBB Context Implementation.
 *
 * The SLEE provides each SBB object with an SbbContext object. The SbbContext
 * object gives the SBB object access to the SBB object�s context maintained by
 * the SLEE, allows the SBB object to invoke functions provided by the SLEE, and
 * obtain information about the SBB entity assigned to the SBB object. The
 * SbbContext object implements the SbbContext interface. The SbbContext
 * interface declares the following methods: � Methods to access information
 * determined at runtime. o A getSbbLocalObject method to get an SBB local
 * object that represents the SBB entity assigned to the SBB object of the
 * SbbContext object. o A getService method to get a ServiceID object that
 * encapsulates the component identity of the Service that the SBB entity is a
 * descendent of, i.e. the SBB entity is in an SBB entity tree whose root SBB
 * entity is instantiated by the SLEE for the child relation (from SLEE as
 * parent to the root SBB) specified by the Service. o A getSbb method to get an
 * SbbID object that encapsulates the component identity of the SBB. � Activity
 * Context methods. These methods are discussed in greater detail in Section
 * 7.7.1. o A getActivities method. This method returns all the Activity
 * Contexts that the SBB entity assigned to the SBB object of the SbbContext
 * object is attached to. More precisely, it returns an Activity Context
 * Interface object for each Activity Context attached to the SBB entity
 * assigned to the SBB object of the SbbContext object. � Event mask methods.
 * These methods are described in Section 8.4.3. o A maskEvent method. This
 * method masks event types that the SBB entity assigned to the SBB object of
 * the SbbContext object no longer wishes to receive from an Activity Context. o
 * A getEventMask method. This returns the set of masked event types for an
 * Activity Context that SBB entity assigned to the SBB object of the SbbContext
 * object is attached to. � Transaction methods. These methods are described in
 * Section 6.10. o A setRollbackOnly method. The SBB Developer uses this method
 * to mark the transaction of the current method invocation for rollback. o A
 * getRollbackOnly method. The SBB Developer uses this method to determine if
 * the transaction of the current method invocation has been marked for
 * rollback.
 *
 * @author M. Ranganathan
 * @author F. Moggia
 * @author Eduardo Martins
 */
public class SbbContextImpl implements SbbContextExt {

	private static final Logger logger = Logger.getLogger(SbbContextImpl.class);

	private static final SleeContainer sleeContainer = SleeContainer
			.lookupFromJndi();

	/** The SBB entity to which I am assigned. */
	private final SbbObject sbbObject;

	/**
	 * Notification source for this Sbb
	 */
	private final NotificationSource notificationSource;

	/**
	 * Creates a new instance of SbbContextImpl
	 *
	 * @param notificationSource
	 */
	public SbbContextImpl(SbbObject sbbObject) {
		this.sbbObject = sbbObject;
		this.notificationSource = new SbbNotification(getService(), getSbb());
	}

	private static ActivityContextInterface[] EMPTY_ACI_ARRAY = {};

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.SbbContext#getActivities()
	 */
	public ActivityContextInterface[] getActivities()
			throws TransactionRequiredLocalException, IllegalStateException,
			SLEEException {
		if (logger.isTraceEnabled()) {
			logger.trace("getActivities() " + this.sbbObject.getState());
		}
		if (SbbObjectState.READY != this.sbbObject.getState()) {
			throw new IllegalStateException(
					"Cannot call SbbContext.getActivities() in "
							+ this.sbbObject.getState());
		}
		ActivityContextFactory acf = sleeContainer.getActivityContextFactory();
		List<ActivityContextInterface> result = new ArrayList<ActivityContextInterface>();
		ActivityContext ac = null;
		for (ActivityContextHandle ach : sbbObject.getSbbEntity()
				.getActivityContexts()) {
			ac = acf.getActivityContext(ach);
			if (ac != null) {
				result.add(ac.getActivityContextInterface());
			}
		}
		return result.toArray(EMPTY_ACI_ARRAY);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.SbbContext#getEventMask(javax.slee.ActivityContextInterface)
	 */
	public String[] getEventMask(ActivityContextInterface aci)
			throws NullPointerException, TransactionRequiredLocalException,
			IllegalStateException, NotAttachedException, SLEEException {
		if (aci == null)
			throw new NullPointerException(
					"Activity Context Interface cannot be null.");
		if (sbbObject == null || sbbObject.getState() != SbbObjectState.READY)
			throw new IllegalStateException("Wrong state! "
					+ (sbbObject == null ? null : sbbObject.getState()));

		if (this.sbbObject.getSbbEntity() == null) {
			throw new IllegalStateException(
					"Wrong state! SbbEntity is not assigned");
		}
		sleeContainer.getTransactionManager().mandateTransaction();
		ActivityContextHandle ach = ((org.mobicents.slee.container.activity.ActivityContextInterface) aci)
				.getActivityContext().getActivityContextHandle();
		if (!sbbObject.getSbbEntity().isAttached(ach))
			throw new NotAttachedException("ACI not attached to SBB");

		return sbbObject.getSbbEntity().getEventMask(ach);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.SbbContext#getRollbackOnly()
	 */
	public boolean getRollbackOnly() throws TransactionRequiredLocalException,
			SLEEException {
		SleeTransactionManager txMgr = sleeContainer.getTransactionManager();
		txMgr.mandateTransaction();
		if (logger.isDebugEnabled()) {
			logger.debug("in getRollbackOnly on " + this);
		}
		try {
			return txMgr.getRollbackOnly();
		} catch (SystemException e) {
			throw new SLEEException("Problem with the tx manager!");
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.SbbContext#getSbb()
	 */
	public SbbID getSbb() throws SLEEException {
		return this.sbbObject.getSbbComponent().getSbbID();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.SbbContext#getSbbLocalObject()
	 */
	public SbbLocalObject getSbbLocalObject()
			throws TransactionRequiredLocalException, IllegalStateException,
			SLEEException {
		sleeContainer.getTransactionManager().mandateTransaction();

		if (this.sbbObject.getState() != SbbObjectState.READY)
			throw new IllegalStateException("Bad state : "
					+ this.sbbObject.getState());

		return sbbObject.getSbbEntity().getSbbLocalObject();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.SbbContext#getService()
	 */
	public ServiceID getService() throws SLEEException {
		// return this.sbbObject.getSbbEntity().getServiceId();
		return this.sbbObject.getServiceID();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.SbbContext#maskEvent(java.lang.String[],
	 * javax.slee.ActivityContextInterface)
	 */
	public void maskEvent(String[] eventNames, ActivityContextInterface aci)
			throws NullPointerException, TransactionRequiredLocalException,
			IllegalStateException, UnrecognizedEventException,
			NotAttachedException, SLEEException {
		if (SbbObjectState.READY != this.sbbObject.getState()) {
			throw new IllegalStateException(
					"Cannot call SbbContext maskEvent in "
							+ this.sbbObject.getState());
		}

		if (this.sbbObject.getSbbEntity() == null) {
			// this shouldnt happen since SbbObject state ready shoudl be set
			// when its fully setup, but....
			throw new IllegalStateException(
					"Wrong state! SbbEntity is not assigned");
		}

		sleeContainer.getTransactionManager().mandateTransaction();
		ActivityContextHandle ach = ((org.mobicents.slee.container.activity.ActivityContextInterface) aci)
				.getActivityContext().getActivityContextHandle();

		if (!sbbObject.getSbbEntity().isAttached(ach))
			throw new NotAttachedException("ACI is not attached to SBB ");
		sbbObject.getSbbEntity().setEventMask(ach, eventNames);

	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.SbbContext#setRollbackOnly()
	 */
	public void setRollbackOnly() throws TransactionRequiredLocalException,
			SLEEException {
		final SleeTransactionManager sleeTransactionManager = sleeContainer
				.getTransactionManager();
		sleeTransactionManager.mandateTransaction();
		try {
			sleeTransactionManager.setRollbackOnly();
		} catch (SystemException e) {
			throw new SLEEException("failed to mark tx for rollback", e);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.SbbContext#getTracer(java.lang.String)
	 */
	public Tracer getTracer(String tracerName) throws NullPointerException,
			IllegalArgumentException, SLEEException {

		try {
			return sleeContainer.getTraceManagement().createTracer(
					this.notificationSource, tracerName, true);
		} catch (InvalidArgumentException e) {
			throw new IllegalArgumentException(e);
		}
	}

	// SbbContextExt

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.SbbContextExt#getActivityContextInterfaceFactory(javax
	 * .slee.resource.ResourceAdaptorTypeID)
	 */
	public Object getActivityContextInterfaceFactory(
			ResourceAdaptorTypeID raTypeID) throws NullPointerException,
			IllegalArgumentException {
		if (raTypeID == null) {
			throw new NullPointerException("null ra type id");
		}
		if (!sbbObject.getSbbComponent().getDependenciesSet().contains(raTypeID)) {
			throw new IllegalArgumentException("ra type "+raTypeID+" not referred by the sbb.");
		}
		return sleeContainer.getComponentRepository().getComponentByID(raTypeID).getActivityContextInterfaceFactory();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.slee.SbbContextExt#getActivityContextNamingFacility()
	 */
	public ActivityContextNamingFacility getActivityContextNamingFacility() {
		return sleeContainer.getActivityContextNamingFacility();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.slee.SbbContextExt#getAlarmFacility()
	 */
	public AlarmFacility getAlarmFacility() {
		return sbbObject.getSbbComponent().getAlarmFacility();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.SbbContextExt#getNullActivityContextInterfaceFactory()
	 */
	public NullActivityContextInterfaceFactory getNullActivityContextInterfaceFactory() {
		return sleeContainer.getNullActivityContextInterfaceFactory();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.slee.SbbContextExt#getNullActivityFactory()
	 */
	public NullActivityFactory getNullActivityFactory() {
		return sleeContainer.getNullActivityFactory();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.slee.SbbContextExt#getProfileFacility()
	 */
	public ProfileFacility getProfileFacility() {
		return sleeContainer.getSleeProfileTableManager().getProfileFacility();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.SbbContextExt#
	 * getProfileTableActivityContextInterfaceFactory()
	 */
	public ProfileTableActivityContextInterfaceFactory getProfileTableActivityContextInterfaceFactory() {
		return sleeContainer.getSleeProfileTableManager()
				.getProfileTableActivityContextInterfaceFactory();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.SbbContextExt#getResourceAdaptorInterface(javax.slee
	 * .resource.ResourceAdaptorTypeID, java.lang.String)
	 */
	public Object getResourceAdaptorInterface(ResourceAdaptorTypeID raTypeID,
			String raLink) throws NullPointerException,
			IllegalArgumentException {
		if (raTypeID == null) {
			throw new NullPointerException("null ra type id");
		}
		if (raLink == null) {
			throw new NullPointerException("null ra link");
		}
		if (!sbbObject.getSbbComponent().getDependenciesSet().contains(raTypeID)) {
			throw new IllegalArgumentException("ra type "+raTypeID+" not referred by the sbb.");
		}
		final ResourceManagement resourceManagement = sleeContainer.getResourceManagement();

		String raEntityName = null;
		try {
			raEntityName = resourceManagement.getResourceAdaptorEntityName(raLink);
		} catch (UnrecognizedLinkNameException e) {
			throw new IllegalArgumentException("ra link "+raLink+" not found.");
		}

		return resourceManagement.getResourceAdaptorEntity(raEntityName).getResourceAdaptorInterface(raTypeID);

	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.SbbContextExt#getServiceActivityContextInterfaceFactory
	 * ()
	 */
	public ServiceActivityContextInterfaceFactory getServiceActivityContextInterfaceFactory() {
		return sleeContainer.getServiceManagement().getServiceActivityContextInterfaceFactory();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.slee.SbbContextExt#getServiceActivityFactory()
	 */
	public ServiceActivityFactory getServiceActivityFactory() {
		return sleeContainer.getServiceManagement().getServiceActivityFactory();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.slee.SbbContextExt#getTimerFacility()
	 */
	public TimerFacility getTimerFacility() {
		return sleeContainer.getTimerFacility();
	}

}


package javax.slee.usage;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import javax.management.Notification;
import javax.slee.SbbID;
import javax.slee.ServiceID;
import javax.slee.management.NotificationSource;
import javax.slee.management.SbbNotification;
import javax.slee.management.VendorExtensionUtils;
import javax.slee.management.VendorExtensions;

/**
 * Notifications of this type are emitted by a {@link UsageMBean} to indicate a counter-type
 * usage parameter has been updated or a sample-type usage parameter has accumulated a
 * new sample. Usage notifications are only generated for usage parameters for which the
 * generation of usage notifications has been enabled.  Control of notification generation
 * is managed via a {@link UsageNotificationManagerMBean} object.
 *

 * Usage notifications contain a {@link NotificationSource} object that can be used to
 * obtain more information about the object that caused the usage notification to be
 * generated.  The type of a usage notification can be used to infer the type of the
 * notification source object in the notification:
 *

 *
if {@link #getType()} == {@link javax.slee.management.SbbNotification#USAGE_NOTIFICATION_TYPE}
 *       then the type of the notification source object is {@link javax.slee.management.SbbNotification}.
 *
if {@link #getType()} == {@link javax.slee.management.ResourceAdaptorEntityNotification#USAGE_NOTIFICATION_TYPE}
 *       then the type of the notification source object is {@link javax.slee.management.ResourceAdaptorEntityNotification}.
 *
if {@link #getType()} == {@link javax.slee.management.SubsystemNotification#USAGE_NOTIFICATION_TYPE}
 *       then the type of the notification source object is {@link javax.slee.management.SubsystemNotification}.
 *

 */
public final class UsageNotification extends Notification implements VendorExtensions {
    private static final int VERSION_SLEE1_0 = 1;
    private static final int VERSION_SLEE1_1 = 2;

    /**
     * Create a UsageNotification containing the updated value of an SBB's usage
     * parameter.  The notification's notificationSource attribute is set to an
     * {@link SbbNotification} encapsulating the serviceID and sbbID
     * arguments.
     * @param sbbUsageMBean the SbbUsageMBean object that is
     *        emitting this notification.
     * @param serviceID the component identifier of the Service whose SBB's usage
     *        parameter was updated.
     * @param sbbID the component identifier of the SBB whose usage parameter was updated.
     * @param paramSet the name of the SBB usage parameter set containing the usage parameter
     *        that was updated.  If the unamed usage parameter set was updated, this value
     *        is null.
     * @param paramName the name of the usage parameter that was updated.
     * @param value this is either the new value of the usage parameter (for counter-type
     *        usage parameters), or a sample value (for sample-type usage parameters).
     * @param sequenceNumber the notification sequence number within the source
     *        SbbUsageMBean.
     * @param timestamp the time (in ms since January 1, 1970 UTC) that the notification
     *        was generated.
     * @throws NullPointerException if notificationSource, serviceID,
     *        sbbID or paramName is null.
     * @deprecated Usage notifications have been expanded with new attributes to take advantage
     *        of the new features provided by the SLEE specification.  The
     *        {@link #UsageNotification(String, UsageMBean, NotificationSource, String, String, boolean, long, long, long)}
     *        constructor should be used instead of this constructor.
     */
    public UsageNotification(SbbUsageMBean sbbUsageMBean, ServiceID serviceID, SbbID sbbID, String paramSet, String paramName, boolean counter, long value, long sequenceNumber, long timestamp) throws NullPointerException {
        super(SbbUsageMBean.USAGE_NOTIFICATION_TYPE, sbbUsageMBean, sequenceNumber, timestamp,
              "Usage parameter \"" + paramName + "\" updated" + (paramSet != null ? " in usage parameter set " + paramSet : ""));

        if (sbbUsageMBean == null) throw new NullPointerException("sbbUsageMBean is null");
        if (serviceID == null) throw new NullPointerException("serviceID is null");
        if (sbbID == null) throw new NullPointerException("sbbID is null");
        if (paramName == null) throw new NullPointerException("paramName is null");

        this.serviceID = serviceID;
        this.sbbID = sbbID;
        this.paramSet = paramSet;
        this.paramName = paramName;
        this.counter = counter;
        this.value = value;

        // forward compatibility
        this.notificationSource = new SbbNotification(serviceID, sbbID);
        this.version = VERSION_SLEE1_0;
    }

    /**
     * Create a UsageNotification to notify listeners of an update to a usage
     * parameter's value.
     * @param type the JMX type of the notification.  The type of the notification is
     *        typically obtained from the NotificationSource parameter when
     *        this notification object is created, and can be used by notification listeners
     *        to infer the type of the NotificationSource, and hence obtain
     *        further information about the source of the notification.
     * @param usageMBean the UsageMBean object that is emitting this
     *        notification.
     * @param notificationSource the component or subsystem in the SLEE that caused this
     *        notification to be generated.
     * @param paramSet the name of the usage parameter set containing the usage parameter that
     *        was updated.  If the unamed usage parameter set was updated, this value is
     *        null.
     * @param paramName the name of the usage parameter that was updated.
     * @param value this is either the new value of the usage parameter (for counter-type
     *        usage parameters), or a sample value (for sample-type usage parameters).
     * @param sequenceNumber the notification sequence number within the source UsageMBean.
     * @param timestamp the time (in ms since January 1, 1970 UTC) that the notification
     *        was generated.
     * @throws NullPointerException if type, usageMBean,
     *        notificationSource, or paramName is null.
     * @since SLEE 1.1
     */
    public UsageNotification(String type, UsageMBean usageMBean, NotificationSource notificationSource, String paramSet, String paramName, boolean counter, long value, long sequenceNumber, long timestamp) throws NullPointerException {
        super(type, usageMBean, sequenceNumber, timestamp,
              "Usage parameter \"" + paramName + "\" updated" + (paramSet != null ? " in usage parameter set " + paramSet : "") + " for " + notificationSource
        );

        if (type == null) throw new NullPointerException("type is null");
        if (usageMBean == null) throw new NullPointerException("usageMBean is null");
        if (notificationSource == null) throw new NullPointerException("notificationSource is null");
        if (paramName == null) throw new NullPointerException("paramName is null");

        this.notificationSource = notificationSource;
        this.paramSet = paramSet;
        this.paramName = paramName;
        this.counter = counter;
        this.value = value;

        // backward compatibility
        if (notificationSource instanceof SbbNotification) {
            SbbNotification sbbNotification = (SbbNotification)notificationSource;
            this.serviceID = sbbNotification.getService();
            this.sbbID = sbbNotification.getSbb();
        }
        else {
            this.serviceID = null;
            this.sbbID = null;
        }
        this.version = VERSION_SLEE1_1;
    }

    /**
     * Get the object that identifies the component or subsystem in the SLEE that caused this
     * usage notification to be generated.
     * @return the notification source.  For SLEE 1.0 usage notifications the type of the
     *        notification source will always be {@link SbbNotification}.
     * @since SLEE 1.1
     */
    public NotificationSource getNotificationSource() {
        return notificationSource;
    }

    /**
     * Get the component identifier of the Service whose SBB's usage parameter was updated.
     * @return the component identifier of the Service whose SBB's usage parameter was updated.
     *        Returns null for SLEE 1.1-compliant notifications unless the
     *        notification source is of type {@link SbbNotification}, in which case the value
     *        of {@link SbbNotification#getService()} is returned.
     * @deprecated Replaced with {@link #getNotificationSource()} in order to specify a
     *       broader range of usage sources.
     */
    public ServiceID getService() {
        return serviceID;
    }

    /**
     * Get the component identifier of the SBB whose usage parameter was updated.
     * @return the component identifier of the SBB whose usage parameter was updated.
     *        Returns null for SLEE 1.1-compliant notifications unless the
     *        notification source is of type {@link SbbNotification}, in which case the value
     *        of {@link SbbNotification#getSbb()} is returned.
     * @deprecated Replaced with {@link #getNotificationSource()} in order to specify a
     *       broader range of usage sources.
     */
    public SbbID getSbb() {
        return sbbID;
    }

    /**
     * Get the name of the usage parameter set containing the usage parameter thas was updated.
     * @return the name of the usage parameter set, or null if the usage parameter
     *        was a member of the unnamed usage parameter set.
     */
    public String getUsageParameterSetName() {
        return paramSet;
    }

    /**
     * Get the name of the usage parameter that was updated.
     * @return the name of the usage parameter that was updated.
     */
    public String getUsageParameterName() {
        return paramName;
    }

    /**
     * Determine if the usage parameter updated is counter-type or sample-type.
     * @return true if the usage parameter updated is counter-type,
     *         false if the usage parameter updated is sample-type.
     */
    public boolean isCounter() {
        return counter;
    }

    /**
     * Get the updated value or emitted sample of the usage parameter.  If {@link #isCounter}
     * returns true this value is the updated value of the counter-type usage
     * parameter.  If {@link #isCounter} returns false this value is a sample
     * value for the usage parameter.
     * @return the updated value or emitted sample of the usage parameter.
     */
    public long getValue() {
        return value;
    }

    /**
     * Enable the serialization of vendor-specific data for objects of this class.
     * This method is typically used by a SLEE implementation that wants to export
     * vendor-specific data with objects of this class to management clients.
     *

     * By default, any vendor-specific data included in an object of this class will
     * not be included in the serialization stream when the object is serialized.
     * Invoking this method changes this behavior so that vendor-specific data is
     * included in the serialization stream when an object of this class is serialized.
     *

     * This method should only be invoked if the vendor-specific data is serializable
     * via standard Java serialization means.
     * @since SLEE 1.1
     * @see #disableVendorDataSerialization
     * @see #setVendorData
     */
    public static void enableVendorDataSerialization() {
        vendorDataSerializationEnabled = true;
    }

    /**
     * Disable the serialization of vendor-specific data for objects of this class.
     *

     * If the serialization of vendor-specific data for objects of this class has
     * been enabled via the {@link #enableVendorDataSerialization} method, this
     * method disables that behavior again.
     * @since SLEE 1.1
     */
    public static void disableVendorDataSerialization() {
        vendorDataSerializationEnabled = false;
    }

    /**
     * Enable the deserialization of vendor-specific data for objects of this class.
     * This method is typically used by a management client that wants to obtain any
     * vendor-specific data included in the serialization stream of objects of this
     * class.
     *

     * By default, any vendor-specific data included in the serialization stream of
     * objects of this class is discarded upon deserialization.  Invoking this method
     * changes that behavior so that the vendor-specific data is also deserialized
     * when an object of this class is deserialized.  A management client that enables
     * the deserialization of vendor-specific data must ensure that any necessary
     * classes required to deserialize that data is available in the relevant
     * classloader.
     * @since SLEE 1.1
     * @see #disableVendorDataDeserialization
     * @see #getVendorData
     */
    public static void enableVendorDataDeserialization() {
        vendorDataDeserializationEnabled = true;
    }

    /**
     * Disable the deserialization of vendor-specific data for objects of this class.
     *

     * If the deserialization of vendor-specific data for objects of this class has
     * been enabled via the {@link #enableVendorDataDeserialization} method, this
     * method disables that behavior again.
     * @since SLEE 1.1
     */
    public static void disableVendorDataDeserialization() {
        vendorDataDeserializationEnabled = false;
    }

    /**
     * Set the vendor-specific data.
     * @param vendorData the vendor-specific data.
     * @since SLEE 1.1
     */
    public void setVendorData(Object vendorData) {
        this.vendorData = vendorData;
    }

    /**
     * Get the vendor-specific data.
     * @return the vendor-specific data.
     * @since SLEE 1.1
     */
    public Object getVendorData() {
        return vendorData;
    }

    /**
     * Compare this notification for equality with another object.
     *

     * For backwards compatibility, this method performs either a SLEE 1.0-based comparison or
     * a SLEE 1.1-based comparison based on the state of this notification object.  If this
     * notification contains a non-null service component identifier reference, a SLEE 1.0-based
     * comparison is performed.  Otherwise, a SLEE 1.1-based comparison is performed.
     *

     * The SLEE 1.0-based comparison considers two notifications to be equal if obj
     * is an instance of this class and the service and SBB component identifiers, parameter set
     * name, parameter name, and parameter type (counter or sample) are the same as the
     * corresponding attributes of this.
     *

     * The SLEE 1.1-based comparison considers two notifications to be equal if obj
     * if an instance of this class and the notification source, parameter set name, parameter
     * name, and parameter type (counter or sample) are the same as the corresponding attributes
     * of this.
     *

     * Note that a SLEE 1.0-compliant usage notification can never be equal to a SLEE 1.1-compliant
     * usage notification.
     * @param obj the object to compare this with.
     * @return true if obj is equal to this according to
     *        the rules specified above, false otherwise.
     */
    public boolean equals(Object obj) {
        if (obj == this) return true;
        if (!(obj instanceof UsageNotification)) return false;

        UsageNotification that = (UsageNotification)obj;
        if (version == VERSION_SLEE1_0) {
            // SLEE 1.0
            // is 'that' a SLEE 1.0 notification?
            if (that.version != VERSION_SLEE1_0) return false;

            return (this.serviceID.equals(that.serviceID))
                && (this.sbbID.equals(that.sbbID))
                && (this.paramSet == null ? that.paramSet == null : this.paramSet.equals(that.paramSet))
                && (this.paramName.equals(that.paramName))
                && (this.counter == that.counter);
        }
        else {
            // SLEE 1.1
            // is that a SLEE 1.1 notification?
            if (that.version != VERSION_SLEE1_1) return false;

            return (this.notificationSource.equals(that.notificationSource))
                && (this.paramSet == null ? that.paramSet == null : this.paramSet.equals(that.paramSet))
                && (this.paramName.equals(that.paramName))
                && (this.counter == that.counter);
        }
    }

    /**
     * Get a hash code value for this notification.  The hash code is the logical XOR of
     * the hash codes of the usage parameter set name (if any) and the usage parameter name.
     * @return a hash code for this notification.
     */
    public int hashCode() {
        return (paramSet != null)
            ? paramSet.hashCode() ^ paramName.hashCode()
            : paramName.hashCode();
    }

    /**
     * Get a string representation for this notification.
     * @return a string representation for this notification.
     */
    public String toString() {
        StringBuffer buf = new StringBuffer();
        buf.append("UsageNotification[");
        if (version == VERSION_SLEE1_0) {
            // generate a SLEE 1.0 message
            buf.append("type=").append(getType()).
                append(",timestamp=").append(getTimeStamp()).
                append(",service=").append(serviceID).
                append(",sbb=").append(sbbID).
                append(",paramSet=").append(paramSet).
                append(",param=").append(paramName).
                append(",counter=").append(counter).
                append(",value=").append(value);
        }
        else {
            // generate a SLEE 1.1 message
            buf.append("type=").append(getType()).
                append(",source=").append(notificationSource).
                append(",paramSet=").append(paramSet).
                append(",param=").append(paramName).
                append(",counter=").append(counter).
                append(",value=").append(value).
                append(",timestamp=").append(getTimeStamp());
        }
        if (vendorData != null) buf.append(",vendor data=").append(vendorData);
        buf.append("]");
        return buf.toString();
    }

    // special handling of serialization
    private void writeObject(ObjectOutputStream out) throws IOException {
        VendorExtensionUtils.writeObject(out, vendorDataSerializationEnabled ? vendorData : null);
    }

    // special handling of deserialization
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        vendorData = VendorExtensionUtils.readObject(in, vendorDataDeserializationEnabled);
    }

    private final NotificationSource notificationSource;
    private final ServiceID serviceID;
    private final SbbID sbbID;
    private final String paramSet;
    private final String paramName;
    private final boolean counter;
    private final long value;
    private final int version;

    private static volatile boolean vendorDataSerializationEnabled = false;
    private static volatile boolean vendorDataDeserializationEnabled = false;
    private transient Object vendorData;
}


/*
 * JBoss, Home of Professional Open Source
 * Copyright 2011, Red Hat, Inc. and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.mobicents.slee.container.component.deployment.jaxb.descriptors;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.slee.SLEEException;
import javax.slee.management.DeploymentException;
import javax.slee.management.LibraryID;

import org.mobicents.slee.container.component.deployment.jaxb.descriptors.event.MEventDefinition;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.event.MEventJar;
import org.mobicents.slee.container.component.event.EventTypeDescriptorFactory;

/**
 * Factory to build {@link EventTypeDescriptorImpl} objects.
 * @author martins
 *
 */
public class EventTypeDescriptorFactoryImpl extends AbstractDescriptorFactory implements EventTypeDescriptorFactory {

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.core.component.event.EventTypeDescriptorFactory#parse(java.io.InputStream)
	 */
	public List<EventTypeDescriptorImpl> parse(InputStream inputStream) throws DeploymentException {

		Object jaxbPojo = buildJAXBPojo(inputStream);

		List<EventTypeDescriptorImpl> result = new ArrayList<EventTypeDescriptorImpl>();

		boolean isSlee11 = false;
		MEventJar mEventJar = null;
		if (jaxbPojo instanceof org.mobicents.slee.container.component.deployment.jaxb.slee.event.EventJar) {
			mEventJar = new MEventJar((org.mobicents.slee.container.component.deployment.jaxb.slee.event.EventJar)jaxbPojo);
		}
		else if (jaxbPojo instanceof org.mobicents.slee.container.component.deployment.jaxb.slee11.event.EventJar ) {
			mEventJar = new MEventJar((org.mobicents.slee.container.component.deployment.jaxb.slee11.event.EventJar)jaxbPojo);
			isSlee11 = true;
		}
		else {
			throw new SLEEException("unexpected class of jaxb pojo built: "+(jaxbPojo != null ? jaxbPojo.getClass() : null));
		}

		List<LibraryID> libraryRefs = mEventJar.getLibraryRef();
		for (MEventDefinition mEventDefinition : mEventJar.getEventDefinition()) {
			result.add(new EventTypeDescriptorImpl(mEventDefinition,libraryRefs,isSlee11));
		}
		return result;
	}
}