/*
 * 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.deployment.profile.jpa;

import org.apache.log4j.Logger;
import org.hibernate.cfg.Environment;
import org.hibernate.ejb.HibernatePersistence;
import org.hibernate.internal.QueryImpl;
import org.jboss.as.jpa.config.PersistenceUnitMetadataImpl;
import org.mobicents.slee.container.component.profile.ProfileAttribute;
import org.mobicents.slee.container.component.profile.ProfileSpecificationComponent;
import org.mobicents.slee.container.profile.entity.ProfileEntity;
import org.mobicents.slee.container.profile.entity.ProfileEntityFactory;
import org.mobicents.slee.container.profile.entity.ProfileEntityFramework;
import org.mobicents.slee.container.transaction.SleeTransactionManager;
import org.mobicents.slee.container.transaction.TransactionContext;
import org.mobicents.slee.container.transaction.TransactionalAction;

import javax.naming.InitialContext;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import javax.persistence.ValidationMode;
import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.slee.InvalidArgumentException;
import javax.slee.SLEEException;
import javax.slee.profile.AttributeTypeMismatchException;
import javax.slee.profile.UnrecognizedAttributeException;
import javax.slee.profile.UnrecognizedQueryNameException;
import javax.slee.profile.query.QueryExpression;
import javax.transaction.Transaction;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.*;

/**
 *
 * The profile entity framework implementation that uses JPA to manage SLEE
 * profile data.
 *
 * @author  Alexandre Mendonca
 * @author  Bartosz Baranowski
 * @author martins
 */
public class JPAProfileEntityFramework implements ProfileEntityFramework {

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

	private static final String DEFAULT_PROFILE_NAME = "";

	/**
	 * the concrete jpa profile entity class of the framework
	 */
	private Class<?> profileEntityClass;

	/**
	 * runtime caching the profile entity class name, used many times in jpa
	 * queries
	 */
	private String profileEntityClassName;

	/**
	 * the concrete jpa profile entity factory class of the framework
	 */
	private Class<?> profileEntityFactoryClass;

	/**
	 * a map containing the concrete jpa profile entity array attr value class
	 * of the framework, per attribute name
	 */
	private Map<String, Class<?>> profileEntityArrayAttrValueClassMap;

	/**
	 * the profile spec component related with the framework
	 */
	private final ProfileSpecificationComponent component;

	/**
	 * the jpa entity manager factory of the framework
	 */
	private EntityManagerFactory entityManagerFactory;

	/**
	 * the shared instance of the profile entity factory of the framework
	 */
	private ProfileEntityFactory profileEntityFactory;

	private final SleeTransactionManager sleeTransactionManager;

	private final Configuration configuration;

	/**
	 *
	 * @param component
	 */
	public JPAProfileEntityFramework(ProfileSpecificationComponent component, Configuration configuration, SleeTransactionManager sleeTransactionManager) {
		this.component = component;
		this.component.setProfileEntityFramework(this);
		this.sleeTransactionManager = sleeTransactionManager;
		this.configuration = configuration;
	}

	// GETTERS / SETTERS

	/**
	 *
	 */
	public Class<?> getProfileEntityClass() {
		return profileEntityClass;
	}

	/**
	 *
	 * @param profileEntityClass
	 */
	public void setProfileEntityClass(Class<?> profileEntityClass) {
		this.profileEntityClass = profileEntityClass;
	}

	/**
	 *
	 * @return
	 */
	public String getProfileEntityClassName() {
		return profileEntityClassName;
	}

	/**
	 *
	 * @param profileEntityClassName
	 */
	public void setProfileEntityClassName(String profileEntityClassName) {
		this.profileEntityClassName = profileEntityClassName;
	}

	/**
	 *
	 * @return
	 */
	public Map<String, Class<?>> getProfileEntityArrayAttrValueClassMap() {
		return profileEntityArrayAttrValueClassMap;
	}

	/**
	 *
	 * @param profileEntityArrayAttrValueClassMap
	 */
	public void setProfileEntityArrayAttrValueClassMap(
			Map<String, Class<?>> profileEntityArrayAttrValueClassMap) {
		this.profileEntityArrayAttrValueClassMap = profileEntityArrayAttrValueClassMap;
	}

	/**
	 *
	 * @return
	 */
	public Class<?> getProfileEntityFactoryClass() {
		return profileEntityFactoryClass;
	}

	// ProfileEntityFramework IMPL

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.component.profile.ProfileEntityFramework
	 * #getProfileEntityFactory()
	 */
	public ProfileEntityFactory getProfileEntityFactory() {
		return profileEntityFactory;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.component.profile.ProfileEntityFramework
	 * #findAll(java.lang.String)
	 */
	public Collection<ProfileEntity> findAll(String profileTable) {
		return findProfilesByAttribute(profileTable, null, null);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.component.profile.ProfileEntityFramework
	 * #findProfilesByAttribute(java.lang.String,
	 * org.mobicents.slee.container.component.profile.ProfileAttribute,
	 * java.lang.Object)
	 */
	@SuppressWarnings("unchecked")
	public Collection<ProfileEntity> findProfilesByAttribute(
			String profileTable, ProfileAttribute profileAttribute,
			Object attributeValue) {

		if (logger.isTraceEnabled()) {
			logger.trace("findProfilesByAttribute( profileTable = "
					+ profileTable + " , profileAttribute = "
					+ profileAttribute + " , attributeValue = "
					+ attributeValue + " )");
		}

		EntityManager em = getEntityManager();
		Query query = null;
		if (profileAttribute == null) {
			query = em
					.createQuery(
							"SELECT x FROM "
									+ profileEntityClassName
									+ " x WHERE x.tableName = :tableName")
					.setParameter("tableName", profileTable);
		} else {
			if (profileAttribute.isArray()) {
				query = em
						.createQuery(
								"SELECT x FROM "
										+ profileEntityClassName
										+ " x , IN (x.c"
										+ profileAttribute.getName()
										+ ") y WHERE x.tableName = :tableName AND y.string = :attrValue")
						.setParameter("tableName", profileTable).setParameter(
								"attrValue", attributeValue.toString());
			} else {
				// TODO handle Address objects in this use case, they can't be
				// binary for search
				query = em
						.createQuery(
								"SELECT x FROM "
										+ profileEntityClassName
										+ " x WHERE x.tableName = :tableName AND x.c"
										+ profileAttribute.getName()
										+ " = :attrValue").setParameter(
								"tableName", profileTable).setParameter(
								"attrValue", attributeValue);
			}
		}

		Collection<ProfileEntity> result = query.getResultList();

		/*
		if (logger.isDebugEnabled()) {
			logger.debug("findProfilesByAttribute : query = "
					+ ((org.hibernate.ejb.QueryImpl) query).getHibernateQuery().getQueryString()
					+ " , result = " + result);
		}
		*/

		return result;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.component.profile.ProfileEntityFramework
	 * #findProfile(java.lang.String, java.lang.String)
	 */
	public ProfileEntity findProfile(String profileTable, String profileName) {

		EntityManager em = getEntityManager();
		Query query = em.createQuery(
				"FROM " + profileEntityClassName
						+ " WHERE tableName = ?1 AND profileName = ?2")
				.setParameter(1, profileTable).setParameter(2, profileName);

		List<?> resultList = query.getResultList();
		if (resultList.isEmpty()) {
			return null;
		} else {
			return (ProfileEntity) resultList.get(0);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.component.profile.ProfileEntityFramework
	 * #getProfilesByStaticQuery(java.lang.String, java.lang.String,
	 * java.lang.Object[])
	 */
	@SuppressWarnings("unchecked")
	public Collection<ProfileEntity> getProfilesByStaticQuery(
			String profileTable, String queryName, final Object[] parameters)
			throws NullPointerException, UnrecognizedQueryNameException,
			AttributeTypeMismatchException, InvalidArgumentException {

		// TODO check for exceptions

		final QueryWrapper wQuery = JPAQueryBuilder.getQuery(queryName);

		final EntityManager em = getEntityManager();

		if(System.getSecurityManager()==null)
		{
		Query staticQuery = em.createQuery(wQuery
				.getQuerySQL(profileEntityClassName));

		if (wQuery.getMaxMatches() > 0)
			staticQuery.setMaxResults((int) wQuery.getMaxMatches());

		for (int i = 0; i < parameters.length; i++) {
			try {
				staticQuery.setParameter(i + 1, parameters[i]);
			} catch (Exception ignore) {
				// We don't care, it's because there's no such parameter.
			}
		}

		return staticQuery.getResultList();
		}else
		{
			try {
				return AccessController.doPrivileged(new PrivilegedExceptionAction<Collection<ProfileEntity>>(){

					public Collection<ProfileEntity> run() throws Exception {
						Query staticQuery = em.createQuery(wQuery
								.getQuerySQL(profileEntityClassName));

						if (wQuery.getMaxMatches() > 0)
							staticQuery.setMaxResults((int) wQuery.getMaxMatches());

						for (int i = 0; i < parameters.length; i++) {
							try {
								staticQuery.setParameter(i + 1, parameters[i]);
							} catch (Exception ignore) {
								// We don't care, it's because there's no such parameter.
							}
						}

						return staticQuery.getResultList();
					}});
			} catch (PrivilegedActionException e) {
				Throwable t = e.getCause();
				if(t instanceof NullPointerException)
					throw (NullPointerException )t;
				if(t instanceof UnrecognizedQueryNameException)
					throw (UnrecognizedQueryNameException )t;
				if(t instanceof AttributeTypeMismatchException)
					throw (AttributeTypeMismatchException )t;
				if(t instanceof InvalidArgumentException)
					throw (InvalidArgumentException )t;

				//?
				throw new SLEEException("",t);

			}
		}

	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.component.profile.ProfileEntityFramework
	 * #getProfilesByDynamicQuery(java.lang.String,
	 * javax.slee.profile.query.QueryExpression)
	 */
	@SuppressWarnings("unchecked")
	public Collection<ProfileEntity> getProfilesByDynamicQuery(
			String profileTable, QueryExpression expr)
			throws UnrecognizedAttributeException,
			AttributeTypeMismatchException {

		// TODO check for exceptions

		QueryWrapper wQuery = JPAQueryBuilder.parseDynamicQuery(expr);

		EntityManager em = getEntityManager();
		Query dynamicQuery = em.createQuery(wQuery
				.getQuerySQL(profileEntityClassName));

		int i = 1;
		for (Object param : wQuery.getDynamicParameters()) {
			dynamicQuery.setParameter(i++, param);
		}

		if (wQuery.getMaxMatches() > 0)
			dynamicQuery.setMaxResults((int) wQuery.getMaxMatches());

		return dynamicQuery.getResultList();

	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.component.profile.ProfileEntityFramework
	 * #persistProfile
	 * (org.mobicents.slee.container.component.profile.ProfileEntity)
	 */
	public void persistProfile(ProfileEntity profileEntity) {
		EntityManager em = null;

		// if(checkUniqueFields(profileObject))
		// {
		em = getEntityManager();
		em.persist(profileEntity);
		/*
		 * } else { // FIXME: We need to throw this PVException! //throw new
		 * ProfileVerificationException
		 * ("Failed to persist profile due to uniqueness constraint."); throw
		 * new
		 * SLEEException("Failed to persist profile due to uniqueness constraint."
		 * ); }
		 */
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.component.profile.ProfileEntityFramework
	 * #retrieveProfile(java.lang.String, java.lang.String)
	 */
	public ProfileEntity retrieveProfile(String profileTable, String profileName) {

		if (logger.isTraceEnabled()) {
			logger.trace("retrieveProfile( profileTableName = " + profileTable
					+ " , profileName = " + profileName + " )");
		}

		if (profileName == null) {
			profileName = DEFAULT_PROFILE_NAME;
		}

		EntityManager em = getEntityManager();

		final Query q = em.createQuery(
				"FROM " + profileEntityClassName
						+ " WHERE tableName = ?1 AND profileName = ?2")
				.setParameter(1, profileTable).setParameter(2, profileName);

		if(System.getSecurityManager()==null)
		{
			List<?> resultList = q.getResultList();
			if (resultList.size() > 0) {
				if (logger.isDebugEnabled()) {
					logger.debug("ProfileEntity retrieved -> " + resultList.get(0));
				}
				return (ProfileEntity) resultList.get(0);
			} else {
				return null;
			}
		}else
		{
			return AccessController.doPrivileged(new PrivilegedAction<ProfileEntity>(){

				public ProfileEntity run() {
					List<?> resultList = q.getResultList();
					if (resultList.size() > 0) {
						if (logger.isDebugEnabled()) {
							logger.debug("ProfileEntity retrieved -> " + resultList.get(0));
						}
						return (ProfileEntity) resultList.get(0);
					} else {
						return null;
					}
				}});
		}

	}

    /*
     * (non-Javadoc)
     *
     * @see
     * org.mobicents.slee.container.component.profile.ProfileEntityFramework
     * #removeprofile
     * (org.mobicents.slee.container.component.profile.ProfileEntity)
     */
    public void removeprofile(ProfileEntity profileEntity) {
        EntityManager em = getEntityManager();
        em.remove(profileEntity);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * org.mobicents.slee.container.component.profile.ProfileEntityFramework
     * #removeprofile
     * (org.mobicents.slee.container.component.profile.ProfileEntity)
     */
    public void renameProfileTable(String oldProfileTableName, String newProfileTableName) {

      EntityManager em = getEntityManager();

      final Query q = em.createQuery(
              "UPDATE " + profileEntityClassName + " SET tableName = ?1 WHERE tableName = ?2")
              .setParameter(1, newProfileTableName).setParameter(2, oldProfileTableName);

      q.executeUpdate();
    }

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.component.profile.ProfileEntityFramework
	 * #install()
	 */
	public void install() {
		synchronized (this) {
			// generate profile entity & related classes
			new ConcreteProfileEntityGenerator(component,this)
					.generateClasses();

			// this one is just a runtime optimization for faster query building
			// now, later to use named queries
			profileEntityClassName = profileEntityClass.getName();

			profileEntityFactoryClass = new ConcreteProfileEntityFactoryGenerator(
					component, profileEntityClass,
					profileEntityArrayAttrValueClassMap).generateClass();
			try {
				profileEntityFactory = (ProfileEntityFactory) profileEntityFactoryClass
						.newInstance();
			} catch (Throwable e) {
				throw new SLEEException(e.getMessage(), e);
			}
			// 1. Generate CMP Interface Impl with JPA Annotations
			component.setProfileCmpConcreteClass(new ConcreteProfileGenerator(
					component).generateConcreteProfile());
			// 2. Create the corresponding JPA PU -- FIXME: Should be somewhere
			// else?
			createPersistenceUnit(component);

			new JPAQueryBuilder(component).parseStaticQueries();
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.component.profile.ProfileEntityFramework
	 * #uninstall()
	 */
	public void uninstall() {
		synchronized (this) {
			Transaction tx = null;
			try {
				tx = sleeTransactionManager.suspend();
			} catch (Throwable e) {
				throw new SLEEException(e.getMessage(), e);
			}
			if (entityManagerFactory != null) {
				entityManagerFactory.close();
			}
			try {
				sleeTransactionManager.resume(tx);
			} catch (Throwable e) {
				throw new SLEEException(e.getMessage(), e);
			}
			//component.setProfileEntityFramework(null);
		}
	}

    public void closeEntityManagerFactory() {
        if (entityManagerFactory != null) {
            entityManagerFactory.close();
        }
    }

	// AUX METHODS

	/**
	 *
	 * @param profileComponent
	 */
	@SuppressWarnings("unchecked")
	private void createPersistenceUnit(
			ProfileSpecificationComponent profileComponent) {
		try {
			HibernatePersistence hp = new HibernatePersistence();
			PersistenceUnitMetadataImpl pumd = new PersistenceUnitMetadataImpl();

			pumd.setTransactionType(PersistenceUnitTransactionType.JTA);
			pumd.setValidationMode(ValidationMode.NONE);

			// FIXME: Do we need this property here
			//pumd.setPersistenceProviderClassName("org.hibernate.ejb.HibernatePersistence");
			//pumd.setPersistenceProviderClassName("org.hibernate.jpa.HibernatePersistenceProvider");
			pumd.setJtaDataSourceName(configuration.getHibernateDatasource());
			pumd.setExcludeUnlistedClasses(false);

            pumd.setPersistenceUnitName("JSLEEProfiles" + profileComponent.getComponentID().hashCode());

            List<String> classes = new ArrayList<String>(1);
            classes.add(profileEntityClass.getName());
            for (Class<?> clazz : profileEntityArrayAttrValueClassMap.values()) {
                classes.add(clazz.getName());
            }
            pumd.setManagedClassNames(classes);

			Properties properties = new Properties();

			// Remote invocations via JNDI?
			// https://docs.jboss.org/author/display/AS71/Remote+EJB+invocations+via+JNDI+-+EJB+client+API+or+remote-naming+project
			//properties.setProperty("hibernate.jndi.java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
			//properties.setProperty(Environment.JNDI_PREFIX+"."+ Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");

			properties.setProperty(Environment.JNDI_CLASS, "org.jboss.as.naming.InitialContextFactory");
			//properties.setProperty("hibernate.jndi.java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
			//properties.setProperty(Environment.JNDI_PREFIX+"."+Context.INITIAL_CONTEXT_FACTORY, "org.jboss.as.naming.InitialContextFactory");

            properties.setProperty(Environment.HBM2DDL_AUTO, configuration.isPersistProfiles() ? "update" : "create-drop");
            properties.setProperty(Environment.DIALECT, configuration.getHibernateDialect());

			pumd.setJtaDataSourceName(configuration.getHibernateDatasource());
			properties.setProperty(Environment.DATASOURCE, pumd.getJtaDataSourceName());

			if(pumd.getJtaDataSourceName() != null) {
				pumd.setJtaDataSource((javax.sql.DataSource) new InitialContext().lookup(pumd.getJtaDataSourceName()));

			}
			else if (pumd.getTransactionType() == PersistenceUnitTransactionType.JTA) {
				throw new RuntimeException("Specification violation [EJB3 JPA 6.2.1.2] - "
						+ "You have not defined a jta-data-source for a JTA enabled persistence context named: "
						+ pumd.getPersistenceUnitName());
			}

			// FIXME: Do we need this property here (Environment.TRANSACTION_STRATEGY)
            //properties.setProperty(Environment.TRANSACTION_STRATEGY, "org.hibernate.transaction.CMTTransactionFactory");
			//properties.setProperty(Environment.TRANSACTION_STRATEGY, "org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory");
            //properties.setProperty(Environment.TRANSACTION_STRATEGY, "org.hibernate.transaction.JTATransactionFactory");

			// SEE: https://developer.jboss.org/thread/172307
			//properties.setProperty(Environment.JTA_PLATFORM, "org.hibernate.service.jta.platform.spi.JtaPlatform");
			//properties.setProperty(Environment.JTA_PLATFORM, "org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform");
			properties.setProperty(Environment.JTA_PLATFORM, "org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform");

			// FIXME: Do we need this property here (Environment.CONNECTION_PROVIDER)
			//properties.setProperty(Environment.CONNECTION_PROVIDER, "org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider");
            //properties.setProperty(Environment.CONNECTION_PROVIDER, "org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl");

			// TODO:
			//properties.setProperty(Environment.CACHE_PROVIDER, "org.hibernate.cache.HashtableCacheProvider");
			// FIXME: Should be Environment.JACC_CONTEXTID but it's
			// hibernate.jacc_context_id vs hibernate.jacc.ctx.id. Bug?
			properties.setProperty("hibernate.jacc.ctx.id", "persistence.xml");
			properties.setProperty(Environment.CACHE_REGION_PREFIX, "persistence.unit:unitName=#" + pumd.getPersistenceUnitName());
			properties.setProperty(Environment.SESSION_FACTORY_NAME, "persistence.unit:unitName=#" + pumd.getPersistenceUnitName());
			//properties.setProperty(Environment.SESSION_FACTORY_NAME, "");
			properties.setProperty(Environment.SESSION_FACTORY_NAME_IS_JNDI, "false");

			// Validation?
			properties.setProperty(Environment.CHECK_NULLABILITY, "true");

			properties.setProperty(Environment.USE_REFLECTION_OPTIMIZER, "false");
			properties.setProperty(Environment.BYTECODE_PROVIDER, "javassist");
			properties.setProperty(Environment.STATEMENT_BATCH_SIZE, "0");
			properties.setProperty(Environment.SHOW_SQL, "false");
			properties.setProperty(Environment.FORMAT_SQL, "false");

			ClassLoader newClassLoader = profileComponent.getClassLoader();
			Thread.currentThread().setContextClassLoader(newClassLoader);

			for (String className : pumd.getManagedClassNames()) {
				Thread.currentThread().getContextClassLoader().loadClass(
						className);
			}

            pumd.setProperties(properties);
            pumd.setClassLoader(Thread.currentThread().getContextClassLoader());
            pumd.setPersistenceUnitRootUrl(ClassLoader.getSystemResource("."));
            pumd.setJarFiles(new ArrayList<String>());

			Transaction tx = null;

			try {
				tx = sleeTransactionManager.suspend();
				this.entityManagerFactory = hp
						.createContainerEntityManagerFactory(pumd, null);
			} catch (Exception e) {
				logger.error("Failure creating Persistence Unit.", e);
			} catch (Throwable t) {
				logger.error("Failure creating Persistence Unit.", t);
			} finally {
				if (tx != null)
					sleeTransactionManager.resume(tx);
			}

		} catch (Exception e) {
			logger.error("Failure creating Persistence Unit.", e);
		}

	}

	/**
	 * the string key used to store entity manager of this profile spec in tx
	 * data
	 */
	private String txDataKey = null;

	/**
	 * Retrieves the entity manager for the current tx and the framework profile
	 * spec
	 *
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private EntityManager getEntityManager() {

		if (txDataKey == null) {
			txDataKey = new StringBuilder("jpapef.em.").append(component.getProfileSpecificationID()).toString();
		}

		final TransactionContext txContext = sleeTransactionManager.getTransactionContext();
		// look in tx
		Map transactionContextData = txContext.getData();

		EntityManager result = (EntityManager) transactionContextData
				.get(txDataKey);
		if (result == null) {
			// create using factory
			result = entityManagerFactory.createEntityManager();
			// store in tx context data
			transactionContextData.put(txDataKey, result);
			// add a tx action to close it before tx commits

			// FIXME: Do we need this after-rollback action here
			/*
			final EntityManager em = result;
			TransactionalAction action = new TransactionalAction() {
				public void execute() {
					try {
						em.close();
					} catch (Throwable e) {
						logger.error(e.getMessage(), e);
					}
				}
			};

			txContext.getAfterRollbackActions().add(action);
			*/
		}
		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.management.jmx;

import javax.management.ListenerNotFoundException;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanServer;
import javax.management.NotificationBroadcasterSupport;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.slee.InvalidArgumentException;
import javax.slee.InvalidStateException;
import javax.slee.management.ManagementException;
import javax.slee.management.SleeManagementMBean;
import javax.slee.management.SleeState;
import javax.slee.management.SleeStateChangeNotification;
import javax.slee.management.UnrecognizedSubsystemException;
import javax.slee.usage.UnrecognizedUsageParameterSetNameException;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.Version;
import org.mobicents.slee.container.management.SleeStateChangeRequest;

/**
 * Implementation of the Slee Management MBean for SLEE 1.1 specs
 *
 * @author M. Ranganathan
 * @author Ivelin Ivanov
 * @author Eduardo Martins
 *
 */
public class SleeManagementMBeanImpl extends MobicentsServiceMBeanSupport implements
		SleeManagementMBeanImplMBean {

	private ObjectName activityManagementMBean;

	private ObjectName sbbEntitiesMBean;

	private static Logger logger;

	private ObjectName deploymentMBean;

	private SleeContainer sleeContainer;

	private ObjectName profileProvisioningMBean;

	private ObjectName serviceManagementMBean;

	private ObjectName rmiServerInterfaceMBean;

	private ObjectName resourceManagementMBean;

	private NotificationBroadcasterSupport notificationBroadcaster = new NotificationBroadcasterSupport();

	/** counter for the number of slee state change notifications sent out */
	private long sleeStateChangeSequenceNumber = 1;

	/**
	 * The array of MBean notifications that this MBean broadcasts
	 *
	 */
	private static final MBeanNotificationInfo[] MBEAN_NOTIFICATIONS;

	private ObjectName objectName;

	static {
		MBEAN_NOTIFICATIONS = new MBeanNotificationInfo[] { new MBeanNotificationInfo(
				new String[] { SleeStateChangeNotification.class.getName() },
				SleeManagementMBean.SLEE_STATE_CHANGE_NOTIFICATION_TYPE,
				"SLEE 1.0 Spec, #14.6, Each time the operational state of the SLEE changes, "
						+ "the SleeManagementMBean object generates a SLEE state change notification.") };
		try {
			logger = Logger.getLogger(SleeManagementMBean.class);
		} catch (Exception ex) {
			logger.error("error initializing slee management mbean");
		}
	}

	/**
	 * Default constructor
	 *
	 * @throws Exception
	 */
	public SleeManagementMBeanImpl(SleeContainer sleeContainer) {
		super(sleeContainer);
		this.sleeContainer = sleeContainer;
	}

	/**
	 *
	 * @return the ObjectName of the SleeManagementMBean
	 */
	public ObjectName getObjectName() {
		return this.objectName;
	}

	/**
	 * @return the current state of the SLEE Container
	 *
	 * @see javax.slee.management.SleeManagementMBean#getState()
	 */
	public SleeState getState() throws ManagementException {
		return this.sleeContainer.getSleeState();
	}

	/**
	 * Start the SLEE container
	 *
	 * @see javax.slee.management.SleeManagementMBean#start()
	 */
	public void start() throws InvalidStateException, ManagementException {

		try {
			// request to change to STARTING
			final SleeStateChangeRequest startingRequest = new SleeStateChangeRequest() {

				@Override
				public void stateChanged(SleeState oldState) {
					if(logger.isDebugEnabled()) {
						logger.debug(generateMessageWithLogo("starting"));
					}
					notifyStateChange(oldState, getNewState());
				}

				@Override
				public void requestCompleted() {
					// inner request, executed when the parent completes, to change to RUNNING
					final SleeStateChangeRequest runningRequest = new SleeStateChangeRequest() {

						private SleeState oldState;

						@Override
						public void stateChanged(SleeState oldState) {
							logger.info(generateMessageWithLogo("started"));
							this.oldState = oldState;
						}

						@Override
						public void requestCompleted() {
							notifyStateChange(oldState, getNewState());
						}

						@Override
						public boolean isBlockingRequest() {
							return true;
						}

						@Override
						public SleeState getNewState() {
							return SleeState.RUNNING;
						}
					};
					try {
						sleeContainer.setSleeState(runningRequest);
					} catch (Throwable e) {
						logger.error(
								"Failed to set container in RUNNING state", e);
						try {
							stop(false);
						} catch (Throwable f) {
							logger.error(
									"Failed to set container in STOPPED state, after failure to set in RUNNING state",
									e);
						}
					}
				}

				@Override
				public boolean isBlockingRequest() {
					// should be false, but the tck doesn't like it
					return true;
				}

				@Override
				public SleeState getNewState() {
					return SleeState.STARTING;
				}
			};
			sleeContainer.setSleeState(startingRequest);

		} catch (InvalidStateException ex) {
			throw ex;
		} catch (Exception ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}
	}

	private void notifyStateChange(SleeState oldState, SleeState newState) {
		if (logger.isTraceEnabled()) {
			logger.trace("notifyStateChange( old = " + oldState + " , new = "
				+ newState + " )");
		}
		notificationBroadcaster
				.sendNotification(new SleeStateChangeNotification(this,
						newState, oldState, sleeStateChangeSequenceNumber++));
	}

	/**
	 * Gracefully stop the SLEE. Should do it in a non-blocking manner.
	 *
	 * @see javax.slee.management.SleeManagementMBean#stop()
	 */
	public void stop() throws InvalidStateException, ManagementException {
		stop(false);
	}

	private void stop(final boolean block) throws InvalidStateException,
			ManagementException {
		try {

			// request to change to STOPPING
			final SleeStateChangeRequest stoppingRequest = new SleeStateChangeRequest() {

				@Override
				public void stateChanged(SleeState oldState) {
					logger.info(generateMessageWithLogo("stopping"));
					notifyStateChange(oldState, getNewState());
				}

				@Override
				public void requestCompleted() {
					// inner request, executed when the parent completes, to change to STOPPED
					final SleeStateChangeRequest stopRequest = new SleeStateChangeRequest() {

						private SleeState oldState;

						@Override
						public void stateChanged(SleeState oldState) {
							logger.info(generateMessageWithLogo("stopped"));
							this.oldState = oldState;
						}

						@Override
						public void requestCompleted() {
							notifyStateChange(oldState, getNewState());
						}

						@Override
						public boolean isBlockingRequest() {
							return true;
						}

						@Override
						public SleeState getNewState() {
							return SleeState.STOPPED;
						}
					};
					try {
						sleeContainer.setSleeState(stopRequest);
					} catch (Throwable e) {
						logger.error(
								"Failed to set container in STOPPED state", e);
					}
				}

				@Override
				public boolean isBlockingRequest() {
					return block;
				}

				@Override
				public SleeState getNewState() {
					return SleeState.STOPPING;
				}
			};
			sleeContainer.setSleeState(stoppingRequest);

		} catch (InvalidStateException ex) {
			throw ex;
		} catch (Exception ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}
	}

	/**
	 * Shutdown the SLEE processes. The spec requires that System.exit() be
	 * called before this methods returns. We are not convinced this is
	 * necessary yet. A trivial implementation would be to make a call to the
	 * JBoss server shutdown()
	 *
	 * @see javax.slee.management.SleeManagementMBean#shutdown()
	 */
	public void shutdown() throws InvalidStateException, ManagementException {
		logger.info(generateMessageWithLogo("shutdown"));
		try {
			sleeContainer.shutdownSlee();
		} catch (InvalidStateException ex) {
			throw ex;
		} catch (Exception ex) {
			throw new ManagementException(ex.getMessage());
		}
	}

	/**
	 * return the ObjectName of the DeploymentMBean
	 *
	 * @see javax.slee.management.SleeManagementMBean#getDeploymentMBean()
	 */
	public ObjectName getDeploymentMBean() {
		return this.deploymentMBean;
	}

	/**
	 * set the ObjectName of the DeploymentMBean
	 *
	 * @see javax.slee.management.SleeManagementMBean#getDeploymentMBean()
	 */
	public void setDeploymentMBean(ObjectName newDM) {
		this.deploymentMBean = newDM;
	}

	/**
	 * return the ObjectName of the ServiceManagementMBean
	 *
	 * @see javax.slee.management.SleeManagementMBean#getServiceManagementMBean()
	 */
	public ObjectName getServiceManagementMBean() {
		return this.serviceManagementMBean;
	}

	/**
	 * set the ObjectName of the ServiceManagementMBean
	 *
	 * @see javax.slee.management.SleeManagementMBean#setServiceManagementMBean()
	 */
	public void setServiceManagementMBean(ObjectName newSMM) {
		this.serviceManagementMBean = newSMM;
	}

	/*
	 * return the ObjectName of the ProfileProvisioningMBean
	 *
	 * @see
	 * javax.slee.management.SleeManagementMBean#getProfileProvisioningMBean()
	 */
	public ObjectName getProfileProvisioningMBean() {
		return this.profileProvisioningMBean;
	}

	/**
	 * set the ObjectName of the ProfileProvisioningMBean
	 *
	 * @see javax.slee.management.SleeManagementMBean#setProfileProvisioningMBean()
	 */
	public void setProfileProvisioningMBean(ObjectName newPPM) {
		this.profileProvisioningMBean = newPPM;
	}

	/*
	 * return the ObjectName of the TraceMBean
	 *
	 * @see javax.slee.management.SleeManagementMBean#getTraceMBean()
	 */
	public ObjectName getTraceMBean() {
		return sleeContainer.getTraceManagement().getTraceMBeanObjectName();
	}

	// /**
	// * @param resourceAdaptorMBean The resourceAdaptorMBean to set.
	// * @deprecated Use setResourceManagementMBean
	// */
	// public void setResourceAdaptorMBean(ObjectName resourceAdaptorMBean) {
	// this.resourceAdaptorMBean = resourceAdaptorMBean;
	// }

	public void setResourceManagementMBean(ObjectName resourceManagementMBean) {
		this.resourceManagementMBean = resourceManagementMBean;
	}

	// /**
	// * @return Returns the resourceAdaptorMBean.
	// * @deprecated Use getResourceManagementMBean
	// */
	// public ObjectName getResourceAdaptorMBean() {
	// return resourceAdaptorMBean;
	// }

	public ObjectName getResourceManagementMBean() {
		return resourceManagementMBean;
	}

	/**
	 * return the ObjectName of the AlarmMBean
	 *
	 * @see javax.slee.management.SleeManagementMBean#getAlarmMBean()
	 */
	public ObjectName getAlarmMBean() {
		return sleeContainer.getAlarmManagement().getAlarmMBeanObjectName();
	}

	public ObjectName preRegister(MBeanServer mbs, ObjectName oname)
			throws Exception {
		this.objectName = new ObjectName(SleeManagementMBean.OBJECT_NAME);
		startSlee();
		return super.preRegister(mbs, objectName);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.management.MBeanRegistration#postRegister(java.lang.Boolean)
	 */
	public void postRegister(Boolean registrationDone) {
		super.postRegister(registrationDone);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.management.MBeanRegistration#preDeregister()
	 */
	public void preDeregister() throws Exception {
		super.preDeregister();
		stopSlee();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.management.MBeanRegistration#postDeregister()
	 */
	public void postDeregister() {
		super.postDeregister();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.management.NotificationBroadcaster#addNotificationListener(javax
	 * .management.NotificationListener, javax.management.NotificationFilter,
	 * java.lang.Object)
	 */
	public void addNotificationListener(NotificationListener listener,
			NotificationFilter filter, Object handback)
			throws IllegalArgumentException {
		notificationBroadcaster.addNotificationListener(listener, filter,
				handback);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.management.NotificationBroadcaster#removeNotificationListener(javax
	 * .management.NotificationListener)
	 */
	public void removeNotificationListener(NotificationListener listener)
			throws ListenerNotFoundException {
		notificationBroadcaster.removeNotificationListener(listener);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.management.NotificationBroadcaster#getNotificationInfo()
	 */
	public MBeanNotificationInfo[] getNotificationInfo() {
		return MBEAN_NOTIFICATIONS;
	}

	public ObjectName getActivityManagementMBean() {
		return activityManagementMBean;
	}

	public void setActivityManagementMBean(ObjectName activityManagementMBean) {
		this.activityManagementMBean = activityManagementMBean;
	}

	public ObjectName getSbbEntitiesMBean() {
		return sbbEntitiesMBean;
	}

	public void setSbbEntitiesMBean(ObjectName sbbEntitiesMBean) {
		this.sbbEntitiesMBean = sbbEntitiesMBean;
	}

	public ObjectName getRmiServerInterfaceMBean() {
		return rmiServerInterfaceMBean;
	}

	public void setRmiServerInterfaceMBean(ObjectName rmiServerInterfaceMBean) {
		this.rmiServerInterfaceMBean = rmiServerInterfaceMBean;
	}

	// ah ah

	private static final String rLogo = " -+-^-v-^-+-^-v-^-+- ";
	private static final String lLogo = rLogo;

	private String generateMessageWithLogo(String message) {
		return lLogo + getSleeName() + " " + getSleeVersion() + " \""
				+ getSleeCodeName() + "\" " + message + rLogo;
	}

	public String getSleeCodeName() {
		return Version.instance.getProperty("codename");
	}

	public String getSleeName() {
		String name = Version.instance.getProperty("name");
		if (name != null) {
			return name;
		} else {
			return "Mobicents JAIN SLEE";
		}
	}

	public String getSleeVendor() {
		String vendor = Version.instance.getProperty("vendor");
		if (vendor != null) {
			return vendor;
		} else {
			return "JBoss, a division of Red Hat";
		}
	}

	public String getSleeVersion() {
		String version = Version.instance.getProperty("version");
		if (version != null) {
			return version;
		} else {
			return "2.0";
		}
	}

	// no subsystems defined

	private static final String DUMMY_SUBSYSTEM = "FooSubsystem";

	public String[] getSubsystems() throws ManagementException {
		return new String[] { DUMMY_SUBSYSTEM };
	}

	public ObjectName getUsageMBean(String arg0) throws NullPointerException,
			UnrecognizedSubsystemException, InvalidArgumentException,
			ManagementException {
		if (arg0 == null) {
			throw new NullPointerException();
		}
		if (arg0.equals(DUMMY_SUBSYSTEM)) {
			throw new InvalidArgumentException();
		} else {
			throw new UnrecognizedSubsystemException();
		}
	}

	public ObjectName getUsageMBean(String arg0, String arg1)
			throws NullPointerException, UnrecognizedSubsystemException,
			InvalidArgumentException,
			UnrecognizedUsageParameterSetNameException, ManagementException {
		if (arg0 == null) {
			throw new NullPointerException();
		}
		if (arg0.equals(DUMMY_SUBSYSTEM)) {
			throw new InvalidArgumentException();
		} else {
			throw new UnrecognizedSubsystemException();
		}
	}

	public ObjectName getUsageNotificationManagerMBean(String arg0)
			throws NullPointerException, UnrecognizedSubsystemException,
			InvalidArgumentException, ManagementException {
		if (arg0 == null) {
			throw new NullPointerException();
		}
		if (arg0.equals(DUMMY_SUBSYSTEM)) {
			throw new InvalidArgumentException();
		} else {
			throw new UnrecognizedSubsystemException();
		}
	}

	public String[] getUsageParameterSets(String arg0)
			throws NullPointerException, UnrecognizedSubsystemException,
			InvalidArgumentException, ManagementException {
		if (arg0 == null) {
			throw new NullPointerException();
		}
		if (arg0.equals(DUMMY_SUBSYSTEM)) {
			throw new InvalidArgumentException();
		} else {
			throw new UnrecognizedSubsystemException();
		}
	}

	public boolean hasUsage(String arg0) throws NullPointerException,
			UnrecognizedSubsystemException, ManagementException {

		if (arg0 == null) {
			throw new NullPointerException();
		}
		if (arg0.equals(DUMMY_SUBSYSTEM)) {
			return false;
		} else {
			throw new UnrecognizedSubsystemException();
		}
	}

	public void startSlee() {
		logger.info(generateMessageWithLogo("init"));
		try {
			sleeContainer.initSlee();
			start();
		} catch (Exception e) {
			logger.error("Failure in SLEE startup", e);
		}
	}

	public void stopSlee() {
		try {
			stop(true);
			shutdown();
		} catch (Exception e) {
			logger.error("Failed in SLEE stop", e);
		}
	}

}


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

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.mobicents.slee.container.component.ComponentRepository;
import org.mobicents.slee.container.component.ServiceComponentImpl;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.ServiceDescriptorImpl;
import org.mobicents.slee.container.component.service.ServiceComponent;

public class ServiceValidator implements Validator {

	private ServiceComponentImpl component = null;
	private ComponentRepository repository = null;
	private final static transient Logger logger = Logger.getLogger(ServiceValidator.class);

	public void setComponentRepository(ComponentRepository repository) {
		this.repository = repository;

	}

	public ServiceComponentImpl getComponent() {
		return component;
	}

	public void setComponent(ServiceComponentImpl component) {
		this.component = component;
	}

	public boolean validate() {
		boolean passed = true;

		if(!validateDescriptor())
		{
			passed = false;
			return passed;
		}

		if(validateCompatibilityReferenceConstraints())
		{
			passed = false;

		}

		return passed;
	}

	boolean validateDescriptor() {
		boolean passed = true;
		String errorBuffer = new String("");

		try {
			ServiceDescriptorImpl descritpor=this.component.getDescriptor();
			//Nothign so far here.
		} finally {
			if (!passed) {
				if (logger.isEnabledFor(Level.ERROR)) {
					logger.error(errorBuffer);
				}
			}
		}
		return passed;
	}

	/**
	 * See section 1.3 of jslee 1.1 specs
	 *
	 * @return
	 */
	boolean validateCompatibilityReferenceConstraints() {

		boolean passed = true;
		String errorBuffer = new String("");

		try {
			if (!this.component.isSlee11()) {
				// A 1.0 SBB must not reference or use a 1.1 Profile
				// Specification. This must be enforced by a 1.1
				// JAIN SLEE.

				ServiceComponent specComponent = this.repository.getComponentByID(this.component.getServiceID());
				if (specComponent == null) {
					// should not happen
					passed = false;
					errorBuffer = appendToBuffer("Referenced " + this.component.getServiceID()
							+ " was not found in component repository, this should not happen since dependencies were already verified", "1.3", errorBuffer);

				} else {
					if (specComponent.isSlee11()) {
						passed = false;
						errorBuffer = appendToBuffer("Service is following 1.0 JSLEE contract, it must not reference 1.1 Sbb as root: " + this.component.getServiceID(), "1.3", errorBuffer);
					}
				}

			}
		} finally {
			if (!passed) {
				if (logger.isEnabledFor(Level.ERROR)) {
					logger.error(errorBuffer);
				}
			}

		}

		return passed;
	}

	protected String appendToBuffer(String message, String section, String buffer) {
		buffer += (this.component.getDescriptor().getServiceID() + " : violates section " + section + " of jSLEE 1.1 specification : " + message + "\n");
		return buffer;
	}
}


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

import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;

import java.io.PrintWriter;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.slee.management.ResourceAdaptorEntityState;
import javax.slee.resource.ConfigProperties;
import javax.slee.resource.ResourceAdaptorID;

import org.jboss.console.twiddle.command.CommandContext;
import org.jboss.console.twiddle.command.CommandException;
import org.jboss.logging.Logger;
import org.mobicents.tools.twiddle.AbstractSleeCommand;
import org.mobicents.tools.twiddle.Utils;
import org.mobicents.tools.twiddle.op.AbstractOperation;

/**
 * @author baranowb
 *
 */
public class ResourceCommand extends AbstractSleeCommand {

	public ResourceCommand() {
		super("resource", "This command performs operations on JSLEE ResourceManagementMBean." );
	}

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

		out.println(desc);
		out.println();
		out.println("usage: " + name + " <-operation[[arg] | [--option[=arg]]*]>");
		out.println();
		out.println("operation:");
		out.println("    -b, --bind                     Creates bind between RA entity and link name, supports following options(mandatory):");
		out.println("          --link-name              Specifies link name to be used, requires argument. ");
		out.println("          --entity-name            Specifies RA entity name to be used, requires argument. ");
		out.println("    -u, --unbind                   Unbinds a link name from a RA entity. Requires link name as argument.");
		out.println("    -a, --activate                 Activate a RA entity. Requires entity name as argument.");
		out.println("    -d, --deactivate               Deactivate a RA entity. Requires entity name as argument.");
		out.println("    -c, --create                   Creates a RA entity. Options specify mandatory arguments:");
		out.println("          --entity-name            Specifies RA entity name to be used, requires entity name as argument. ");
		out.println("          --ra-id                  Specifies ResourceAdaptorID to be used, requires argument. ");
		out.println("          --config                 Specifies ConfigurationProperties to be used, requires argument. ");
		out.println("    -r, --remove                   Removes a RA entity. Requires RA entity name as argument.");
		out.println("    -p, --update-config            Update RA entity configuration. Options specify mandatory arguments:");
		out.println("          --entity-name            Specifies RA entity name to be used, requires argument. ");
		out.println("          --config                 Specifies ConfigurationProperties to be used as new set, requires argument. ");
		out.println("    -l, --list                     Lists result. Result content depends on passed options. One option is required, supported:");
		out.println("          --ra-entities            Marks list operation to list entity names. Without argument it will list all entities. If ");
		out.println("                                   ResourceAdaptorID is passed as argument it will list entity names corresponding to argument. ");
		out.println("          --ra-entities-in-state   Marks list operation to list entity names of RAs in given state. Requires argument(ResourceAdaptorEntityState). ");
		out.println("          --ra-entities-by-link    Marks list operation to list entity name(s) of RAs bound to given link name(s). Requires argument which is a single link name or array. ");
		out.println("          --links                  Marks list operation to list link names. Without argument it will list all links. If ");
		out.println("                                   RA entity name is passed as argument it will list only corresponding link names. ");
		out.println("          --sbbs                   Marks list operation to list SbbIDs bound to passed link name. Requires link name as argument ");
		out.println("    -g, --get                      Fetches information from container based on passed option. One option is required, supported options:");
		out.println("          --ra-id                  Retrieves ResourceAdaptorID. Requires entity name as argument, RA ID is fetched for this name. ");
		out.println("          --state                  Retrieves state of RA. Requires entity name as argument. ");
		out.println("          --config-by-id           Retrieves ConfigurationProperties for given ResourceAdaptorID. Requires ResourceAdaptorID as argument.");
		out.println("          --config-by-name         Retrieves ConfigurationProperties for given RA entity name. Requires entity name as argument.");
		//out.println("          --usage-mbean            Retrieves ObjectName of ResourceAdaptorUsageMBean. Requires entity name as argument.");
//
//
		out.println("arg:");
		out.println("");
		out.println("NOTE: Config property has general form of: (name:java.type=value) and array has different form, than in components: [(cnf.prop),(cnf.prop)]");
		out.println("     Configuration property array: [(remotePort:java.lang.Integer=40001),(localPort:java.lang.Integer=40000),(localHost:java.lang.String=127.0.0.1),(remoteHost:java.lang.String=127.0.0.1)]");
		out.println("     ResourceAdaptorEntityState: [INACTIVE|STOPPING|ACTIVE]");

		out.println("");
		out.println("Examples: ");
		out.println("");
		out.println("     1. Create RA Entity:");
		out.println("" + name + " -c --entity-name=SipRA --ra-id=ResourceAdaptorID[name=JainSipResourceAdaptor,vendor=net.java.slee.sip,version=1.2] --config=[(javax.sip.TRANSPORT:java.lang.String=UDP),(javax.sip.IP_ADDRESS:java.lang.String=),(javax.sip.PORT:java.lang.Integer=5060)]");
		out.println("");
		out.println("     2. Bind RA Entity to Link:");
		out.println("" + name + " -b --link-name=SipRALink --entity-name=SipRA");
		out.println("");
		out.println("     3. Get state of RA Entity:");
		out.println("" + name + " -g --state=SipRA");
		out.println("");
		out.println("     4 List all RA Entities in container:");
		out.println("" + name + " -l --ra-entities");
		out.println("");
		out.println("     5. List all RA Entities created from specific ResourceAdaptorID:");
		out.println("" + name + " -l --ra-entities=ResourceAdaptorID[name=JainSipResourceAdaptor,vendor=net.java.slee.sip,version=1.2]");
		out.flush();

	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.tools.twiddle.AbstractSleeCommand#processArguments(java.lang.String[])
	 */
	@Override
	protected void processArguments(String[] args) throws CommandException {
		String sopts = ":bu:a:d:cr:plg";

		LongOpt[] lopts = {
				new LongOpt("bind", LongOpt.NO_ARGUMENT, null, 'b'),
					//common options
					new LongOpt("link-name", LongOpt.REQUIRED_ARGUMENT, null, BindOperation.ra_link_name),
					new LongOpt("entity-name", LongOpt.REQUIRED_ARGUMENT, null, BindOperation.ra_entity_name),
				new LongOpt("unbind", LongOpt.REQUIRED_ARGUMENT, null, 'u'),
				new LongOpt("activate", LongOpt.REQUIRED_ARGUMENT, null, 'a'),
				new LongOpt("deactivate", LongOpt.REQUIRED_ARGUMENT, null, 'd'),
				new LongOpt("create", LongOpt.NO_ARGUMENT, null, 'c'),
					//entity-name is covered
					new LongOpt("ra-id", LongOpt.REQUIRED_ARGUMENT, null, CreateOperation.ra_id),
					new LongOpt("config", LongOpt.REQUIRED_ARGUMENT, null, CreateOperation.config),
				new LongOpt("remove", LongOpt.REQUIRED_ARGUMENT, null, 'r'),
				new LongOpt("update-config", LongOpt.NO_ARGUMENT, null, 'p'),
					//entity-name and config are already covered
				new LongOpt("list", LongOpt.NO_ARGUMENT, null, 'l'),
					new LongOpt("ra-entities", LongOpt.OPTIONAL_ARGUMENT, null, ListOperation.ra_entities),
					new LongOpt("ra-entities-in-state", LongOpt.REQUIRED_ARGUMENT, null, ListOperation.ra_entities_in_state),
					new LongOpt("ra-entities-by-link", LongOpt.REQUIRED_ARGUMENT, null, ListOperation.ra_entities_by_link),
					new LongOpt("links", LongOpt.OPTIONAL_ARGUMENT, null, ListOperation.links),
					new LongOpt("sbbs", LongOpt.REQUIRED_ARGUMENT, null, ListOperation.sbbs),
				new LongOpt("get", LongOpt.NO_ARGUMENT, null, 'g'),
					//ra-id is covered
					new LongOpt("state", LongOpt.REQUIRED_ARGUMENT, null, GetOperation.state),
					new LongOpt("config-by-id", LongOpt.REQUIRED_ARGUMENT, null, GetOperation.config_by_id),
					new LongOpt("config-by-name", LongOpt.REQUIRED_ARGUMENT, null, GetOperation.config_by_name),
					//new LongOpt("usage-mbean", LongOpt.REQUIRED_ARGUMENT, null, GetOperation.usage_mbean),
				 };

		Getopt getopt = new Getopt(null, args, sopts, lopts);
		// getopt.setOpterr(false);

		int code;
		while ((code = getopt.getopt()) != -1) {
			switch (code) {
			case ':':
				throw new CommandException("Option requires an argument: " + args[getopt.getOptind() - 1]);

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

			case 'b':

				super.operation = new BindOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);
				break;

			case 'u':

				super.operation = new UnBindOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);
				break;

			case 'a':

				super.operation = new ActivateOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);
				break;

			case 'd':

				super.operation = new DeactivateOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);
				break;

			case 'c':

				super.operation = new CreateOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);
				break;
			case 'r':

				super.operation = new RemoveOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);
				break;

			case 'p':

				super.operation = new UpdateConfigOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);
				break;

			case 'l':

				super.operation = new ListOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);
				break;

			case 'g':

				super.operation = new GetOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);
				break;

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

			}
		}

	}
	/* (non-Javadoc)
	 * @see org.mobicents.slee.tools.twiddle.AbstractSleeCommand#getBeanOName()
	 */
	@Override
	public ObjectName getBeanOName() throws MalformedObjectNameException, NullPointerException {
		return new ObjectName(Utils.SLEE_RESOURCE_MANAGEMENT);
	}

	private class BindOperation extends AbstractOperation
	{
		public static final char ra_link_name = 'v';
		public static final char ra_entity_name = 'm';

		private static final String OPERATION_bindLinkName = "bindLinkName";

		private String linkName;
		private String entityName;

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

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

			int code;

			while ((code = opts.getopt()) != -1) {
				switch (code) {
				case ':':
					throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

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

				case ra_link_name:

					this.linkName = opts.getOptarg();
					break;
				case ra_entity_name:

					this.entityName = opts.getOptarg();
					break;

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

				}

			}
			if (this.linkName == null || this.entityName == null) {
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", expects both \"--link-name\" and \"--entity-name\" to be present");
			}

			super.addArg(this.entityName, String.class, false);
			super.addArg(this.linkName, String.class, false);
		}

	}

	private class UnBindOperation extends AbstractOperation
	{

		private static final String OPERATION_unbindLinkName = "unbindLinkName";
		public UnBindOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			super.operationName = OPERATION_unbindLinkName;
		}

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

			super.addArg(opts.getOptarg(), String.class, false);
		}

	}
	private class ActivateOperation extends AbstractOperation
	{

		private static final String OPERATION_activateResourceAdaptorEntity = "activateResourceAdaptorEntity";
		public ActivateOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			super.operationName = OPERATION_activateResourceAdaptorEntity;
		}

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

			super.addArg(opts.getOptarg(), String.class, false);
		}

	}
	private class DeactivateOperation extends AbstractOperation
	{

		private static final String OPERATION_deactivateResourceAdaptorEntity = "deactivateResourceAdaptorEntity";

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

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

			super.addArg(opts.getOptarg(), String.class, false);
		}

	}
	private class RemoveOperation extends AbstractOperation
	{
		private static final String OPERATION_removeResourceAdaptorEntity = "removeResourceAdaptorEntity";

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

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

			super.addArg(opts.getOptarg(), String.class, false);
		}

	}
	private class CreateOperation extends AbstractOperation
	{

		//TODO: make config param optional
		private static final char config='i';
		private static final char ra_id='j';

		private static final String OPERATION_createResourceAdaptorEntity = "createResourceAdaptorEntity";

		private String stringEntityName;
		private String stringConfig;
		private String stringRaID;
		public CreateOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			super.operationName = OPERATION_createResourceAdaptorEntity;
		}

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

			int code;

			while ((code = opts.getopt()) != -1) {
				switch (code) {
				case ':':
					throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

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

				case BindOperation.ra_entity_name:

					this.stringEntityName = opts.getOptarg();
					break;
				case config:
					this.stringConfig = opts.getOptarg();

					break;
				case ra_id:
					this.stringRaID = opts.getOptarg();

					break;

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

				}

			}
			if (this.stringEntityName == null || this.stringConfig == null || this.stringRaID == null) {
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", expects all \"--config\" ,\"--entity-name\" and \"--ra-id\" to be present");
			}
			try {
				super.addArg(this.stringRaID, ResourceAdaptorID.class, true);
			} catch (Exception e) {
				throw new CommandException("Failed to parse ResourceAdaptorID: \"" + stringRaID + "\"", e);
			}

			super.addArg(this.stringEntityName, String.class, false);

			try {
				super.addArg(this.stringConfig, ConfigProperties.class, true);
			} catch (Exception e) {
				throw new CommandException("Failed to parse ConfigProperties: \"" + stringConfig + "\"", e);
			}
		}

	}

	private class ListOperation extends AbstractOperation
	{

		private static final char sbbs='s';
		private static final char links='k';
		private static final char ra_entities_by_link='e';
		private static final char ra_entities_in_state='x';
		private static final char ra_entities='q';

		private static final String OPERATION_getBoundSbbs = "getBoundSbbs";
		private static final String OPERATION_getLinkNames = "getLinkNames";
		private static final String OPERATION_getResourceAdaptorEntities = "getResourceAdaptorEntities";
		private static final String OPERATION_getResourceAdaptorEntity = "getResourceAdaptorEntity";

		public ListOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			//operation is set based on arg.
		}

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

			while ((code = opts.getopt()) != -1) {
				if (super.operationName != null) {
					throw new CommandException("Command: \"" + sleeCommand.getName()
							+ "\", expects only one option!");
				}
				switch (code) {
				case ':':
					throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

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

				case sbbs:
					super.operationName = OPERATION_getBoundSbbs;
					String optArg = opts.getOptarg(); // arg is mandatory
					super.addArg(optArg, String.class, false);
					break;
				case links:
					super.operationName = OPERATION_getLinkNames;
					optArg = opts.getOptarg();
					if(optArg!=null)
					{
						//it must be link name
						super.addArg(optArg, String.class, false);
					}
					break;
				case ra_entities:
					super.operationName = OPERATION_getResourceAdaptorEntities;
					 optArg = opts.getOptarg();
					if(optArg!=null)
					{
						//it must be RA ID
						try {
							super.addArg(optArg, ResourceAdaptorID.class, true);
						} catch (Exception e) {
							throw new CommandException("Failed to parse ResourceAdaptorID: \"" + optArg + "\"", e);
						}
					}
					break;

				case ra_entities_by_link:

					 optArg = opts.getOptarg();
					 if(optArg.contains(";"))
					 {
						 super.operationName = OPERATION_getResourceAdaptorEntities;
						 super.addArg(optArg.split(";"), String[].class, false);
					 }else
					 {
						 super.operationName = OPERATION_getResourceAdaptorEntity;
						 super.addArg(optArg, String.class, false);
					 }
					break;
				case ra_entities_in_state:
					super.operationName = OPERATION_getResourceAdaptorEntities;
					optArg = opts.getOptarg();
					try {
						super.addArg(optArg, ResourceAdaptorEntityState.class, true);
					} catch (Exception e) {
						throw new CommandException("Failed to parse ResourceAdaptorEntityState: \"" + optArg + "\"", e);
					}
					break;
				default:
					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
							+ "\", found unexpected opt: " + args[opts.getOptind() - 1]);

				}

			}
			if (super.operationName == null) {
				throw new CommandException("Command: \"" + sleeCommand.getName()
						+ "\", expects one option!");
			}
		}

	}
	private class GetOperation extends AbstractOperation
	{
		private static final char usage_mbean='z';
		private static final char config_by_name='n';
		private static final char config_by_id='m';
		private static final char state='o';

		private static final String OPERATION_getResourceAdaptor = "getResourceAdaptor";
		private static final String OPERATION_getState = "getState";
		private static final String OPERATION_getConfigurationProperties = "getConfigurationProperties";
		private static final String OPERATION_getResourceUsageMBean = "getResourceUsageMBean";

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

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

			while ((code = opts.getopt()) != -1) {
				if (super.operationName != null) {
					throw new CommandException("Command: \"" + sleeCommand.getName()
							+ "\", expects only one option!");
				}
				switch (code) {
				case ':':
					throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

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

				case CreateOperation.ra_id:
					super.operationName = OPERATION_getResourceAdaptor;
					String optArg = opts.getOptarg();
					//it must be entity name
					super.addArg(optArg, String.class, false);
					break;
				case state:
					super.operationName = OPERATION_getState;
					optArg = opts.getOptarg();
					//it must be entity name
					super.addArg(optArg, String.class, false);
					break;

					//FIXME: decided to leave conf options listing as default, so its easier to copy/paste?
				case config_by_id:
					super.operationName = OPERATION_getConfigurationProperties;
					optArg = opts.getOptarg();
					//it must be RA ID
					try {
						super.addArg(optArg, ResourceAdaptorID.class, true);
					} catch (Exception e) {
						throw new CommandException("Failed to parse ResourceAdaptorID: \"" + optArg + "\"", e);
					}
					break;
				case config_by_name:
					super.operationName = OPERATION_getConfigurationProperties;
					optArg = opts.getOptarg();
					//it must be RA entity name

					super.addArg(optArg, String.class, false);
					break;
				case usage_mbean:
					super.operationName = OPERATION_getResourceUsageMBean;
					optArg = opts.getOptarg();
					//it must be RA entity name

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

				}

			}

			if (super.operationName == null) {
				throw new CommandException("Command: \"" + sleeCommand.getName()
						+ "\", expects one option!");
			}
		}

	}

	private class UpdateConfigOperation extends AbstractOperation
	{
		private static final String OPERATION_updateConfigurationProperties = "updateConfigurationProperties";
		private String stringEntityName;
		private String stringConfig;

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

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

			int code;

			while ((code = opts.getopt()) != -1) {
				switch (code) {
				case ':':
					throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

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

				case BindOperation.ra_entity_name:

					this.stringEntityName = opts.getOptarg();
					break;
				case CreateOperation.config:
					this.stringConfig = opts.getOptarg();

					break;

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

				}

			}
			if (this.stringEntityName == null || this.stringConfig == null ) {
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", expects both \"--config\"  and \"--entity-name\" to be present");
			}

			super.addArg(this.stringEntityName, String.class, false);

			try {
				super.addArg(this.stringConfig, ConfigProperties.class, true);
			} catch (Exception e) {
				throw new CommandException("Failed to parse ConfigProperties: \"" + stringConfig + "\"", e);
			}
		}

	}

}


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

/**
 * Start time:16:39:44 2009-06-12

 * Project: restcomm-jainslee-server-core

 *
 * @author Bartosz Baranowski
 * @author  Alexandre Mendonca
 */
package org.mobicents.slee.container.security;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.util.Arrays;
import java.util.Iterator;

import javax.management.ObjectName;
import javax.slee.management.ManagementException;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.profile.ProfileObject;

/**
 * Start time:16:39:44 2009-06-12

 * Project: restcomm-jainslee-server-core

 *
 * Dev class, to test logic, put all security related methods here to delegate to org.mobicents domain.
 *
 * @author  Bartosz Baranowski
 */
public class Utility {

	private Utility() {

	}

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

	public static void registerSafelyMBean(final SleeContainer sleeContainer, final ObjectName on, final Object bean) throws ManagementException {
		if (System.getSecurityManager() != null) {
			try {
				AccessController.doPrivileged(new PrivilegedExceptionAction() {

					public Object run() throws Exception {
						_registerSafelyMBean(sleeContainer, on, bean);
						return null;
					}
				});
			} catch (PrivilegedActionException e) {
				Throwable t = e.getCause();
				throw new ManagementException(t.getMessage(), t);
			}
		} else {
			_registerSafelyMBean(sleeContainer, on, bean);
		}
	}
	private static void _registerSafelyMBean(final SleeContainer sleeContainer, final ObjectName on, final Object bean) throws ManagementException {
		try {
			sleeContainer.getMBeanServer().registerMBean(bean, on);
		} catch (Throwable e) {
			throw new ManagementException(e.getMessage(), e);
		}
	}
	public static void unregisterSafelyMBean(final SleeContainer sleeContainer, final ObjectName on) throws ManagementException {
		if (System.getSecurityManager() != null) {
			try {
				AccessController.doPrivileged(new PrivilegedExceptionAction() {

					public Object run() throws Exception {
						_unregisterSafelyMBeanfinal(sleeContainer, on);
						return null;
					}
				});
			} catch (PrivilegedActionException e) {
				Throwable t = e.getCause();
				throw new ManagementException(t.getMessage(), t);
			}
		} else {
			_unregisterSafelyMBeanfinal(sleeContainer, on);
		}
	}

	private static void _unregisterSafelyMBeanfinal( SleeContainer sleeContainer, final ObjectName on) throws ManagementException {
		try {
			sleeContainer.getMBeanServer().unregisterMBean(on);
		} catch (Throwable e) {
			throw new ManagementException(e.getMessage(), e);
		}
	}

	/**
	 * This method depending if SecurityManger is present switches class loader using priviledged action,
	 * this is requried as some action may be initiated by unsecure domains.
	 * @param cl
	 * @param po
	 * @return
	 */
	public static ClassLoader switchSafelyClassLoader(final ClassLoader cl,final ProfileObject po)
	{
		ClassLoader _cl = null;
		if(System.getSecurityManager()!=null)
		{
			_cl =	(ClassLoader) AccessController.doPrivileged(new PrivilegedAction(){

				public Object run() {

					return _switchSafelyClassLoader(cl,po);
				}});
		}else
		{
			_cl = _switchSafelyClassLoader(cl, po);
		}

		return _cl;

	}

	private static ClassLoader _switchSafelyClassLoader(ClassLoader cl,ProfileObject po)
	{

		Thread t = Thread.currentThread();
		if(cl == null)
		{
			ClassLoader currentCL = t.getContextClassLoader();
			t.setContextClassLoader(po.getProfileTable().getProfileSpecificationComponent().getClassLoader());
			return currentCL;

		}else
		{
			t.setContextClassLoader(cl);
			return null;
		}

	}
	/**
	 * Its used to embed calls in AccessController in case of insturmented code, cause javassist does not support anonmous inner class.
	 * @param proxy
	 * @param methodToCallname
	 * @param signature
	 * @param values
	 * @return
	 */
	public static Object makeSafeProxyCall(final Object proxy,final String methodToCallname,final  Class[] signature,final  Object[] values) throws PrivilegedActionException
	{
		//Here we execute in sbb/profile or any other slee component domain
		// so no security calls can be made
		try {

			//AccessControlContext acc = new AccessControlContext(new ProtectionDomain[]{proxy.getClass().getProtectionDomain()});

			return AccessController.doPrivileged(new PrivilegedExceptionAction(){

				public Object run() throws Exception {
					final Method m = proxy.getClass().getMethod(methodToCallname, signature);
					//Here we cross to org.mobicents domain, with all perms, once m.invoke is called, we go into proxy object domain, effective rightsd are cross section of All + proxy object domain permissions
					//This is used when isolate security permissions is set to true;

					return m.invoke(proxy, values);
				//}},acc);
				}});
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}catch(PrivilegedActionException e)
		{
			e.printStackTrace();
		}
		return null;

	}

	public static Class getReturnType(Object o,String methodName)
	{
		try {
			Method m = o.getClass().getMethod(methodName, null);
			return m.getReturnType();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return null;
	}
	public static boolean evaluateNext(final Iterator i)
	{
		return ((Boolean)AccessController.doPrivileged(new PrivilegedAction(){

			public Object run() {
				return i.hasNext();
			}})).booleanValue();
	}

}


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

import java.security.PrivilegedActionException;

import javax.slee.NoSuchObjectLocalException;
import javax.slee.SLEEException;
import javax.slee.TransactionRequiredLocalException;
import javax.slee.TransactionRolledbackLocalException;
import javax.slee.profile.ProfileTable;
import javax.transaction.SystemException;
import javax.transaction.Transaction;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.profile.entity.ProfileEntity;

/**
 * Start time:14:20:46 2009-03-14

 * Project: restcomm-jainslee-server-core

 * This class implements profile local interface to provide all required
 * methods. It obtains on the fly ProfileObject to perform its tasks.
 *
 * @author  Bartosz Baranowski
 * @author  Alexandre Mendonca
 * @author martins
 */
public class ProfileLocalObjectImpl implements ProfileLocalObject {

	protected static final Logger logger = Logger.getLogger(ProfileLocalObjectImpl.class);

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

	/**
	 * the profile object to be used
	 */
	protected final ProfileObjectImpl profileObject;

	/**
	 * the transaction that defines if the profile object is tsill valid
	 */
	protected final Transaction transaction;

	/**
	 * the name of the profile related with this object
	 */
	private final String profileName;

	public ProfileLocalObjectImpl(ProfileObjectImpl profileObject) {
		this.profileObject = profileObject;
		try {
			this.transaction = sleeContainer.getTransactionManager().getTransaction();
			this.profileName = profileObject.getProfileEntity().getProfileName();
		} catch (Throwable e) {
			throw new SLEEException(e.getMessage(),e);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.profile.ProfileLocalObject#getProfileName()
	 */
	public String getProfileName() throws SLEEException {
		return profileName;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.profile.ProfileLocalObject#getProfileTable()
	 */
	public ProfileTable getProfileTable() throws SLEEException {
		return profileObject.getProfileTable();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.profile.ProfileLocalObject#getProfileTableName()
	 */
	public String getProfileTableName() throws SLEEException {
		return profileObject.getProfileTable().getProfileTableName();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.profile.ProfileLocalObject#isIdentical(javax.slee.profile.
	 * ProfileLocalObject)
	 */
	public boolean isIdentical(javax.slee.profile.ProfileLocalObject other) throws SLEEException {

		if (!(other instanceof ProfileLocalObjectImpl)) {
			return false;
		}

		return this._equals(other);
	}

	@Override
	public int hashCode() {
		return getProfileTable().hashCode() * 31 + ((profileName == null) ? 0 : profileName.hashCode());
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof ProfileLocalObjectImpl) {
			ProfileLocalObjectImpl other = (ProfileLocalObjectImpl) obj;
			return this._equals(other);
		}
		else {
			return false;
		}
	}

	/**
	 *
	 * @param other
	 * @return
	 */
	private boolean _equals(javax.slee.profile.ProfileLocalObject other) {

		if (!this.getProfileTableName().equals(other.getProfileTableName())) {
			return false;
		}

		if (this.getProfileName() == null) {
			if (other.getProfileName() == null) {
				return true;
			}
			else {
				return false;
			}
		}
		else {
			return this.getProfileName().equals(other.getProfileName());
		}
	}
	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.profile.ProfileLocalObject#remove()
	 */
	public void remove() throws TransactionRequiredLocalException, TransactionRolledbackLocalException, SLEEException {

		if (logger.isDebugEnabled()) {
			logger.debug("removing profile with name " + getProfileName() + " from table with name " + getProfileTableName());
		}

		sleeContainer.getTransactionManager().mandateTransaction();

		try {
			ProfileEntity profileEntity = profileObject.getProfileEntity();
			if (profileEntity != null) {
				// confirm it is still the same tx
				checkTransaction();
				// remove
				profileEntity.remove();
			}
			else {
				// there is no profile assigned to the object
				if(getProfileTable().find(getProfileName()) == null) {
					// this exception has priority
					throw new NoSuchObjectLocalException("the profile with name "+getProfileName()+" was not found on table with name "+getProfileTableName());
				}
				else {
					throw new IllegalStateException("the profile object is no longer valid");
				}
			}
		}
		catch (RuntimeException e) {
			try {
				profileObject.invalidateObject();
				sleeContainer.getTransactionManager().setRollbackOnly();
			} catch (SystemException e1) {
				throw new SLEEException(e1.getMessage(),e1);
			};
			throw new TransactionRolledbackLocalException(e.getMessage(),e);
		}
	}

	/**
	 * Verifies that the current transaction is still the one used to create the object
	 * @throws IllegalStateException
	 */
	protected void checkTransaction() throws IllegalStateException {
		try {
			if (!sleeContainer.getTransactionManager().getTransaction().equals(this.transaction)) {
				throw new IllegalStateException();
			}
		} catch (SystemException e) {
			throw new IllegalStateException();
		}
	}

	/**
	 * Process a {@link RuntimeException} occurred when invoking a method in the custom local object interface.
	 * @param e
	 * @throws SLEEException
	 * @throws TransactionRolledbackLocalException
	 */
	protected void processRuntimeException(RuntimeException e) throws SLEEException, TransactionRolledbackLocalException {
		try {
			profileObject.invalidateObject();
			sleeContainer.getTransactionManager().setRollbackOnly();
		} catch (SystemException e1) {
			throw new SLEEException(e1.getMessage(),e1);
		}
		throw new TransactionRolledbackLocalException(e.getMessage(),e);
	}

	/**
	 * Process a {@link PrivilegedActionException} occurred when invoking a method in the custom local object interface.
	 * @param e
	 * @throws Exception
	 * @throws TransactionRolledbackLocalException
	 */
	protected void processPrivilegedActionException(PrivilegedActionException e) throws Exception, TransactionRolledbackLocalException {
		if (e.getCause() instanceof RuntimeException) {
			processRuntimeException((RuntimeException) e.getCause());
		}
		else if (e.getCause() instanceof Exception) {
			throw (Exception) e.getCause();
		}
		else {
			throw new SLEEException("unexpected type of cause",e.getCause());
		}
	}

}


/*
 * JBoss, Home of Professional Open Source
 * Copyright 2003-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.console.server.activity;

import java.util.HashMap;

import org.mobicents.slee.container.management.console.client.ManagementConsoleException;
import org.mobicents.slee.container.management.console.client.activity.ActivityContextInfo;
import org.mobicents.slee.container.management.console.client.activity.ActivityService;
import org.mobicents.slee.container.management.console.server.ManagementConsole;
import org.mobicents.slee.container.management.console.server.mbeans.ActivityManagementMBeanUtils;
import org.mobicents.slee.container.management.console.server.mbeans.SleeMBeanConnection;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * @author Vladimir Ralev
 *
 */
public class ActivityServiceImpl extends RemoteServiceServlet implements ActivityService {

  private static final long serialVersionUID = -5366129803477778369L;

  public static final ManagementConsole managementConsole = ManagementConsole.getInstance();

  private SleeMBeanConnection sleeConnection = managementConsole.getSleeConnection();

  public Long getActivityContextTimeout() throws ManagementConsoleException {
    ActivityManagementMBeanUtils activity = sleeConnection.getSleeManagementMBeanUtils().getActivityManagementMBeanUtils();
    return activity.getActivityContextTimeout();
  }

  public ActivityServiceImpl() {

  }

  public ActivityContextInfo[] listActivityContexts() throws ManagementConsoleException {
    ActivityManagementMBeanUtils activity = sleeConnection.getSleeManagementMBeanUtils().getActivityManagementMBeanUtils();
    Object[] acs = activity.listActivityContexts(true);
    return objectToActivityContextArray(acs);
  }

  public void endActivity(String id) throws ManagementConsoleException {
    ActivityManagementMBeanUtils activity = sleeConnection.getSleeManagementMBeanUtils().getActivityManagementMBeanUtils();
    activity.endActivity(id);
  }

  public ActivityContextInfo retrieveActivityContextDetails(String id) throws ManagementConsoleException {
    ActivityManagementMBeanUtils activity = sleeConnection.getSleeManagementMBeanUtils().getActivityManagementMBeanUtils();
    // Object[] acs = activity.retrieveActivityContextDetails(id);
    Object[] acs = activity.listActivityContexts(true);
    return objectByIdToActivityContext(id, acs);
  }

  public ActivityContextInfo[] retrieveActivityContextIDByResourceAdaptorEntityName(String id) throws ManagementConsoleException {
    ActivityManagementMBeanUtils activity = sleeConnection.getSleeManagementMBeanUtils().getActivityManagementMBeanUtils();
    Object[] acs = activity.retrieveActivityContextIDByResourceAdaptorEntityName(id);
    return idsToActivityInfo(acs);
  }

  public ActivityContextInfo[] retrieveActivityContextIDByActivityType(String id) throws ManagementConsoleException {
    ActivityManagementMBeanUtils activity = sleeConnection.getSleeManagementMBeanUtils().getActivityManagementMBeanUtils();
    Object[] acs = activity.retrieveActivityContextIDByActivityType(id);
    return idsToActivityInfo(acs);
  }

  public ActivityContextInfo[] retrieveActivityContextIDBySbbEntityID(String id) throws ManagementConsoleException {
    ActivityManagementMBeanUtils activity = sleeConnection.getSleeManagementMBeanUtils().getActivityManagementMBeanUtils();
    Object[] acs = activity.retrieveActivityContextIDBySbbEntityID(id);
    return idsToActivityInfo(acs);
  }

  public void queryActivityContextLiveness() throws ManagementConsoleException {
    ActivityManagementMBeanUtils activity = sleeConnection.getSleeManagementMBeanUtils().getActivityManagementMBeanUtils();
    activity.queryActivityContextLiveness();
  }

  public ActivityContextInfo[] objectToActivityContextArray(Object[] acs) {
    ActivityContextInfo[] acsTransport;
    if (acs == null)
      return new ActivityContextInfo[0];
    acsTransport = new ActivityContextInfo[acs.length];
    for (int q = 0; q < acs.length; q++) {
      Object[] subItems = (Object[]) acs[q];
      acsTransport[q] = objectToActivityContext(subItems);
    }
    return acsTransport;
  }

  public static String[] objectToStringArray(Object[] acs) {
    String[] strings = new String[acs.length];
    for (int q = 0; q < strings.length; q++) {
      strings[q] = (String) acs[q];
    }
    return strings;
  }

  public ActivityContextInfo[] idsToActivityInfo(Object[] ids) {
    if (ids == null)
      return null;
    ActivityContextInfo[] acis = new ActivityContextInfo[ids.length];
    try {
      ActivityContextInfo[] all = listActivityContexts();
      HashMap<String, ActivityContextInfo> allMapped = new HashMap<String, ActivityContextInfo>();
      for (int q = 0; q < all.length; q++)
        allMapped.put(all[q].getId(), all[q]);
      for (int q = 0; q < ids.length; q++)
        acis[q] = allMapped.get(ids[q]);
    }
    catch (Exception e) {
      e.printStackTrace();
      return null;
    }
    return acis;
  }

  public ActivityContextInfo objectToActivityContext(Object[] subItems) {
    ActivityContextInfo acsTransport = new ActivityContextInfo();
    acsTransport.setId(subItems[0].toString());
    acsTransport.setActivityClass(subItems[1].toString());
    acsTransport.setLastAccessTime(toTimeStamp(subItems[2].toString()));
    acsTransport.setRaEntityId((String) subItems[3]);
    acsTransport.setSbbAttachments((String[]) subItems[4]);
    acsTransport.setNamesBoundTo((String[]) subItems[5]);
    acsTransport.setAttachedTimers((String[]) subItems[6]);
    acsTransport.setDataAttributes((String[]) subItems[7]);

    long timeout;
    try {
      timeout = getActivityContextTimeout();
    }
    catch (Exception ex) {
      ex.printStackTrace();
      timeout = -1;
    }
    if (timeout == -1)
      acsTransport.setTTL("N/A");
    else
      acsTransport.setTTL(toTTL(subItems[2].toString(), timeout));

    return acsTransport;
  }

  public ActivityContextInfo objectByIdToActivityContext(String id, Object[] acs) {
    if (acs == null || id == null)
      return null;

    for (int q = 0; q < acs.length; q++) {
      Object[] subItems = (Object[]) acs[q];
      if (subItems[0].toString().equals(id)) {
        return objectToActivityContext(subItems);
      }
    }

    return null;
  }

  @SuppressWarnings("unused")
  private static ActivityContextInfo[] testACS() {
    ActivityContextInfo[] test = new ActivityContextInfo[5];
    for (int q = 0; q < test.length; q++) {
      test[q] = new ActivityContextInfo();
      test[q].setId("ID" + new Long(new java.util.Random().nextLong()));
      test[q].setActivityClass("com.jboss.class");
      test[q].setLastAccessTime(toTimeStamp(new Long(new java.util.Random().nextLong()).toString()));
      test[q].setSbbAttachments(new String[] { "sbb1", "sbb2", "sbb3" });
      test[q].setNamesBoundTo(new String[] { "name1", "name2", "name3" });
      test[q].setAttachedTimers(new String[] { "timer1", "t2", "t3" });
      test[q].setDataAttributes(new String[] { "data1", "d2", "d3" });
    }
    return test;
  }

  private static String toTimeStamp(String millis) {
    long lmillis = Long.parseLong(millis);
    java.util.Date date = new java.util.Date(lmillis);
    java.text.SimpleDateFormat dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
    return dateFormat.format(date);
  }

  /**
   * Calculates the Activity TTL
   *
   * @param lastAccess time of last access to activity (in milliseconds)
   * @param timeout activity max idle time (in seconds)
   * @return a String with TTL value (in seconds)
   */
  private static String toTTL(String lastAccess, long timeout) {
    Long ttl = timeout - ((System.currentTimeMillis() - Long.parseLong(lastAccess)) / 1000);
    return ttl.toString();
  }

  public ActivityContextInfo[] retrieveActivityContextIDBySbbID(String id) throws ManagementConsoleException {
    ActivityManagementMBeanUtils activity = sleeConnection.getSleeManagementMBeanUtils().getActivityManagementMBeanUtils();
    Object[] acs = activity.retrieveActivityContextIDBySbbID(id);
    return idsToActivityInfo(acs);
  }
}


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

import java.util.HashMap;
import java.util.Map;

import javax.slee.Address;
import javax.slee.AddressPlan;
import javax.slee.EventTypeID;
import javax.slee.TransactionRequiredLocalException;
import javax.slee.profile.ProfileID;

import org.mobicents.slee.container.management.ProfileManagementImpl;
import org.mobicents.slee.container.profile.ProfileObjectImpl;
import org.mobicents.slee.container.profile.ProfileObjectPool;
import org.mobicents.slee.container.profile.ProfileTableTransactionView;
import org.mobicents.slee.container.profile.entity.ProfileEntity;
import org.mobicents.slee.container.transaction.SleeTransactionManager;

/**
 *
 * @author baranowb - Bartosz Baranowski
 * @author martins
 */
public abstract class AbstractProfileEvent {

	/**
	 * the address pointing to the event's profile
	 */
	private final Address profileAddress;

	/**
	 * the id of the event's profile
	 */
	private final ProfileID profileID;

	/**
	 * a snapshot of the event's profile, when the event occurred
	 */
	private final ProfileEntity profileAfterAction;

	private final ProfileManagementImpl profileManagement;

	/**
	 *
	 * @param profileEntityAfterAction
	 */
	AbstractProfileEvent(ProfileEntity profileEntityAfterAction, ProfileManagementImpl profileManagement) {
		this.profileManagement = profileManagement;
		this.profileAfterAction = profileEntityAfterAction;
		this.profileAddress = new Address(AddressPlan.SLEE_PROFILE, profileEntityAfterAction.getTableName() + "/"
				+ profileEntityAfterAction.getProfileName());
		this.profileID = new ProfileID(this.profileAddress);
	}

	/**
	 * Retrieves the address pointing to the event's profile
	 * @return
	 */
	public Address getProfileAddress() {
		return profileAddress;
	}

	/**
	 * Retrieves a snapshot of the instance of the event's profile, when the event occurred
	 * @return
	 */
	public ProfileEntity getProfileConcreteAfterAction() {
		return profileAfterAction;
	}

	/**
	 * Retrieves the id of the event's profile
	 * @return
	 */
	public ProfileID getProfile() {
		return profileID;
	}

	/**
	 * Verifies if the specified class can be loaded by current thread class loader
	 * @return
	 */
	boolean isProfileClassVisible() {
		try {
			Thread.currentThread().getContextClassLoader().loadClass(profileAfterAction.getClass().getName());
			return true;
		} catch (Throwable e) {
			return false;
		}
	}

	/**
	 * Retrieves a local object valid for thus current transaction.
	 *
	 * @param profilePojo
	 * @return
	 * @throws TransactionRequiredLocalException
	 */
	ProfileObjectImpl getProfileObjectValidInCurrentTransaction(ProfileEntity profileEntity) throws TransactionRequiredLocalException {
		// check tx
		final SleeTransactionManager txManager = profileManagement.getSleeContainer().getTransactionManager();
		txManager.mandateTransaction();

		// look for an assigned object in local map
		if (txData == null) {
			txData = new HashMap<ProfileEntity, ProfileObjectImpl>();
		}
		ProfileObjectImpl profileObject = (ProfileObjectImpl) txData.get(profileEntity);
		if (profileObject == null) {
			// get an object from the table
			profileEntity.setReadOnly(true);
			profileEntity.setDirty(false);
			ProfileObjectPool pool = profileManagement.getObjectPoolManagement().getObjectPool(profileEntity.getTableName());
			profileObject = pool.borrowObject();
			profileObject.profileActivate(profileEntity);
			ProfileTableTransactionView.passivateProfileObjectOnTxEnd(txManager, profileObject, pool);
			txData.put(profileEntity, profileObject);
		}
		return profileObject;
	}

	/**
	 * a map to hold loaded profile objects
	 */
	private Map<ProfileEntity,ProfileObjectImpl> txData = null;

	/**
	 * Retrieves the event type id for the event object
	 * @return
	 */
	public abstract EventTypeID getEventTypeID();

}