/*
 * 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.management.jmx;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.StandardMBean;
import javax.slee.InvalidArgumentException;
import javax.slee.management.ManagementException;
import javax.slee.management.NotificationSource;
import javax.slee.management.ProfileTableUsageMBean;
import javax.slee.management.ResourceManagementMBean;
import javax.slee.management.UsageParameterSetNameAlreadyExistsException;
import javax.slee.usage.UnrecognizedUsageParameterSetNameException;
import javax.slee.usage.UsageNotificationManagerMBean;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.component.SleeComponentWithUsageParametersInterface;
import org.mobicents.slee.runtime.usage.AbstractUsageParameterSet;

/**
 * Abstract class code for a "parent" usage mbean, such as the
 * {@link ResourceManagementMBean} or {@link ProfileTableUsageMBean}
 *
 * @author martins
 *
 */
public abstract class AbstractUsageMBeanImplParent extends StandardMBean implements
		UsageMBeanImplParent,
		Serializable {

	//FIXME: maybe part of this logic should be moved to UsageManagement class?
	/**
	 *
	 */
	private static final long serialVersionUID = 1L;

	protected abstract Logger getLogger();

	/**
	 * the object name used to register this mbean
	 */
	private ObjectName objectName;

	/**
	 * the child name param usage mbeans registred by this mbean, holds paramName->bean mapping.
	 */
	private ConcurrentHashMap<String, UsageMBeanImpl> usageMBeans = new ConcurrentHashMap<String, UsageMBeanImpl>();

	/**
	 * the default usage mbean
	 */
	private UsageMBeanImpl defaultUsageMBean;

	/**
	 * the usage notification manager mbean
	 */
	private UsageNotificationManagerMBeanImpl notificationManager;

	/**
	 * the container
	 */
	private final SleeContainer sleeContainer;

	/**
	 * the component
	 */
	private final SleeComponentWithUsageParametersInterface component;

	/**
	 * the notification source used by the usage mbeans
	 */
	private final NotificationSource notificationSource;

	/**
	 *
	 */
	private boolean closed = false;

	/**
	 * Creates a new instance of an abstract usage mbean
	 * @param mBeanInterfaceClass the class poiting to the interface this mbean implements
	 * @param component the component related with this mbean
	 * @param notificationSource the notification source to be used in notifications sent by the notification manager mbean
	 * @param sleeContainer "the" container
	 * @throws NotCompliantMBeanException
	 * @throws MalformedObjectNameException
	 * @throws NullPointerException
	 */
	public AbstractUsageMBeanImplParent(Class<?> mBeanInterfaceClass,
			SleeComponentWithUsageParametersInterface component,
			NotificationSource notificationSource, SleeContainer sleeContainer)
			throws NotCompliantMBeanException, MalformedObjectNameException,
			NullPointerException {
		super(mBeanInterfaceClass);
		this.sleeContainer = sleeContainer;
		this.component = component;
		this.notificationSource = notificationSource;
	}

	/**
	 * Retrieves the object name of this mbean
	 *
	 * @return
	 */
	public ObjectName getObjectName() {
		return objectName;
	}

	/**
	 * Sets the object name of this mbean
	 *
	 * @param objectName
	 */
	public void setObjectName(ObjectName objectName) {
		this.objectName = objectName;
	}

	/**
	 * Removes the mbean
	 *
	 */
	public void remove() {

		Logger logger = getLogger();
		if (logger.isDebugEnabled()) {
			logger.debug("Closing " + toString());
		}
		final MBeanServer mbeanServer = sleeContainer.getMBeanServer();
		try {
			mbeanServer.unregisterMBean(getObjectName());
		} catch (Exception e) {
			logger.error("failed to remove " + toString(), e);
		}
		// remove all usage param
		if (logger.isDebugEnabled()) {
			logger
					.debug("Removing all named usage parameters of "
							+ toString());
		}
		for (String name : usageMBeans.keySet()) {
			try {
				_removeUsageParameterSet(name,false);
			} catch (Throwable e) {
				logger.error(e.getMessage(), e);
			}
		}
		// also remove the default
		try {
			removeUsageParameterSet();
		} catch (Throwable e) {
			logger.error(e.getMessage(), e);
		}
	}

	/**
	 *
	 *
	 * @throws ManagementException
	 */
	public void close() throws ManagementException {
		ensureMBeanIsNotClosed();
		closed = true;
	}

	public void open() {
		closed = false;
	}

	/**
	 *
	 * @throws ManagementException
	 */
	protected void ensureMBeanIsNotClosed() throws ManagementException {
		if (closed) {
			throw new ManagementException("closed");
		}
	}

	/**
	 * Creates the default usage param (and its mbean)
	 *
	 * @throws NullPointerException
	 * @throws InvalidArgumentException
	 * @throws UsageParameterSetNameAlreadyExistsException
	 * @throws ManagementException
	 */
	public void createUsageParameterSet() throws NullPointerException,
			InvalidArgumentException,
			UsageParameterSetNameAlreadyExistsException, ManagementException {
		_createUsageParameterSet(null);
	}

	/**
	 * Creates the usage param (and its mbean) for the specified name
	 *
	 * @param paramSetName
	 * @throws NullPointerException
	 * @throws InvalidArgumentException
	 * @throws UsageParameterSetNameAlreadyExistsException
	 * @throws ManagementException
	 */
	public void createUsageParameterSet(String paramSetName)
			throws NullPointerException, InvalidArgumentException,
			UsageParameterSetNameAlreadyExistsException, ManagementException {

		if (paramSetName == null)
			throw new NullPointerException("usage param set is null");
		if (paramSetName.length() == 0)
			throw new InvalidArgumentException(
					"The lenght of the Usage Parameter Set Name is zero!");
		if (!isValidUsageParameterName(paramSetName))
			throw new InvalidArgumentException(
					"The lenght of the Usage Parameter Set Name is zero!");

		_createUsageParameterSet(paramSetName);
	}

	private synchronized void _createUsageParameterSet(String name) throws NullPointerException,
			UsageParameterSetNameAlreadyExistsException, ManagementException {

		ensureMBeanIsNotClosed();

		Logger logger = getLogger();

		// get usage parameter class
		Class<?> usageParameterClass = component.getUsageParametersConcreteClass();

		// check if the usage parameter name set already exists
		if (name != null && this.usageMBeans.containsKey(name)) {
				throw new UsageParameterSetNameAlreadyExistsException("name "
					+ name + " already exists for " + this);
		}

		UsageMBeanImpl usageMbean = null;
		UsageNotificationManagerMBeanImpl usageNotificationManagerMBean = null;
		Thread currentThread = Thread.currentThread();
		ClassLoader currentThreadClassLoader = currentThread
				.getContextClassLoader();
		try {
			// change class loader
			currentThread.setContextClassLoader(component.getClassLoader());
			// create the actual usage parameter instance and map it in the
			// mbean
			AbstractUsageParameterSet installedUsageParameterSet = (AbstractUsageParameterSet) AbstractUsageParameterSet.newInstance(usageParameterClass, notificationSource, name, sleeContainer);
			// create and register the usage mbean
			Class<?> usageParameterMBeanClass = component
					.getUsageParametersMBeanImplConcreteClass();
			Constructor<?> constructor = usageParameterMBeanClass
					.getConstructor(new Class[] { Class.class,
							NotificationSource.class });

			ObjectName usageParameterMBeanObjectName = generateUsageParametersMBeanObjectName(name);
			usageMbean = (UsageMBeanImpl) constructor.newInstance(new Object[] {
					component.getUsageParametersMBeanConcreteInterface(),
					notificationSource });
			usageMbean.setObjectName(usageParameterMBeanObjectName);
			usageMbean.setParent(this);
			sleeContainer.getMBeanServer().registerMBean(usageMbean,
					usageParameterMBeanObjectName);
			// set the usage param data related with the mbean

			installedUsageParameterSet.setUsageMBean(usageMbean);
			usageMbean.setUsageParameter(installedUsageParameterSet);
			// store the mbean
			if (name != null) {
				this.usageMBeans.put(name, usageMbean);
			} else {
				// default mbean
				this.defaultUsageMBean = usageMbean;
				// create notification manager
				Class<?> usageNotificationManagerMBeanClass = component
						.getUsageNotificationManagerMBeanImplConcreteClass();
				constructor = usageNotificationManagerMBeanClass
						.getConstructor(new Class[] { Class.class,
								NotificationSource.class,SleeComponentWithUsageParametersInterface.class});
				usageNotificationManagerMBean = (UsageNotificationManagerMBeanImpl) constructor
						.newInstance(new Object[] {
								component
										.getUsageNotificationManagerMBeanConcreteInterface(),
								notificationSource ,component});
				ObjectName usageNotificationManagerMBeanObjectName = generateUsageNotificationManagerMBeanObjectName();
				usageNotificationManagerMBean
						.setObjectName(usageNotificationManagerMBeanObjectName);
				sleeContainer.getMBeanServer().registerMBean(
						usageNotificationManagerMBean,
						usageNotificationManagerMBeanObjectName);
				this.notificationManager = usageNotificationManagerMBean;
			}
		} catch (Throwable e) {
			if (logger.isDebugEnabled()) {
				logger.debug("Error creating usage param set named "+name,e);
			}
			if (usageMbean != null) {
				if (name != null) {
					this.usageMBeans.remove(name);
				} else {
					this.defaultUsageMBean = null;
				}
				try {
					sleeContainer.getMBeanServer().unregisterMBean(
							usageMbean.getObjectName());
				} catch (Throwable f) {
					logger.error("failed to unregister usage parameter mbean "
							+ usageMbean.getObjectName());
				}
			}
			if (usageNotificationManagerMBean != null) {
				this.notificationManager = null;
				try {
					sleeContainer.getMBeanServer().unregisterMBean(
							usageNotificationManagerMBean.getObjectName());
				} catch (Throwable f) {
					logger
							.error("failed to unregister usage notification manager mbean "
									+ usageNotificationManagerMBean
											.getObjectName());
				}
			}
			throw new ManagementException(e.getMessage(), e);
		} finally {
			currentThread.setContextClassLoader(currentThreadClassLoader);
		}
	}

	/*
	 * verifies a name for an usage mbean
	 */
	private static boolean isValidUsageParameterName(String str) {
		for (int i = 0; i < str.length(); i++) {
			char c = str.charAt(i);
			if (!(Character.isDigit(c) || Character.isLetter(c) || (c <= '\u007e' && c >= '\u0020'))) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Retrieves the object name for the default usage param mbean
	 *
	 * @return
	 * @throws ManagementException
	 */
	public ObjectName getUsageMBean() throws ManagementException {
		try {
			return _getUsageMBean(null);
		} catch (UnrecognizedUsageParameterSetNameException e) {
			throw new ManagementException(
					"default usage parameter name not found", e);
		}
	}

	/**
	 * Retrieves the object name for the usage param mbean with the specified
	 * name
	 *
	 * @param paramSetName
	 * @return
	 * @throws NullPointerException
	 * @throws UnrecognizedUsageParameterSetNameException
	 * @throws ManagementException
	 */
	public ObjectName getUsageMBean(String paramSetName)
			throws NullPointerException,
			UnrecognizedUsageParameterSetNameException, ManagementException {
		if (paramSetName == null)
			throw new NullPointerException("Sbb usage param set is null");
		return _getUsageMBean(paramSetName);
	}

	private synchronized ObjectName _getUsageMBean(String name)
			throws ManagementException,
			UnrecognizedUsageParameterSetNameException {

		ensureMBeanIsNotClosed();

		Logger logger = getLogger();
		if (logger.isDebugEnabled()) {
			logger.debug("_getUsageMBean( name = "+name+")");
		}

		UsageMBeanImpl usageMBeanImpl = null;
		if (name != null) {
			usageMBeanImpl = usageMBeans.get(name);
		}
		else {
			usageMBeanImpl = defaultUsageMBean;
		}
		if (usageMBeanImpl == null) {
			throw new UnrecognizedUsageParameterSetNameException(name);
		} else {
			return usageMBeanImpl.getObjectName();
		}
	}

	/**
	 * Retrieves the object name of the {@link UsageNotificationManagerMBean}
	 *
	 * @return
	 * @throws ManagementException
	 */
	public ObjectName getUsageNotificationManagerMBean()
			throws ManagementException {

		ensureMBeanIsNotClosed();

		return notificationManager.getObjectName();
	}

	/**
	 * Retrieves the names of the usage params, which exist in this mbean
	 *
	 * @return
	 * @throws ManagementException
	 */
	public String[] getUsageParameterSets() throws ManagementException {

		ensureMBeanIsNotClosed();
		return getUsageParameterNamesSet().toArray(new String[0]);
	}

	/**
	 *
	 * @return
	 */
	public Set<String> getUsageParameterNamesSet() {
		return usageMBeans.keySet();
	}

	/**
	 * Removes the default usage param (and its mbean)
	 *
	 * @throws ManagementException
	 * @throws UnrecognizedUsageParameterSetNameException
	 */
	private void removeUsageParameterSet() throws ManagementException,
			UnrecognizedUsageParameterSetNameException {
		_removeUsageParameterSet(null,false);
	}

	/**
	 * Removes the usage param (and its mbean) for the specified name
	 *
	 * @param paramSetName
	 * @throws NullPointerException
	 * @throws UnrecognizedUsageParameterSetNameException
	 * @throws ManagementException
	 */
	public void removeUsageParameterSet(String paramSetName)
			throws NullPointerException,
			UnrecognizedUsageParameterSetNameException, ManagementException {
		if (paramSetName == null)
			throw new NullPointerException("usage param set is null");
		//FIXME: should we recreate beans here as well ?
		_removeUsageParameterSet(paramSetName,true);
	}

	private synchronized void _removeUsageParameterSet(String name, boolean ensureMBeanIsNotClosed)
			throws UnrecognizedUsageParameterSetNameException,
			ManagementException {

		Logger logger = getLogger();
		if (logger.isDebugEnabled()) {
			logger.debug("_removeUsageParameterSet( name = "+name+")");
		}

		UsageMBeanImpl usageMbean = null;
		try {
			if (name != null) {
				// remove from this mbean map
				usageMbean = this.usageMBeans.remove(name);
			} else {
				usageMbean = defaultUsageMBean;
				defaultUsageMBean = null;
			}
			if (usageMbean == null) {
				throw new UnrecognizedUsageParameterSetNameException(name);
			}
			sleeContainer.getMBeanServer().unregisterMBean(
					usageMbean.getObjectName());
			if (name == null) {
				removeNotificationManager();
			}
			//FIXME: Here possibly we should mark to be remove, or remove and throw exception o demands...?
			boolean clustered = !sleeContainer.getCluster().isSingleMember();
			if( !clustered)
			{
				//we are last, lets clear cache
				usageMbean.getUsageParameter().remove();
			}
		} catch (Throwable e) {
			// rollback changes
			if (usageMbean != null) {
				if (name != null) {
					// add to this mbean map
					usageMbean = this.usageMBeans.put(name, usageMbean);
				} else {
					defaultUsageMBean = usageMbean;
				}
				try {
					sleeContainer.getMBeanServer().registerMBean(usageMbean,
							usageMbean.getObjectName());
				} catch (Throwable f) {
					logger.error("failed to re-register usage parameter mbean "
							+ usageMbean.getObjectName());
				}
			}
			// note: removal rollback of notification manager is done by the
			// removeNotificationManager() method
			throw new ManagementException(e.getMessage(), e);
		}
	}

	/**
	 * Resets all usage params
	 *
	 * @throws ManagementException
	 */
	public void resetAllUsageParameters() throws ManagementException {

		ensureMBeanIsNotClosed();
		try {
			defaultUsageMBean.resetAllUsageParameters();
			for (UsageMBeanImpl usageMBeanImpl : usageMBeans.values()) {
				usageMBeanImpl.resetAllUsageParameters();
			}
		} catch (Throwable e) {
			throw new ManagementException(e.getMessage(), e);
		}
	}

	private void removeNotificationManager() throws ManagementException {

		try {
			sleeContainer.getMBeanServer().unregisterMBean(
					notificationManager.getObjectName());
			notificationManager = null;
		} catch (Throwable e) {
			// rollback changes
			try {
				sleeContainer.getMBeanServer().registerMBean(
						notificationManager,
						notificationManager.getObjectName());
			} catch (Throwable f) {
				getLogger().error(
						"failed to re-register usage parameter mbean "
								+ notificationManager.getObjectName());
			}
			throw new ManagementException(e.getMessage(), e);
		}
	}

	/**
	 * Generates the usage mbean object name for the specified usage param name
	 *
	 * @param name
	 * @return
	 * @throws MalformedObjectNameException
	 * @throws NullPointerException
	 */
	protected abstract ObjectName generateUsageParametersMBeanObjectName(
			String name) throws MalformedObjectNameException,
			NullPointerException;

	/**
	 * Generates the usage mbean object name for the default usage param
	 *
	 * @return
	 * @throws MalformedObjectNameException
	 * @throws NullPointerException
	 */
	protected abstract ObjectName generateUsageNotificationManagerMBeanObjectName()
			throws MalformedObjectNameException, NullPointerException;

	/**
	 * Retrieves the usage notification manager mbean
	 */
	public UsageNotificationManagerMBeanImpl getUsageNotificationManagerMBean(
			NotificationSource notificationSource) {
		return notificationManager;
	}

	/**
	 * Convenience method to retrieve the default
	 * {@link AbstractUsageParameterSet}
	 *
	 * @return
	 */
	public AbstractUsageParameterSet getDefaultInstalledUsageParameterSet() {
		if (defaultUsageMBean != null) {
			return defaultUsageMBean.getUsageParameter();
		} else {
			return null;
		}
	}

	/**
	 * Convenience method to retrieve the {@link AbstractUsageParameterSet} for
	 * the specified param set name.
	 *
	 * @param name
	 * @return
	 */
	public AbstractUsageParameterSet getInstalledUsageParameterSet(String name) {

		if (name == null) {
			return getDefaultInstalledUsageParameterSet();
		} else {
			UsageMBeanImpl usageMBean = usageMBeans.get(name);
			if (usageMBean == null) {
				return null;
			} else {
				return usageMBean.getUsageParameter();
			}
		}
	}

	/*
	 * To be defined by concrete mbean, for a proper logging (non-Javadoc)
	 *
	 * @see java.lang.Object#toString()
	 */
	public abstract String toString();

}


/*
 * 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 org.mobicents.slee.container.component.deployment.jaxb.descriptors.common.MSecurityPermissions;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.ra.MResourceAdaptor;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.ra.MResourceAdaptorJar;
import org.mobicents.slee.container.component.ra.ResourceAdaptorDescriptorFactory;

/**
 *
 * Factory to build {@link ResourceAdaptorDescriptorImpl} objects.
 *
 * @author  Alexandre Mendonca
 * @author  Bartosz Baranowski
 */
public class ResourceAdaptorDescriptorFactoryImpl extends AbstractDescriptorFactory implements ResourceAdaptorDescriptorFactory {

  /*
   * (non-Javadoc)
   * @see org.mobicents.slee.core.component.ra.ResourceAdaptorDescriptorFactory#parse(java.io.InputStream)
   */
  public List<ResourceAdaptorDescriptorImpl> parse(InputStream inputStream) throws DeploymentException
  {
    Object jaxbPojo = buildJAXBPojo(inputStream);

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

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

    MSecurityPermissions securityPermissions = mResourceAdaptorJar.getSecurityPermissions();
    for (MResourceAdaptor mResourceAdaptor : mResourceAdaptorJar.getResourceAdaptor())
    {
      result.add(new ResourceAdaptorDescriptorImpl(mResourceAdaptor, securityPermissions, isSlee11));
    }

    return 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.container.component.deployment;

import java.lang.reflect.Modifier;

import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;

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

import org.apache.log4j.Logger;
import org.mobicents.slee.container.component.ProfileSpecificationComponentImpl;
import org.mobicents.slee.container.component.deployment.ClassPool;
import org.mobicents.slee.container.component.profile.ProfileAbstractClassDescriptor;

/**
 * Class decorating the profile abstract class.
 * @author martins
 *
 */
public class ProfileAbstractClassDecorator {

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

    /**
     * the abstract class
     */
    private CtClass ctClass = null;

    private final ProfileSpecificationComponentImpl component;

    /**
     * Constructor
     */
    public ProfileAbstractClassDecorator(ProfileSpecificationComponentImpl component) {
        this.component = component;
    }

    /**
     * Decorate the abstract Class
     *
     * @return true is the class was decorated
     */
    public boolean decorateAbstractClass() throws DeploymentException {

    	ClassPool pool = component.getClassPool();
    	ProfileAbstractClassDescriptor abstractClass = component.getDescriptor().getProfileAbstractClass();
    	if (abstractClass == null) {
    		return false;
    	}
    	String abstractClassName = abstractClass.getProfileAbstractClassName();
        try {
            ctClass = pool.get(abstractClassName);
        } catch (NotFoundException nfe) {
            throw new DeploymentException("Could not find Abstract Class: "
                    + abstractClassName, nfe);
        }

        decorateClassJNDIAddToEnvironmentCalls();

        if (isAbstractClassDecorated) {
        	try {
        		String deployDir = component.getDeploymentDir().getAbsolutePath();
        		ctClass.writeFile(deployDir);
        		ctClass.detach();
        		// the file on disk is now in sync with the latest in-memory version
        		if (logger.isDebugEnabled()) {
        			logger.debug("Modified Abstract Class "
        					+ ctClass.getName()
        					+ " generated in the following path "
        					+ deployDir);
        		}
        	} catch (Throwable e) {
        		throw new SLEEException ( e.getMessage(), e);
        	} finally {
        		ctClass.defrost();
        	}
        	return true;
        }
        else {
        	return false;
        }
    }

   /**
    *
    * @return
    */
    private void decorateClassJNDIAddToEnvironmentCalls() {
        for (CtMethod ctMethod : ctClass.getMethods()) {
    		if (!Modifier.isAbstract(ctMethod.getModifiers()) && !Modifier.isNative(ctMethod.getModifiers()) && !ctMethod.getDeclaringClass().getName().equals(Object.class.getName())) {
    			try {
    				decorateMethodJNDIAddToEnvironmentCalls(ctMethod);
                } catch (CannotCompileException e) {
                    throw new SLEEException(e.getMessage(),e);
                }
    		}
        }
    }

    private void decorateMethodJNDIAddToEnvironmentCalls(CtMethod method)
            throws CannotCompileException {
        method.instrument(new ExprEditor() {

            public void edit(MethodCall m) throws CannotCompileException {
                // the call has to be on a JNDI Context object
                boolean isJndiCtx = false;
                try {
                    // see if the method call is on javax.naming.Context or a derived type
                    if (m.getClassName().equals(javax.naming.Context.class.getName())) {
                        isJndiCtx = true;
                    } else {
                        CtClass cl0 = component.getClassPool().get(m.getClassName());
                        CtClass[] cl0Interfaces = cl0.getInterfaces();
                        for (int i = 0; i < cl0Interfaces.length; i++) {
                            CtClass cl0If = cl0Interfaces[i];
                            if (cl0If.getName().equals(javax.naming.Context.class.getName())) {
                                isJndiCtx = true;
                                break;
                            }
                        }
                    }
                } catch (NotFoundException e) {
                	// The class is not in the pool so ignore it
                	return;
                    //throw new CannotCompileException(e);
                }
                if (!isJndiCtx)
                    return;

                if (m.getMethodName().endsWith("bind") || m.getMethodName().equals("createSubcontext") ) {
                    m.replace("{ throw new javax.naming.OperationNotSupportedException(); $_ = $proceed($$); }");
                    isAbstractClassDecorated = true;
                }

                else if (m.getMethodName().equals("addToEnvironment")) {
                    m.replace("{ throw new javax.naming.NamingException(); $_ = $proceed($$); }");
                    isAbstractClassDecorated = true;
                }
            }
        });
    }

    boolean isAbstractClassDecorated = false;

}


/*
 * 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.usage.local;

import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.slee.management.NotificationSource;

import org.mobicents.slee.runtime.usage.UsageMBeanData;
import org.mobicents.slee.runtime.usage.UsageParameter;

/**
 * Class used to store usage params locally, thus this should be used once usage
 * param replication is not desirable.
 *
 * @author martins
 *
 */
public class UsageMBeanLocalData implements UsageMBeanData {

	/**
	 *
	 */
	private static final ConcurrentHashMap<NotificationSource, ConcurrentHashMap<String,UsageParamSetLocalData>> notificationSourceUsageParamSetsMap
		= new ConcurrentHashMap<NotificationSource, ConcurrentHashMap<String,UsageParamSetLocalData>>();

	/**
	 *
	 */
	private final NotificationSource notificationSource;

	/**
	 *
	 */
	private final String usageParameterSetName;

	/**
	 * @param notificationSource
	 * @param usageParameterSetName
	 */
	public UsageMBeanLocalData(NotificationSource notificationSource,
			String usageParameterSetName) {
		this.notificationSource = notificationSource;
		this.usageParameterSetName = usageParameterSetName;
	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.runtime.usage.UsageMBeanData#create()
	 */
	public boolean create() {

		ConcurrentHashMap<String, UsageParamSetLocalData> notificationSourceUsageParamSets = notificationSourceUsageParamSetsMap.get(notificationSource);
		if (notificationSourceUsageParamSets == null) {
			ConcurrentHashMap<String, UsageParamSetLocalData> newNotificationSourceUsageParamSets = new ConcurrentHashMap<String, UsageParamSetLocalData>();
			notificationSourceUsageParamSets = notificationSourceUsageParamSetsMap.putIfAbsent(notificationSource, newNotificationSourceUsageParamSets);
			if (notificationSourceUsageParamSets == null) {
				notificationSourceUsageParamSets = newNotificationSourceUsageParamSets;
			}
		}

		if (!notificationSourceUsageParamSets.containsKey(usageParameterSetName)) {
			return notificationSourceUsageParamSets.putIfAbsent(usageParameterSetName,new UsageParamSetLocalData(usageParameterSetName)) == null;
		}
		else {
			return false;
		}

	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.runtime.usage.UsageMBeanData#getParameter(java.lang.String)
	 */
	public UsageParameter getParameter(String parameterName) {
		Map<String,UsageParamSetLocalData> notificationSourceUsageParamSets = notificationSourceUsageParamSetsMap.get(notificationSource);
		if (notificationSourceUsageParamSets != null) {
			UsageParamSetLocalData data = notificationSourceUsageParamSets.get(usageParameterSetName);
			if (data != null) {
				return data.getUsageParam(parameterName);
			}
			else {
				return null;
			}
		}
		else {
			return null;
		}
	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.runtime.usage.UsageMBeanData#getParameterNames()
	 */
	public Collection<String> getParameterNames() {
		Map<String,UsageParamSetLocalData> notificationSourceUsageParamSets = notificationSourceUsageParamSetsMap.get(notificationSource);
		if (notificationSourceUsageParamSets != null) {
			UsageParamSetLocalData data = notificationSourceUsageParamSets.get(usageParameterSetName);
			if (data != null) {
				return data.getParameterNames();
			}
			else {
				throw new IllegalStateException("Usage param set not found ( notification source = "+notificationSource+" , usage param set name = "+usageParameterSetName+" ) ");
			}
		}
		else {
			throw new IllegalStateException("Notification source usage param sets not found ( notification source = "+notificationSource+" ) ");
		}
	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.runtime.usage.UsageMBeanData#remove()
	 */
	public boolean remove() {
		final Map<String,UsageParamSetLocalData> notificationSourceUsageParamSets = notificationSourceUsageParamSetsMap.get(notificationSource);
		if (notificationSourceUsageParamSets != null) {
			return notificationSourceUsageParamSets.remove(usageParameterSetName) != null;
		}
		else {
			return false;
		}
	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.runtime.usage.UsageMBeanData#setParameter(java.lang.String, org.mobicents.slee.runtime.usage.UsageParameter)
	 */
	public void setParameter(String parameterName, UsageParameter usageParameter) {
		final Map<String,UsageParamSetLocalData> notificationSourceUsageParamSets = notificationSourceUsageParamSetsMap.get(notificationSource);
		if (notificationSourceUsageParamSets != null) {
			UsageParamSetLocalData data = notificationSourceUsageParamSets.get(usageParameterSetName);
			if (data != null) {
				data.setUsageParam(parameterName, usageParameter);
			}
			else {
				throw new IllegalStateException("Usage param set not found ( notification source = "+notificationSource+" , usage param set name = "+usageParameterSetName+" ) ");
			}
		}
		else {
			throw new IllegalStateException("Notification source usage param sets not found ( notification source = "+notificationSource+" ) ");
		}
	}

	/**
	 * @param notificationSource
	 * @return
	 */
	public static Collection<String> getExistingSets(
			NotificationSource notificationSource) {
		Map<String,UsageParamSetLocalData> notificationSourceUsageParamSets = notificationSourceUsageParamSetsMap.get(notificationSource);
		if (notificationSourceUsageParamSets != null) {
			return Collections.unmodifiableSet(notificationSourceUsageParamSets.keySet());
		}
		else {
			return Collections.emptySet();
		}
	}

	/**
	 * @param notificationSource
	 * @param parameterSetName
	 * @return
	 */
	public static boolean setExists(NotificationSource notificationSource,
			String parameterSetName) {
		return getExistingSets(notificationSource).contains(parameterSetName);
	}

}


/*
 * 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 javax.slee.ActivityContextInterface;
import javax.slee.Address;
import javax.slee.EventTypeID;
import javax.slee.SLEEException;
import javax.slee.SbbLocalObject;
import javax.slee.ServiceID;
import javax.slee.profile.ProfileID;
import javax.slee.profile.UnrecognizedProfileNameException;
import javax.slee.profile.UnrecognizedProfileTableNameException;
import javax.slee.usage.UnrecognizedUsageParameterSetNameException;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.activity.ActivityContext;
import org.mobicents.slee.container.activity.ActivityContextHandle;
import org.mobicents.slee.container.component.sbb.CMPFieldDescriptor;
import org.mobicents.slee.container.component.sbb.GetProfileCMPMethodDescriptor;
import org.mobicents.slee.container.event.EventContext;
import org.mobicents.slee.container.event.EventContextHandle;
import org.mobicents.slee.container.eventrouter.EventRoutingTransactionData;
import org.mobicents.slee.container.management.ProfileManagement;
import org.mobicents.slee.container.management.jmx.ServiceUsageMBeanImpl;
import org.mobicents.slee.container.profile.ProfileLocalObject;
import org.mobicents.slee.container.profile.ProfileTable;
import org.mobicents.slee.container.sbb.SbbObjectState;
import org.mobicents.slee.container.sbbentity.ChildRelation;
import org.mobicents.slee.container.sbbentity.SbbEntity;
import org.mobicents.slee.container.sbbentity.SbbEntityID;
import org.mobicents.slee.container.transaction.SleeTransactionManager;
import org.mobicents.slee.runtime.sbbentity.ProfileLocalObjectCmpValue;

/**
 * The logic to implement sbb abstract methods.
 *
 * @author martins
 *
 */
public class SbbAbstractMethodHandler {

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

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

	// CMP ACCESSORs

	private static final Boolean DEFAULT_CMP_VALUE_BOOLEAN = Boolean.FALSE;
	private static final Byte DEFAULT_CMP_VALUE_BYTE = Byte.valueOf((byte) 0);
	private static final Character DEFAULT_CMP_VALUE_CHAR = Character.valueOf((char) 0);
	private static final Double DEFAULT_CMP_VALUE_DOUBLE = Double.valueOf(0);
	private static final Float DEFAULT_CMP_VALUE_FLOAT = Float.valueOf(0);
	private static final Integer DEFAULT_CMP_VALUE_INTEGER = Integer.valueOf(0);
	private static final Long DEFAULT_CMP_VALUE_LONG = Long.valueOf(0);
	private static final Short DEFAULT_CMP_VALUE_SHORT = Short.valueOf((short)0);

	public static void setCMPFieldOfTypePrimitiveOrUnknown(SbbEntity sbbEntity, String cmpFieldName,
			char cmpFieldValue) {
		SbbAbstractMethodHandler.setCMPFieldOfTypePrimitiveOrUnknown(sbbEntity,cmpFieldName, Character.valueOf(cmpFieldValue));
	}

	public static void setCMPFieldOfTypePrimitiveOrUnknown(SbbEntity sbbEntity, String cmpFieldName,
			byte cmpFieldValue) {
		SbbAbstractMethodHandler.setCMPFieldOfTypePrimitiveOrUnknown(sbbEntity,cmpFieldName, Byte.valueOf(cmpFieldValue));
	}

	public static void setCMPFieldOfTypePrimitiveOrUnknown(SbbEntity sbbEntity, String cmpFieldName,
			short cmpFieldValue) {
		SbbAbstractMethodHandler.setCMPFieldOfTypePrimitiveOrUnknown(sbbEntity,cmpFieldName, Short.valueOf(cmpFieldValue));
	}

	public static void setCMPFieldOfTypePrimitiveOrUnknown(SbbEntity sbbEntity, String cmpFieldName,
			int cmpFieldValue) {
		SbbAbstractMethodHandler.setCMPFieldOfTypePrimitiveOrUnknown(sbbEntity,cmpFieldName, Integer.valueOf(cmpFieldValue));
	}

	public static void setCMPFieldOfTypePrimitiveOrUnknown(SbbEntity sbbEntity, String cmpFieldName,
			long cmpFieldValue) {
		SbbAbstractMethodHandler.setCMPFieldOfTypePrimitiveOrUnknown(sbbEntity,cmpFieldName, Long.valueOf(cmpFieldValue));
	}

	public static void setCMPFieldOfTypePrimitiveOrUnknown(SbbEntity sbbEntity, String cmpFieldName,
			float cmpFieldValue) {
		SbbAbstractMethodHandler.setCMPFieldOfTypePrimitiveOrUnknown(sbbEntity,cmpFieldName, Float.valueOf(cmpFieldValue));
	}

	public static void setCMPFieldOfTypePrimitiveOrUnknown(SbbEntity sbbEntity, String cmpFieldName,
			double cmpFieldValue) {
		SbbAbstractMethodHandler.setCMPFieldOfTypePrimitiveOrUnknown(sbbEntity,cmpFieldName, Double.valueOf(cmpFieldValue));
	}

	public static void setCMPFieldOfTypePrimitiveOrUnknown(SbbEntity sbbEntity, String cmpFieldName,
			boolean cmpFieldValue) {
		SbbAbstractMethodHandler.setCMPFieldOfTypePrimitiveOrUnknown(sbbEntity,cmpFieldName, Boolean.valueOf(cmpFieldValue));
	}

	/**
	 *
	 * @param sbbEntity
	 * @param cmpFieldName
	 * @param cmpFieldValue
	 */
	public static void setCMPFieldOfTypeActivityContextInterface(SbbEntity sbbEntity, String cmpFieldName, ActivityContextInterface cmpFieldValue) {
		if (cmpFieldValue == null) {
			sbbEntity.setCMPField(cmpFieldName, null);
			return;
		}
		org.mobicents.slee.container.activity.ActivityContextInterface aci = null;
		try {
			aci = (org.mobicents.slee.container.activity.ActivityContextInterface) cmpFieldValue;
		} catch (ClassCastException e) {
			throw new IllegalArgumentException("CMP value being set (" + cmpFieldValue + ") is an unknown ActivityContextInterface implementation");
		}
		sbbEntity.setCMPField(cmpFieldName, aci.getActivityContext().getActivityContextHandle());
	}

	/**
	 *
	 * @param sbbEntity
	 * @param cmpFieldName
	 * @param cmpFieldValue
	 */
	public static void setCMPFieldOfTypeEventContext(SbbEntity sbbEntity, String cmpFieldName, javax.slee.EventContext cmpFieldValue) {
		if (cmpFieldValue == null) {
			sbbEntity.setCMPField(cmpFieldName, null);
			return;
		}
		EventContext eventContextImpl = null;
		try {
			eventContextImpl = (EventContext) cmpFieldValue;
		} catch (ClassCastException e) {
			throw new IllegalArgumentException("CMP value being set (" + cmpFieldValue + ") is an unknown EventContext implementation");
		}
		sbbEntity.setCMPField(cmpFieldName,eventContextImpl.getEventContextHandle());
	}

	/**
	 *
	 * @param sbbEntity
	 * @param cmpFieldName
	 * @param cmpFieldValue
	 */
	public static void setCMPFieldOfTypePrimitiveOrUnknown(SbbEntity sbbEntity, String cmpFieldName, Object cmpFieldValue) {
		sbbEntity.setCMPField(cmpFieldName,cmpFieldValue);
	}

	/**
	 *
	 * @param sbbEntity
	 * @param cmpFieldName
	 * @param object
	 */
	public static void setCMPFieldOfTypeProfileLocalObject(SbbEntity sbbEntity, String cmpFieldName, javax.slee.profile.ProfileLocalObject cmpFieldValue) {
		if (cmpFieldValue == null) {
			sbbEntity.setCMPField(cmpFieldName, null);
			return;
		}
		ProfileLocalObject profileLocalObjectConcreteImpl = null;
		try {
			profileLocalObjectConcreteImpl = (ProfileLocalObject) cmpFieldValue;
		} catch (ClassCastException e) {
			throw new IllegalArgumentException("CMP value being set (" + cmpFieldValue + ") is an unknown ProfileLocalObject implementation");
		}
		final ProfileLocalObjectCmpValue profileLocalObjectCmpValue = new ProfileLocalObjectCmpValue(profileLocalObjectConcreteImpl.getProfileTableName(),profileLocalObjectConcreteImpl.getProfileName());
		sbbEntity.setCMPField(cmpFieldName, profileLocalObjectCmpValue);
	}

	/**
	 *
	 * @param sbbEntity
	 * @param cmpFieldName
	 * @param cmpFieldValue
	 */
	public static void setCMPFieldOfTypeSbbLocalObject(SbbEntity sbbEntity, String cmpFieldName, SbbLocalObject cmpFieldValue) {
		if (cmpFieldValue == null) {
			sbbEntity.setCMPField(cmpFieldName, null);
			return;
		}
		SbbLocalObjectImpl sbbLocalObjectImpl = null;
		try {
			sbbLocalObjectImpl = (SbbLocalObjectImpl) cmpFieldValue;
		} catch (ClassCastException e) {
			throw new IllegalArgumentException("CMP value being set ("+ cmpFieldValue+ ") is an unknown SbbLocalObject implementation");
		}
		final CMPFieldDescriptor field = sbbEntity.getSbbComponent().getDescriptor().getCmpFields().get(cmpFieldName);
		if (field.getSbbRef() != null && !field.getSbbRef().equals(sbbLocalObjectImpl.getSbbEntity().getSbbComponent().getSbbID())) {
			throw new IllegalArgumentException("CMP value being set ("+ sbbLocalObjectImpl.getSbbEntity().getSbbComponent().getSbbID()+ ") is for a different sbb then the one expected ("+ field.getSbbRef() + ")");
		}
		sbbEntity.setCMPField(cmpFieldName, sbbLocalObjectImpl.getSbbEntityId());
	}

	/**
	 *
	 * @param cmpFieldName
	 * @param returnType
	 * @return
	 */
	public static Object getCMPFieldOfTypeUnknown(SbbEntity sbbEntity,String cmpFieldName) {
		return sbbEntity.getCMPField(cmpFieldName);
	}

	/**
	 *
	 * @param cmpFieldName
	 * @return
	 */
	public static Integer getCMPFieldOfTypeInteger(SbbEntity sbbEntity,String cmpFieldName) {
		final Object cmpFieldValue = sbbEntity.getCMPField(cmpFieldName);
		if (cmpFieldValue == null) {
			return DEFAULT_CMP_VALUE_INTEGER;
		}
		else {
			return (Integer) cmpFieldValue;
		}
	}

	/**
	 *
	 * @param cmpFieldName
	 * @return
	 */
	public static Boolean getCMPFieldOfTypeBoolean(SbbEntity sbbEntity,String cmpFieldName) {
		final Object cmpFieldValue = sbbEntity.getCMPField(cmpFieldName);
		if (cmpFieldValue == null) {
			return DEFAULT_CMP_VALUE_BOOLEAN;
		}
		else {
			return (Boolean) cmpFieldValue;
		}
	}

	/**
	 *
	 * @param cmpFieldName
	 * @return
	 */
	public static Byte getCMPFieldOfTypeByte(SbbEntity sbbEntity,String cmpFieldName) {
		final Object cmpFieldValue = sbbEntity.getCMPField(cmpFieldName);
		if (cmpFieldValue == null) {
			return DEFAULT_CMP_VALUE_BYTE;
		}
		else {
			return (Byte) cmpFieldValue;
		}
	}

	/**
	 *
	 * @param cmpFieldName
	 * @return
	 */
	public static Character getCMPFieldOfTypeChar(SbbEntity sbbEntity,String cmpFieldName) {
		final Object cmpFieldValue = sbbEntity.getCMPField(cmpFieldName);
		if (cmpFieldValue == null) {
			return DEFAULT_CMP_VALUE_CHAR;
		}
		else {
			return (Character) cmpFieldValue;
		}
	}

	/**
	 *
	 * @param cmpFieldName
	 * @return
	 */
	public static Short getCMPFieldOfTypeShort(SbbEntity sbbEntity,String cmpFieldName) {
		final Object cmpFieldValue = sbbEntity.getCMPField(cmpFieldName);
		if (cmpFieldValue == null) {
			return DEFAULT_CMP_VALUE_SHORT;
		}
		else {
			return (Short) cmpFieldValue;
		}
	}

	/**
	 *
	 * @param cmpFieldName
	 * @return
	 */
	public static Long getCMPFieldOfTypeLong(SbbEntity sbbEntity,String cmpFieldName) {
		final Object cmpFieldValue = sbbEntity.getCMPField(cmpFieldName);
		if (cmpFieldValue == null) {
			return DEFAULT_CMP_VALUE_LONG;
		}
		else {
			return (Long) cmpFieldValue;
		}
	}

	/**
	 *
	 * @param cmpFieldName
	 * @return
	 */
	public static Double getCMPFieldOfTypeDouble(SbbEntity sbbEntity,String cmpFieldName) {
		final Object cmpFieldValue = sbbEntity.getCMPField(cmpFieldName);
		if (cmpFieldValue == null) {
			return DEFAULT_CMP_VALUE_DOUBLE;
		}
		else {
			return (Double) cmpFieldValue;
		}
	}

	/**
	 *
	 * @param cmpFieldName
	 * @return
	 */
	public static Float getCMPFieldOfTypeFloat(SbbEntity sbbEntity,String cmpFieldName) {
		final Object cmpFieldValue = sbbEntity.getCMPField(cmpFieldName);
		if (cmpFieldValue == null) {
			return DEFAULT_CMP_VALUE_FLOAT;
		}
		else {
			return (Float) cmpFieldValue;
		}
	}

	/**
	 *
	 * @param sbbEntity
	 * @param cmpFieldName
	 * @return
	 */
	public static ActivityContextInterface getCMPFieldOfTypeActivityContextInterface(SbbEntity sbbEntity,String cmpFieldName) {
		final Object cmpFieldValue = sbbEntity.getCMPField(cmpFieldName);
		if (cmpFieldValue == null) {
			return null;
		}
		else {
			final ActivityContext ac = sleeContainer.getActivityContextFactory().getActivityContext((ActivityContextHandle) cmpFieldValue);
			if (ac != null) {
				return sbbEntity.asSbbActivityContextInterface(ac.getActivityContextInterface());
			} else {
				return null;
			}
		}
	}

	/**
	 *
	 * @param sbbEntity
	 * @param cmpFieldName
	 * @return
	 */
	public static javax.slee.EventContext getCMPFieldOfTypeEventContext(SbbEntity sbbEntity,String cmpFieldName) {
		final Object cmpFieldValue = sbbEntity.getCMPField(cmpFieldName);
		if (cmpFieldValue == null) {
			return null;
		}
		else {
			return sleeContainer.getEventContextFactory().getEventContext((EventContextHandle)cmpFieldValue);
		}
	}

	/**
	 *
	 * @param sbbEntity
	 * @param cmpFieldName
	 * @return
	 */
	public static javax.slee.profile.ProfileLocalObject getCMPFieldOfTypeProfileLocalObject(SbbEntity sbbEntity,String cmpFieldName) {
		final Object cmpFieldValue = sbbEntity.getCMPField(cmpFieldName);
		if (cmpFieldValue == null) {
			return null;
		}
		else {
			final ProfileLocalObjectCmpValue profileLocalObjectCmpValue = (ProfileLocalObjectCmpValue) cmpFieldValue;
			try {
				final ProfileTable profileTable = sleeContainer.getSleeProfileTableManager().getProfileTable(profileLocalObjectCmpValue.getProfileTableName());
				return profileTable.find(profileLocalObjectCmpValue.getProfileName());
			} catch (UnrecognizedProfileTableNameException e) {
				return null;
			}
		}
	}

	/**
	 *
	 * @param sbbEntity
	 * @param cmpFieldName
	 * @return
	 */
	public static SbbLocalObject getCMPFieldOfTypeSbbLocalObject(SbbEntity sbbEntity,String cmpFieldName) {
		final Object cmpFieldValue = sbbEntity.getCMPField(cmpFieldName);
		if (cmpFieldValue == null) {
			return null;
		}
		else {
			final SbbEntity anotherSbbEntity = sleeContainer.getSbbEntityFactory().getSbbEntity((SbbEntityID) cmpFieldValue,false);
			if (anotherSbbEntity == null)
				return null;
			else if (anotherSbbEntity.isRemoved())
				return null;
			else {
				return anotherSbbEntity.getSbbLocalObject();
			}
		}
	}

	// CHILD RELATION GETTER

	/**
	 * Retrieves the {@link ChildRelation} for the specified sbb entity and get
	 * child relation method name
	 */
	public static ChildRelation getChildRelation(SbbEntity sbbEntity,
			String childRelationMethodName) {

		if (sbbEntity.getSbbObject().getState() != SbbObjectState.READY)
			throw new IllegalStateException(
					"Could not invoke getChildRelation Method, Sbb Object is not in the READY state!");

		if (logger.isTraceEnabled()) {
			logger.trace("ChildRelation Interceptor:"
							+ childRelationMethodName);
		}

		return sbbEntity.getChildRelation(childRelationMethodName);
	}

	// EVENT FIRING

	/**
	 * The logic to fire an event from an SLEE 1.0 Sbb
	 *
	 * @param sbbEntity
	 *            an sbb entity with an object assigned
	 * @param eventTypeID
	 *            the id of the event to fire
	 * @param eventObject
	 *            the event object, can't be null
	 * @param aci
	 *            the activity context where the event will be fired, can't be
	 *            null
	 * @param address
	 *            the optional address to fire the event
	 */
	public static void fireEvent(SbbEntity sbbEntity, EventTypeID eventTypeID,
			Object eventObject, ActivityContextInterface aci, Address address) {
		fireEvent(sbbEntity, eventTypeID, eventObject, aci, address, null);
	}

	/**
	 * The logic to fire an event from an SLEE 1.1 Sbb
	 *
	 * @param sbbEntity
	 *            an sbb entity with an object assigned
	 * @param eventTypeID
	 *            the id of the event to fire
	 * @param eventObject
	 *            the event object, can't be null
	 * @param aci
	 *            the activity context where the event will be fired, can't be
	 *            null
	 * @param address
	 *            the optional address to fire the event
	 * @param serviceID
	 *            the optional service id to fire the event
	 */
	public static void fireEvent(SbbEntity sbbEntity, EventTypeID eventTypeID,
			Object eventObject, ActivityContextInterface aci, Address address,
			ServiceID serviceID) {

		if (sleeContainer.getCongestionControl().refuseFireEvent()) {
			throw new SLEEException("congestion control refused event");
		}

		// JAIN SLEE (TM) specs - Section 8.4.1
		// The SBB object must have an assigned SBB entity when it invokes this
		// method.
		// Otherwise, this method throws a java.lang.IllegalStateException.
		if (sbbEntity == null || sbbEntity.getSbbObject() == null
				|| sbbEntity.getSbbObject().getState() != SbbObjectState.READY)
			throw new IllegalStateException("SbbObject not assigned!");

		// JAIN SLEE (TM) specs - Section 8.4.1
		// The event ... cannot be null. If ... argument is null, the fire
		// event method throws a java.lang.NullPointerException.
		if (eventObject == null)
			throw new NullPointerException(
					"JAIN SLEE (TM) specs - Section 8.4.1: The event ... cannot be null. If ... argument is null, the fire event method throws a java.lang.NullPointerException.");

		// JAIN SLEE (TM) specs - Section 8.4.1
		// The activity ... cannot be null. If ... argument is null, the fire
		// event method throws a java.lang.NullPointerException.
		if (aci == null)
			throw new NullPointerException(
					"JAIN SLEE (TM) specs - Section 8.4.1: The activity ... cannot be null. If ... argument is null, the fire event method throws a java.lang.NullPointerException.");

		// JAIN SLEE (TM) specs - Section 8.4.1
		// It is a mandatory transactional method (see Section 9.6.1).
		final SleeTransactionManager txManager = sleeContainer.getTransactionManager();
		txManager.mandateTransaction();

		// rebuild the ac from the aci in the 2nd argument of the invoked
		// method, check it's state
		ActivityContext ac = ((org.mobicents.slee.container.activity.ActivityContextInterface) aci)
				.getActivityContext();
		if (logger.isTraceEnabled()) {
			logger.trace("invoke(): firing event on "
					+ ac);
		}

		// exception not in specs by mandated by
		// tests/activities/activitycontext/Test560Test.xml , it's preferable to
		// do double check on here than have the aci fire method throwing it and
		// the ra slee endpoint having to translate it to activity ending
		// exception, it is not common to have custom event firing in sbbs
		if (ac.isEnding()) {
			throw new IllegalStateException("activity context "
					+ ac.getActivityContextHandle() + " is ending");
		}

		final EventRoutingTransactionData transactionData = txManager.getTransactionContext().getEventRoutingTransactionData();
		if (transactionData != null) {
			final EventContext eventBeingDelivered = transactionData.getEventBeingDelivered();
			if (eventBeingDelivered != null && eventBeingDelivered.getEvent() == eventObject) {
				// there is an event being delivered by this tx and it matches the event being fired, lets copy the ref handler
				// fire the event
				ac.fireEvent(eventTypeID, eventObject, (Address) address, serviceID, eventBeingDelivered);
				return;
			}
		}
		// seems it is not a refire
		ac.fireEvent(eventTypeID, eventObject, (Address) address, serviceID, null, null, null);

	}

	// GET PROFILE CMP METHODS

	/**
	 * Retrieves a profile given the cmp method name and profile id
	 */
	public static Object getProfileCMPMethod(SbbEntity sbbEntity,
			String getProfileCMPMethodName, ProfileID profileID)
			throws UnrecognizedProfileTableNameException,
			UnrecognizedProfileNameException {

		GetProfileCMPMethodDescriptor mGetProfileCMPMethod = sbbEntity.getSbbComponent()
				.getDescriptor().getGetProfileCMPMethods().get(
						getProfileCMPMethodName);
		if (mGetProfileCMPMethod == null)
			throw new AbstractMethodError("Profile CMP Method not found");

		if (sbbEntity.getSbbObject().getState() != SbbObjectState.READY) {
			throw new IllegalStateException(
					"Could not invoke getProfileCMP Method, Sbb Object is not in the READY state!");
		}

		ProfileManagement sleeProfileManager = sleeContainer
				.getSleeProfileTableManager();

		ProfileTable profileTable = sleeProfileManager.getProfileTable(profileID.getProfileTableName());

		if (!profileTable.profileExists(profileID.getProfileName())) {
			throw new UnrecognizedProfileNameException(profileID.toString());
		}

		return profileTable.getProfile(profileID.getProfileName()).getProfileCmpSlee10Wrapper();
	}

	// SBB USAGE PARAMS

	public static Object getSbbUsageParameterSet(SbbEntity sbbEntity, String name)
			throws UnrecognizedUsageParameterSetNameException {
		if (logger.isTraceEnabled()) {
			logger.trace("getSbbUsageParameterSet(): serviceId = "
					+ sbbEntity.getSbbEntityId().getServiceID() + " , sbbID = "
					+ sbbEntity.getSbbId() + " , name = " + name);
		}
		return getServiceUsageMBeanImpl(sbbEntity.getSbbEntityId().getServiceID())
				.getInstalledUsageParameterSet(sbbEntity.getSbbId(), name);
	}

	public static Object getDefaultSbbUsageParameterSet(SbbEntity sbbEntity) {
		if (logger.isTraceEnabled()) {
			logger.trace("getDefaultSbbUsageParameterSet(): "
					+ sbbEntity.getSbbEntityId().getServiceID() + " sbbID = "
					+ sbbEntity.getSbbId());
		}
		return getServiceUsageMBeanImpl(sbbEntity.getSbbEntityId().getServiceID())
				.getDefaultInstalledUsageParameterSet(sbbEntity.getSbbId());
	}

	private static ServiceUsageMBeanImpl getServiceUsageMBeanImpl(
			ServiceID serviceID) {
		return (ServiceUsageMBeanImpl) sleeContainer
				.getComponentRepository().getComponentByID(serviceID)
				.getServiceUsageMBean();
	}

}


/*
 * 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.facilities.nullactivity;

import javax.slee.FactoryException;
import javax.slee.TransactionRequiredLocalException;
import javax.slee.management.SleeState;
import javax.slee.nullactivity.NullActivity;
import javax.slee.resource.ActivityAlreadyExistsException;
import javax.slee.resource.ActivityFlags;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.AbstractSleeContainerModule;
import org.mobicents.slee.container.facilities.nullactivity.NullActivityFactory;
import org.mobicents.slee.container.facilities.nullactivity.NullActivityHandle;

/**
 * Implementation of the null activity factory.
 *
 * @author M. Ranganathan
 * @author Ivelin Ivanov
 * @author martins
 *
 */
public class NullActivityFactoryImpl extends AbstractSleeContainerModule
		implements NullActivityFactory {

	private static Logger logger = Logger
			.getLogger(NullActivityFactoryImpl.class);

	@Override
	public void sleeInitialization() {
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.nullactivity.NullActivityFactory#createNullActivity()
	 */
	public NullActivity createNullActivity()
			throws TransactionRequiredLocalException, FactoryException {
		return createNullActivity(createNullActivityHandle(), true);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.runtime.facilities.nullactivity.NullActivityFactory
	 * #createNullActivityHandle()
	 */
	public NullActivityHandleImpl createNullActivityHandle() {
		return new NullActivityHandleImpl(sleeContainer.getUuidGenerator()
				.createUUID());
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.runtime.facilities.nullactivity.NullActivityFactory
	 * #createNullActivityImpl
	 * (org.mobicents.slee.runtime.facilities.nullactivity.NullActivityHandle,
	 * boolean)
	 */
	public NullActivityImpl createNullActivity(
			NullActivityHandle nullActivityHandle, boolean mandateTransaction)
			throws TransactionRequiredLocalException, FactoryException {
		// check mandated by SLEE TCK test CreateActivityWhileStoppingTest
		if (sleeContainer.getSleeState() != SleeState.RUNNING) {
			return null;
		}

		if (mandateTransaction) {
			sleeContainer.getTransactionManager().mandateTransaction();
		}

		// create activity
		NullActivityImpl nullActivity = new NullActivityImpl(nullActivityHandle);
		// get an activity context for it
		try {
			sleeContainer.getActivityContextFactory().createActivityContext(
					new NullActivityContextHandle(nullActivityHandle),
					ActivityFlags.REQUEST_ACTIVITY_UNREFERENCED_CALLBACK);
		} catch (ActivityAlreadyExistsException e) {
			throw new FactoryException(e.getMessage(), e);
		}

		if (logger.isDebugEnabled()) {
			logger
					.debug("NullActivityFactory.createNullActivity() Created null activity "
							+ nullActivity);
		}

		return nullActivity;
	}

}


/*
 * 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.transaction;

import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.Transaction;

import org.apache.log4j.Logger;

/**
 *
 * @author martins
 *
 */
public class SleeTransactionSynchronization implements Synchronization {

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

	/**
	 *
	 */
	private final Transaction tx;

	/**
	 *
	 */
	private final TransactionContextImpl txContext;

	/**
	 *
	 * @param tx
	 * @param txContext
	 */
	public SleeTransactionSynchronization(Transaction tx,TransactionContextImpl txContext) {
		this.tx = tx;
		this.txContext = txContext;
	}

	/*
	 * (non-Javadoc)
	 * @see javax.transaction.Synchronization#afterCompletion(int)
	 */
	public void afterCompletion(int status) {
		TransactionContextThreadLocal.setTransactionContext(null);
		switch (status) {

		case Status.STATUS_COMMITTED:
			if (logger.isDebugEnabled()) {
				logger.debug("Completed commit of tx " + tx);
			}
			txContext.executeAfterCommitPriorityActions();
			txContext.executeAfterCommitActions();
			break;

		case Status.STATUS_ROLLEDBACK:
			if (logger.isDebugEnabled()) {
				logger.debug("Completed rollback of tx " + tx);
			}
			txContext.executeAfterRollbackActions();
			break;

		default:
			throw new IllegalStateException("Unexpected transaction state "
					+ status);
		}
		txContext.cleanup();
	}

	/*
	 * (non-Javadoc)
	 * @see javax.transaction.Synchronization#beforeCompletion()
	 */
	public void beforeCompletion() {
		txContext.executeBeforeCommitPriorityActions();
		txContext.executeBeforeCommitActions();
	}

}


/*
 * TeleStax, Open Source Cloud Communications
 * Copyright 2011-2015, Telestax Inc and individual contributors
 * by the @authors tag.
 *
 * This program is free software: you can redistribute it and/or modify
 * under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 *
 * This file incorporates work covered by the following copyright contributed under the GNU LGPL : Copyright 2007-2011 Red Hat.
 */
package org.mobicents.slee.runtime.eventrouter.routingtask;

import java.lang.reflect.Method;
import java.util.Collection;

import javax.slee.Address;
import javax.slee.SLEEException;
import javax.slee.profile.AttributeNotIndexedException;
import javax.slee.profile.AttributeTypeMismatchException;
import javax.slee.profile.ProfileID;
import javax.slee.profile.ProfileSpecificationID;
import javax.slee.profile.UnrecognizedAttributeException;
import javax.slee.profile.UnrecognizedProfileTableNameException;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.activity.ActivityContext;
import org.mobicents.slee.container.component.profile.ProfileSpecificationComponent;
import org.mobicents.slee.container.component.sbb.EventEntryDescriptor;
import org.mobicents.slee.container.component.sbb.InitialEventSelectorVariables;
import org.mobicents.slee.container.component.sbb.SbbComponent;
import org.mobicents.slee.container.component.service.ServiceComponent;
import org.mobicents.slee.container.event.EventContext;
import org.mobicents.slee.container.jndi.JndiManagement;
import org.mobicents.slee.container.profile.ProfileTable;
import org.mobicents.slee.container.sbb.SbbObject;
import org.mobicents.slee.container.sbb.SbbObjectPool;
import org.mobicents.slee.container.sbbentity.SbbEntity;

public class InitialEventProcessor {

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

	private static final char NOT_SELECTED = '_';
	private static final String NOT_SELECTED_STRING = "_";
	private static final String ALL_NOT_SELECTED_EXCEPT_AC = "____";

	/**
	 * Compute a convergence name for the Sbb for the given Slee event.
	 * Convergence names are used to instantiate the Sbb. I really ought to move
	 * this to SleeContainer.java
	 *
	 * @param eventContext -
	 *            slee event for the convergence name computation
	 * @return the convergence name or null if this is not an initial event for
	 *         this service
	 */
	private String computeConvergenceName(EventContext eventContext,
			ServiceComponent serviceComponent, SleeContainer sleeContainer) throws Exception {

		final SbbComponent sbbComponent = serviceComponent.getRootSbbComponent();
		final EventEntryDescriptor eventEntryDescriptor = sbbComponent.getDescriptor().getEventEntries().get(eventContext.getEventTypeId());
		StringBuilder buff = null;

		/*
		 * An initial-event-selector-method-name element. This element is
		 * optional and is meaningful only if initial-event is true. It
		 * identifies an in itial event selector method. The SLEE invokes this
		 * optional method to d etermine if an event of the specified event type
		 * is an initial event if the SBB is a root SBB of a Service (see
		 * Section 8.5.4). Note that this method is not static. You can either
		 * used a pooled instance of the object or create a new instance of the
		 * object to run the specified method.
		 */
		if (eventEntryDescriptor.getInitialEventSelectorMethod() != null) {
			// IES METHOD DEFINED
			// invoke method
			InitialEventSelectorImpl selector = new InitialEventSelectorImpl(eventContext,eventEntryDescriptor);
			SbbObjectPool pool = sleeContainer.getSbbManagement().getObjectPool(serviceComponent.getServiceID(),
					sbbComponent.getSbbID());
			SbbObject sbbObject = pool.borrowObject();
			Object[] args = new Object[] { selector };
			ClassLoader oldCl = Thread.currentThread().getContextClassLoader();

			final JndiManagement jndiManagement = sleeContainer.getJndiManagement();
			jndiManagement.pushJndiContext(sbbComponent);

			try {
				Thread.currentThread().setContextClassLoader(
						sbbComponent.getClassLoader());
				final Method m = sbbComponent.getInitialEventSelectorMethods().get(eventEntryDescriptor.getInitialEventSelectorMethod());
				selector = (InitialEventSelectorImpl) m.invoke(sbbObject.getSbbConcrete(),
						args);
				if (selector == null) {
					return null;
				}
				if (!selector.isInitialEvent()) {
					return null;
				}
			} finally {
				jndiManagement.popJndiContext();
				Thread.currentThread().setContextClassLoader(oldCl);
				pool.returnObject(sbbObject);
			}
			// build convergence name
			// AC VARIABLE
			if (selector.isActivityContextSelected()) {
				buff = new StringBuilder(eventContext.getLocalActivityContext().getStringId());
			} else {
				buff = new StringBuilder(NOT_SELECTED_STRING);
			}
			// ADDRESS VARIABLE
			if (selector.isAddressSelected() && selector.getAddress() != null) {
				buff.append(selector.getAddress().toString());
			}
			else {
				buff.append(NOT_SELECTED);
			}
			// EVENT TYPE
			if (selector.isEventTypeSelected()) {
				buff.append(eventContext.getEventTypeId());
			}
			else {
				buff.append(NOT_SELECTED);
			}
			// EVENT
			if (selector.isEventSelected()) {
				buff.append(eventContext.getEventContextHandle().getId());
			}
			else {
				buff.append(NOT_SELECTED);
			}
			// ADDRESS PROFILE
			if (selector.isAddressProfileSelected() && selector.getAddress() != null) {
				final Collection<ProfileID> profileIDs = getAddressProfilesMatching(selector.getAddress(), serviceComponent, sbbComponent, sleeContainer);
				if (profileIDs.isEmpty())
					// no profiles located
					return null;
				else {
					buff.append(profileIDs.iterator().next());
				}
			}
			else {
				buff.append(NOT_SELECTED);
			}
			// CUSTOM NAME
			if (selector.getCustomName() != null) {
				buff.append(selector.getCustomName());
			}

		}
		else {
			// NO IES METHOD DEFINED
			// build convergence name considering the variabes selected in sbb's xml descriptor
			// AC VARIABLE
			final InitialEventSelectorVariables initialEventSelectorVariables = eventEntryDescriptor.getInitialEventSelectVariables();
			if(initialEventSelectorVariables.isActivityContextSelected()) {
				if (initialEventSelectorVariables.isActivityContextOnlySelected()) {
					// special most used case where convergence name is only bound to activity context
					return new StringBuilder(eventContext.getLocalActivityContext().getStringId()).append(ALL_NOT_SELECTED_EXCEPT_AC).toString();
				}
				else {
					buff = new StringBuilder(eventContext.getLocalActivityContext().getStringId());
				}
			}
			else {
				buff = new StringBuilder(NOT_SELECTED_STRING);
			}
			// ADDRESS VARIABLE
			if(initialEventSelectorVariables.isAddressSelected() && eventContext.getAddress() != null) {
				buff.append(eventContext.getAddress().toString());
			}
			else {
				buff.append(NOT_SELECTED);
			}
			// EVENT TYPE
			if(initialEventSelectorVariables.isEventTypeSelected()) {
				buff.append(eventContext.getEventTypeId());
			}
			else {
				buff.append(NOT_SELECTED);
			}
			// EVENT
			if(initialEventSelectorVariables.isEventSelected()) {
				buff.append(eventContext.getEventContextHandle().getId());
			}
			else {
				buff.append(NOT_SELECTED);
			}
			// ADDRESS PROFILE
			if(initialEventSelectorVariables.isAddressProfileSelected() && eventContext.getAddress() != null) {
				final Collection<ProfileID> profileIDs = getAddressProfilesMatching(eventContext.getAddress(), serviceComponent, sbbComponent, sleeContainer);
				if (profileIDs.isEmpty())
					// no profiles located
					return null;
				else {
					buff.append(profileIDs.iterator().next());
				}
			}
			else {
				buff.append(NOT_SELECTED);
			}
		}

		return buff.toString();
	}

	private Collection<ProfileID> getAddressProfilesMatching(Address address, ServiceComponent serviceComponent, SbbComponent sbbComponent, SleeContainer sleeContainer) throws NullPointerException, UnrecognizedProfileTableNameException, SLEEException, UnrecognizedAttributeException, AttributeNotIndexedException, AttributeTypeMismatchException {

		logger.trace("getAddressProfilesMatching: sbbComponent: "+sbbComponent);
		logger.trace("getAddressProfilesMatching: sbbComponent: "+sbbComponent.getDescriptor());
		logger.trace("getAddressProfilesMatching: sbbComponent: "+sbbComponent.getDescriptor().getSbbID());

		ProfileSpecificationID addressProfileId = sbbComponent.getDescriptor().getAddressProfileSpecRef();
		logger.trace("getAddressProfilesMatching: addressProfileId: "+addressProfileId);

		ProfileSpecificationComponent profileSpecificationComponent = sleeContainer.getComponentRepository().getComponentByID(addressProfileId);
		String addressProfileTable = serviceComponent.getDescriptor().getAddressProfileTable();
		// Cannot find an address profile table spec.
		if (addressProfileTable == null) {
			throw new SLEEException("null address profile table in service !");
		}
		ProfileTable profileTable = sleeContainer.getSleeProfileTableManager().getProfileTable(addressProfileTable);
		return profileTable.getProfilesByAttribute(profileSpecificationComponent.isSlee11() ? "address" : "addresses", address, profileSpecificationComponent.isSlee11());
	}

	public SbbEntity processInitialEvent(ServiceComponent serviceComponent,
			EventContext deferredEvent, SleeContainer sleeContainer,
			ActivityContext ac) {

		SbbEntity sbbEntity = null;

		if (logger.isTraceEnabled()) {
			logger.trace("Initial event processing for " + serviceComponent+" and "+deferredEvent);
		}

		/*
		 * Start of SLEE originated invocation sequence
		 * ============================================ We run a SLEE
		 * originated invocation sequence here for every service that
		 * this might be an intial event for
		 */

		/*
		 * Use the initial event select to compute the convergence names
		 * for the service. This is a method that is provided by the
		 * service deployment. The names set is composed by only one
		 * convergence name the error is due an error in the pseudocode
		 */
		String name = null;
		try {
			name = computeConvergenceName(deferredEvent,serviceComponent,sleeContainer);
		}
		catch (Exception e) {
			logger.error("Failed to compute convergance name: "+e.getMessage(),e);
		}

		if (name != null) {
			sbbEntity = sleeContainer.getSbbEntityFactory().createRootSbbEntity(serviceComponent.getServiceID(),name);
			if (sbbEntity.isCreated()) {
				if (logger.isDebugEnabled()) {
					logger.debug("Computed convergence name for "+serviceComponent+" and "+deferredEvent+" is "
							+ name + ", creating sbb entity and attaching to activity context.");
				}
				// set priority
				sbbEntity.setPriority(serviceComponent.getDescriptor().getDefaultPriority());
			} else {
				if (logger.isDebugEnabled()) {
					logger.debug("Computed convergence name for "+serviceComponent.getServiceID()+" and "+deferredEvent+" is "
							+ name + ", sbb entity already exists, attaching to activity context (if not attached yet)");
				}
			}
			// ensure sbb entity is attached to AC
			if (ac.attachSbbEntity(sbbEntity.getSbbEntityId())) {
				// do the reverse on the sbb entity
				sbbEntity.afterACAttach(deferredEvent.getActivityContextHandle());
			}

		} else {
			if (logger.isDebugEnabled()) {
				logger.debug("Computed convergence name for "+serviceComponent.getServiceID()+" and "+deferredEvent+" is null, either the root sbb is not interested in the event or an error occurred.");
			}
		}

		return sbbEntity;

	}

}


/*
 * 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.
 */

/***************************************************
 *                                                 *
 *  Restcomm: The Open Source VoIP Platform      *
 *                                                 *
 *  Distributable under LGPL license.              *
 *  See terms of license at gnu.org.               *
 *                                                 *
 *  Created on 2005-5-21                             *
 *                                                 *
 ***************************************************/

package org.mobicents.slee.container.deployment;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;

import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;

/**
 * @author Ivelin Ivanov
 * @author Stefano Gamma
 */
public class ClassUtils {

    private static final String PUBLIC_IDENTIFIER = "Public";
    private static Logger logger = Logger.getLogger(ClassUtils.class);

    public static final String IS_PREFIX = "is";
    public static final String GET_PREFIX = "get";
    public static final String SET_PREFIX = "set";

    /**
     * Returns the set of names representing valid, full access (read&write) JavaBean properties declared in the given class.
     * NOTE: the implementation is not as strict as in Introspector (@see java.beans.Introspector#getTargetPropertyInfo()). It probably should be.
     *
     * @param CtClass the class metadata
     * @return Set of names representing valid, full access (read&write) JavaBean properties declared in the given class
     * @throws NotFoundException if a class type could not be found
     *
     */
    public static Set getCMPFields(CtClass clazz) {

        Set properties = new HashSet();

	    // Apply some reflection to the current class.

	    // First get an array of all the public methods at this level
	    Set methods = getPublicAbstractMethods(clazz);

	    // remove non-public methods

	    Iterator iter = methods.iterator();

	    // the key in the getter/setter tables will be method name
	    HashMap getters = new HashMap();
	    HashMap setters = new HashMap();

	    // split out getters and setters; ignore the rest
	    while (iter.hasNext()) {
	        CtMethod method = (CtMethod)iter.next();
	        String mname = method.getName();

	        // skip static methods
	        if (Modifier.isStatic(method.getModifiers())) continue;

	        String property = "";
	        try {
		        // skip methods, which throw exceptions
		        if (method.getExceptionTypes().length > 0) continue;

		        if (mname.startsWith(GET_PREFIX)) {
		            property = mname.substring(GET_PREFIX.length());
		            getters.put(property, method);
		        } else if (mname.startsWith(IS_PREFIX) && method.getReturnType().equals(CtClass.booleanType)) {
		            property = mname.substring(IS_PREFIX.length());
		            getters.put(property, method);
		        } else if (mname.startsWith(SET_PREFIX)) {
		            property = mname.substring(SET_PREFIX.length());
		            setters.put(property, method);
		        }
	        } catch (NotFoundException e) {
	            logger.warn(e);
	        }
            if (property.length() == 0 || !Character.isUpperCase(property.charAt(0)) || property.equals(PUBLIC_IDENTIFIER)) {
                logger.warn("Method " + mname + " has a non-capitalized first character of the JavaBean property.");
                getters.remove(property);
                setters.remove(property);
            }
		}

	    // iterate over getters and find matching setters
	    iter = getters.entrySet().iterator();
	    while (iter.hasNext()) {
	        Map.Entry entry = (Map.Entry)iter.next();
	        String property = (String)entry.getKey();
	        CtMethod getter = (CtMethod)entry.getValue();
	        // find matching setter
	        CtMethod setter = (CtMethod)setters.get(property);
	        // if setter is null, the property is not full access (read&write), therefore ignored
	        try {
		        if (setter != null) {
		            CtClass[] sparams = setter.getParameterTypes();
		            if (sparams.length == 1 && sparams[0].equals(getter.getReturnType())) {
		                properties.add(property);
		            }
		        }
	        } catch (NotFoundException e) {
	            logger.warn(e);
	        }
		}
	    return properties;
    }

    /**
     * Return the String allowing one to create an Object (Integer, Boolean,
     * Byte,... ) from a primitive type given in parameter.
     *
     * @param argumentType -
     *            the primitive type as a String (int, boolean, byte, ...)
     * @param argument -
     *            the argument to transform
     * @return the String allowing one to create an Object from a primitive type
     */
    public static String getObjectFromPrimitiveType(String argumentType,
    		String argument) {
    	if (argumentType.equals("int"))
    		return "new Integer(" + argument + ")";
    	if (argumentType.equals("boolean"))
    		return "new Boolean(" + argument + ")";
    	if (argumentType.equals("byte"))
    		return "new Byte(" + argument + ")";
    	if (argumentType.equals("char"))
    		return "new Character(" + argument + ")";
    	if (argumentType.equals("double"))
    		return "new Double(" + argument + ")";
    	if (argumentType.equals("float"))
    		return "new Float(" + argument + ")";
    	if (argumentType.equals("long"))
    		return "new Long(" + argument + ")";
    	if (argumentType.equals("short"))
    		return "new Short(" + argument + ")";
    	return null;
    }

    /**
     * Return the String allowing one to create an Object (Integer, Boolean,
     * Byte,... ) from a primitive type given in parameter.
     *
     * @param argumentType -
     *            the primitive type as a String (int, boolean, byte, ...)
     * @param argument -
     *            the argument to transform
     * @return the String allowing one to create an Object from a primitive type
     */
    public static String getClassFromPrimitiveType(String argumentType) {
    	if (argumentType.equals("int"))
    		return "java.lang.Integer";
    	if (argumentType.equals("boolean"))
    		return "java.lang.Boolean";
    	if (argumentType.equals("byte"))
    		return "java.lang.Byte";
    	if (argumentType.equals("char"))
    		return "java.lang.Character";
    	if (argumentType.equals("double"))
    		return "java.lang.Double";
    	if (argumentType.equals("float"))
    		return "java.lang.Float";
    	if (argumentType.equals("long"))
    		return "java.lang.Long";
    	if (argumentType.equals("short"))
    		return "java.lang.Short";
    	return null;
    }

    /**
     *
     * @param argumentType
     * @return
     */
    public static String getPrimitiveTypeFromClass(String argumentType) {
    	if (argumentType.equals("java.lang.Integer"))
    		return "int";
    	if (argumentType.equals("java.lang.Boolean"))
    		return "boolean";
    	if (argumentType.equals("java.lang.Byte"))
    		return "byte";
    	if (argumentType.equals("java.lang.Character"))
    		return "char";
    	if (argumentType.equals("java.lang.Double"))
    		return "double";
    	if (argumentType.equals("java.lang.Float"))
    		return "float";
    	if (argumentType.equals("java.lang.Long"))
    		return "long";
    	if (argumentType.equals("java.lang.Short"))
    		return "short";
    	return argumentType;
    }

    /**
     * Return the String allowing one to create a primitive type (Integer,
     * Boolean, Byte,... ) from a primitive type given in parameter.
     *
     * @param argumentType
     * @param argument
     * @return
     */
    public static String getPrimitiveTypeFromObject(String argumentType,
    		String argument) {
    	if (argumentType.equals("int"))
    		return "((Integer)" + argument + ").intValue()";
    	if (argumentType.equals("boolean"))
    		return "((Boolean)" + argument + ").booleanValue()";
    	if (argumentType.equals("byte"))
    		return "((Byte)" + argument + ").byteValue()";
    	if (argumentType.equals("char"))
    		return "((Character)" + argument + ").charValue()";
    	if (argumentType.equals("double"))
    		return "((Double)" + argument + ").doubleValue()";
    	if (argumentType.equals("float"))
    		return "((Float)" + argument + ").floatValue()";
    	if (argumentType.equals("long"))
    		return "((Long)" + argument + ").longValue()";
    	if (argumentType.equals("short"))
    		return "((Short)" + argument + ").shortValue()";
    	return null;
    }

    /**
     * Retrieve all abstract methods from a class
     *
     * @param sbbAbstractClass
     *            the class to extract the abstract methods
     * @return all abstract methods from a class
     */
    public static Map getAbstractMethodsFromClass(CtClass sbbAbstractClass) {
    	HashMap abstractMethods = new HashMap();
    	CtMethod[] methods = sbbAbstractClass.getDeclaredMethods();
    	for (int i = 0; i < methods.length; i++) {
    		if (Modifier.isAbstract(methods[i].getModifiers())) {
    			abstractMethods.put(methods[i].getName(), methods[i]);
    		}
    	}

    	return abstractMethods;
    }

    /**
     * Retrieve all concrete (non-abstract and non-native) methods from a class
     * Stored under key Name+signature
     * @param sbbClass
     *            the class to extract the concrete methods from
     * @return all concrete methods from a class
     */
    public static Map getConcreteMethodsFromClass(CtClass sbbClass) {
    	HashMap concreteMethods = new HashMap();
    	CtMethod[] methods = sbbClass.getDeclaredMethods();
    	for (int i = 0; i < methods.length; i++) {
    	    int mods = methods[i].getModifiers();
    		if (!Modifier.isAbstract(mods) && !Modifier.isNative(mods)) {
    			concreteMethods.put(getMethodKey(methods[i]), methods[i]);
    		}
    	}
    	return concreteMethods;
    }

    /**
     * Retrieve all concrete (non-abstract and non-native) methods names from a class
     *
     * @param sbbClass
     *            the class to extract the concrete methods from
     * @return all concrete methods from a class
     */
    public static Set getConcreteMethodsNamesFromClass(CtClass sbbClass) {
    	Set concreteMethods = new HashSet();
    	CtMethod[] methods = sbbClass.getDeclaredMethods();
    	for (int i = 0; i < methods.length; i++) {
    	    int mods = methods[i].getModifiers();
    		if (!Modifier.isAbstract(mods) && !Modifier.isNative(mods)) {
    			concreteMethods.add(methods[i].getName());
    		}
    	}
    	return concreteMethods;
    }

    public static Map getSuperClassesConcreteMethodsFromClass(CtClass sbbAbstractClass) {
    	HashMap concrete = new HashMap();
    	CtMethod[] methods = null;
    	CtClass superClass;
    	try {
    		superClass = sbbAbstractClass.getSuperclass();

    		while (superClass.getName().compareTo("java.lang.Object") != 0) {
    			methods = superClass.getDeclaredMethods();
    			for (int i = 0; i < methods.length; i++) {
    				if (!Modifier.isAbstract(methods[i].getModifiers())) {
    					concrete.put(methods[i].getName(), methods[i]);
    				}
    			}
    			superClass = superClass.getSuperclass();
    		}
    	} catch (NotFoundException e) {
    		String s = "Method not found ! Huh!!";
    		ConcreteClassGeneratorUtils.logger.fatal(s,e);
    		throw new RuntimeException ("s",e);
    	}
    	return concrete;
    }

    public static Map getSuperClassesAbstractMethodsFromClass(CtClass sbbAbstractClass) {
    	HashMap abstractMethods = new HashMap();
    	CtMethod[] methods = null;
    	CtClass superClass;
    	try {
    		superClass = sbbAbstractClass.getSuperclass();

    		while (superClass.getName().compareTo("java.lang.Object") != 0) {
    			methods = superClass.getDeclaredMethods();
    			for (int i = 0; i < methods.length; i++) {
    				if (Modifier.isAbstract(methods[i].getModifiers())) {
    					abstractMethods.put(methods[i].getName(), methods[i]);
    				}
    			}
    			superClass = superClass.getSuperclass();
    		}
    	} catch (NotFoundException e) {
    		String s = "Method not found ! Huh!!";
    		ConcreteClassGeneratorUtils.logger.fatal(s,e);
    		throw new RuntimeException ("s",e);
    	}
    	return abstractMethods;
    }

    /**
     * Collects all methods of the interfaces implemented/extended by the specified {@link CtClass}
     * @param sbbAbstractClass
     * @return
     */
    public static Map getSuperClassesAbstractMethodsFromInterface(CtClass sbbAbstractClass) {
    	HashMap abstractMethods = new HashMap();
    	CtMethod[] methods = null;

    	ArrayList<CtClass> superClasses = new ArrayList<CtClass>();
    	superClasses.add(sbbAbstractClass);
    	ArrayList<CtClass> superClassesProcessed = new ArrayList<CtClass>();

    	try {
    		while(!superClasses.isEmpty()) {
    			// remove head
    			CtClass ctClass = superClasses.remove(0);
    			superClassesProcessed.add(ctClass);
    			// get its methods
    			methods = ctClass.getDeclaredMethods();
    			for (CtMethod ctMethod:methods)	{
    				abstractMethods.put(getMethodKey(ctMethod), ctMethod);
    			}
    			// get super interfaces
    			for(CtClass anotherCtClass : ctClass.getInterfaces()) {
    				if (!superClassesProcessed.contains(anotherCtClass)) {
    					superClasses.add(anotherCtClass);
    				}
    			}
    			try {
    				ctClass.detach();
    			}
    			catch (Exception e) {
    				// ignore
    			}
    		}
    	} catch (NotFoundException e) {
    		logger.error(e);
    	}
    	return abstractMethods;
    }

    /**
     * Retrieve all methods from an interface, including super interfaces
     *
     * @param sbbAbstractClass
     *            the class to extract the abstract methods
     * @return all interface methods from an interface
     */
    public static Map getInterfaceMethodsFromInterface(CtClass interfaceClass) {
    	return getInterfaceMethodsFromInterface(interfaceClass, Collections.emptyMap());
    }

    /**
     * Retrieve all methods from an interface, including super interfaces, except the ones specified in the provided map
     * @param interfaceClass
     * @param exceptMethods
     * @return
     */
    public static Map getInterfaceMethodsFromInterface(CtClass interfaceClass,
            Map exceptMethods) {

        HashMap interfaceMethods = new HashMap();
        CtMethod[] methods = interfaceClass.getDeclaredMethods();
        for (int i = 0; i < methods.length; i++)
        {
            if (exceptMethods.get(methods[i].getName()) == null)
            {
                    ConcreteClassGeneratorUtils.logger.trace(methods[i].getName());
                    interfaceMethods.put(getMethodKey(methods[i]), methods[i]);
            }
        }

        Map temp = getSuperClassesAbstractMethodsFromInterface(interfaceClass);
        for (Iterator i= temp.keySet().iterator(); i.hasNext(); )
        {
            String key = (String)i.next();
            if (!exceptMethods.containsKey(key)) {
                    interfaceMethods.put(key, temp.get(key));
            }
        }

        return interfaceMethods;
    }

    /**
     * @param CtClass the class metadata
     * @return Set - all public abstract methods declared in the given class and all its superclasses
     */
    public static Set getPublicAbstractMethods(CtClass abstractClass) {
    	Set methodsSet = new HashSet();
    	// CtClass.getMethods returns all methods, including the ones declared in super classes
    	CtMethod[] methods = abstractClass.getMethods();
    	for(int i=0; i<methods.length; i++){
    	    if (Modifier.isPublic(methods[i].getModifiers()) &&
		            Modifier.isAbstract(methods[i].getModifiers()))
    	        methodsSet.add(methods[i]);
    	}
    	return methodsSet;
    }

    /**
     * @param CtClass the class metadata
     * @return Set - all public methods declared in the given class and all its superclasses
     */
    public static Set getPublicMethods(CtClass abstractClass) {
    	Set methodsSet = new HashSet();
    	// CtClass.getMethods returns all methods, including the ones declared in super classes
    	CtMethod[] methods = abstractClass.getMethods();
    	for(int i=0; i<methods.length; i++){
    	    if (Modifier.isPublic(methods[i].getModifiers()))
    	        methodsSet.add(methods[i]);
    	}
    	return methodsSet;
    }

    /**
     *
     * Checks if the child method is correctly overriding the parent method.
     * A valid override has identical argument types and order,
     * identical return type, and is not less accessible than the original method.
     * The overriding method must not throw any checked exceptions that were not
     * declared for the original method.
     *
     * @param CtMethod the parent method
     * @param CtMethod the child method
     * @return true if the child method is a valid override of the parent method
     */
    public static boolean isValidOverride(CtMethod parent, CtMethod child) {
        if (!parent.getName().equals(child.getName())) return false;

        try {
            if (!parent.getReturnType().equals(child.getReturnType())) return false;

            // compare method arguments
            CtClass[] parentArgs = parent.getParameterTypes();
            CtClass[] childArgs = child.getParameterTypes();
            if (parentArgs.length != childArgs.length) return false;
            for (int i = 0; i < parentArgs.length; i++) {
                if (!parentArgs[i].equals(childArgs[i])) return false;
            }

	        // this is not a precise check. Protected access for parent and Default for child will fail it.
	        if (!(Modifier.isPublic(parent.getModifiers()) && Modifier.isPublic(child.getModifiers()))) return false;
	        if (!Modifier.isPrivate(parent.getModifiers()) && Modifier.isPrivate(child.getModifiers())) return false;

	        // verify exceptions
	        CtClass[] parentEx = parent.getExceptionTypes();
	        CtClass[] childEx = child.getExceptionTypes();
            if (childEx.length > 0) {
		        for (int i = 0; i < parentEx.length; i++) {
		            boolean validEx = false;
		            for (int j = 0; j < childEx.length; j++) {
		                if ((childEx[j]).subtypeOf(parentEx[i])) validEx = true;
		            }
		            if (!validEx) return false;
		        }
            }
        } catch (NotFoundException e) {
            logger.warn("Failed: isValidOverride", e);
            return false;
        }

        return true;
    }

    /**
     * Create a unique key for store the CtMethod object in an Map object.
     * @param CtMethod to store in the Map
     * @return a String key unique for the method.
     */
    public static String getMethodKey(CtMethod method) {
    	return method.getName() + method.getSignature();
    }
}