/*
 * 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.AccessController;
import java.security.PrivilegedAction;

import javax.slee.CreateException;
import javax.slee.SLEEException;
import javax.slee.management.SleeState;
import javax.slee.profile.ProfileLocalObject;
import javax.slee.profile.ProfileVerificationException;
import javax.slee.profile.UnrecognizedProfileNameException;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainerUtils;
import org.mobicents.slee.container.activity.ActivityContext;
import org.mobicents.slee.container.component.profile.ProfileConcreteClassInfo;
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.TransactionalAction;
import org.mobicents.slee.runtime.facilities.profile.AbstractProfileEvent;
import org.mobicents.slee.runtime.facilities.profile.ProfileAddedEventImpl;
import org.mobicents.slee.runtime.facilities.profile.ProfileRemovedEventImpl;
import org.mobicents.slee.runtime.facilities.profile.ProfileUpdatedEventImpl;

/**
 * Start time:16:46:52 2009-03-13

 * Project: restcomm-jainslee-server-core

 *
 * Class representing Profile Object - this object servers as place holder for
 * selected profiles. ProfileObject can belong to only one profile table during
 * its lifecycle, ever.
 *
 * @author  Bartosz Baranowski
 * @author  Alexandre Mendonca
 * @author martins
 */
public class ProfileObjectImpl implements ProfileObject {

	/**
	 *
	 */
	private static final Logger logger = Logger.getLogger(ProfileObject.class);

	/**
	 * the state of the profile object
	 */
	private ProfileObjectState state = ProfileObjectState.DOES_NOT_EXIST;

	/**
	 * the profile table the profile is related
	 */
	private final ProfileTableImpl profileTable;

	/**
	 * the instance of the concrete implementation of the profile spec
	 */
	private final ProfileConcrete profileConcrete;

	/**
	 * a snapshot copy of the current profile pojo, before updates, needed
	 * for profile table events
	 */
	private ProfileEntity profileEntitySnapshot;

	/**
	 * the context of the profile object
	 */
	private ProfileContextImpl profileContext = null;

	/**
	 * inidcates if this profile can be invoked more than once in a call tree for a single tx, thus exposed to loops
	 */
	private final boolean profileReentrant;

	/**
	 * indicates if the object is related with a slee 1.1 profile spec or not
	 */
	private final boolean isSlee11;

	/**
	 * the entity holding cmp data of currently assigned profile
	 */
	private ProfileEntity profileEntity;

	/**
	 *
	 */
	private final boolean readOnlyProfileTable;

	/**
	 *
	 */
	private final ProfileEntityFramework profileEntityFramework;

	/**
	 *
	 */
	private boolean persisted;

	/**
	 * used to filter invocations to profile concrete
	 */
	private final ProfileConcreteClassInfo profileConcreteClassInfo;

	/**
	 *
	 * @param profileTable
	 * @param profileSpecificationId
	 * @throws NullPointerException
	 * @throws SLEEException
	 */
	public ProfileObjectImpl(ProfileTableImpl profileTable) throws NullPointerException, SLEEException {

		if (profileTable == null) {
			throw new NullPointerException("Parameters must not be null");
		}

		this.profileTable = profileTable;

		final ProfileSpecificationComponent component = profileTable.getProfileSpecificationComponent();

		this.profileReentrant = component.getDescriptor().getProfileAbstractClass() == null ? false : this.profileTable.getProfileSpecificationComponent().getDescriptor().getProfileAbstractClass().getReentrant();
		this.readOnlyProfileTable = component.getDescriptor().getReadOnly();
		this.profileConcreteClassInfo = component.getProfileConcreteClassInfo();

		this.isSlee11 = profileTable.getProfileSpecificationComponent().isSlee11();

		try {
			this.profileConcrete = (ProfileConcrete) component.getProfileCmpConcreteClass().newInstance();
			this.profileConcrete.setProfileObject(this);
		}
		catch (Throwable e) {
			throw new SLEEException(e.getMessage(), e);
		}

		this.profileEntityFramework = component.getProfileEntityFramework();

	}

	/**
	 * Invoked from pool.
	 *
	 * @param profileContext
	 */
	public void setProfileContext(ProfileContextImpl profileContext) {

		if(logger.isTraceEnabled()) {
			logger.trace("[setProfileContext] "+this);
		}

		if (profileContext == null) {
			throw new NullPointerException("Passed context must not be null.");
		}

		if (state != ProfileObjectState.DOES_NOT_EXIST) {
			throw new IllegalStateException("Wrong state: " + this.state + ",on profile set context operation, for profile table: "
					+ this.profileTable.getProfileTableName() + " with specification: " + this.profileTable.getProfileSpecificationComponent().getProfileSpecificationID());
		}

		this.profileContext = profileContext;
		this.profileContext.setProfileObject(this);

		if (profileConcreteClassInfo.isInvokeSetProfileContext()) {
			final ClassLoader oldClassLoader = SleeContainerUtils.getCurrentThreadClassLoader();

			try {
				final ClassLoader cl = this.profileTable.getProfileSpecificationComponent().getClassLoader();

				if (System.getSecurityManager()!=null) {
					AccessController.doPrivileged(new PrivilegedAction<Object>() {
						public Object run() {
							Thread.currentThread().setContextClassLoader(cl);
							return null;
						}
					});
				}
				else {
					Thread.currentThread().setContextClassLoader(cl);
				}

				try {
					if (isSlee11) {
						try {
							profileConcrete.setProfileContext(profileContext);
						}
						catch (RuntimeException e) {
							runtimeExceptionOnProfileInvocation(e);
						}
					}
				}
				catch (Exception e) {
					if (logger.isDebugEnabled())
						logger.debug("Exception encountered while setting profile context for profile table: "
								+ this.profileTable.getProfileTableName() + " with specification: " + this.profileTable.getProfileSpecificationComponent().getProfileSpecificationID(), e);
				}
			}
			finally {
				if (System.getSecurityManager()!=null) {
					AccessController.doPrivileged(new PrivilegedAction<Object>() {
						public Object run() {
							Thread.currentThread().setContextClassLoader(oldClassLoader);
							return null;
						}
					});
				}
				else {
					Thread.currentThread().setContextClassLoader(oldClassLoader);
				}
			}
		}

		state = ProfileObjectState.POOLED;

	}

	/**
	 * Creation of the profile with the specified name
	 * @param profileName
	 * @throws CreateException
	 */
	public void profileCreate(String profileName) throws CreateException {
		profileInitialize(profileName);
		profilePostCreate();
		profileStore();
		profilePersist();
	}

	public void profilePersist() {
		persistProfileConcrete();
		persisted = true;
	}

	/**
	 * initialize state from default profile
	 */
	private void profileInitialize(String profileName) {

		if(logger.isTraceEnabled()) {
			logger.trace("[profileInitialize] "+this+" , profileName = "+profileName);
		}

		if (this.state != ProfileObjectState.POOLED) {
			throw new SLEEException(this.toString());
		}

		if (profileName == null) {
			// default profile creation
			// create instance of entity
			profileEntity = profileEntityFramework.getProfileEntityFactory().newInstance(profileTable.getProfileTableName(), null);
			// change state
			this.state = ProfileObjectState.PROFILE_INITIALIZATION;
			// invoke life cycle method on profile
			if (profileConcreteClassInfo.isInvokeProfileInitialize()) {
				try {
					profileConcrete.profileInitialize();
				}
				catch (RuntimeException e) {
					runtimeExceptionOnProfileInvocation(e);
				}
			}
		}
		else {
			// load the default profile entity
			if (logger.isTraceEnabled()) {
				logger.trace("Copying state from default profile on object "+this);
			}
			profileEntity = cloneEntity(profileTable.getDefaultProfileEntity());
			profileEntity.setProfileName(profileName);
		}

		// mark entity as dirty and for creation
		profileEntity.create();
		profileEntity.setDirty(true);
	}

	/**
	 *
	 * @throws CreateException
	 */
	private void profilePostCreate() throws CreateException {

		if(logger.isTraceEnabled()) {
			logger.trace("[profilePostCreate] "+this);
		}

		if (this.state != ProfileObjectState.POOLED && this.state != ProfileObjectState.PROFILE_INITIALIZATION) {
			throw new SLEEException(this.toString());
		}

		this.state = ProfileObjectState.READY;

		if (isSlee11) {
			if (profileConcreteClassInfo.isInvokeProfilePostCreate()) {
				try {
					this.profileConcrete.profilePostCreate();
				}
				catch (RuntimeException e) {
					runtimeExceptionOnProfileInvocation(e);
				}
			}
		}
	}

	/**
	 *
	 * Activates the profile object and use a specific snapshot of a profile entity
	 * @param snapshot
	 */
	public void profileActivate(ProfileEntity profileEntity) {
		profileActivate();
		profileLoad(profileEntity);
	}

	/**
	 * Activates the profile object and loads its persistent state
	 * @param profileName
	 * @throws UnrecognizedProfileNameException
	 */
	public void profileActivate(String profileName) throws UnrecognizedProfileNameException {
		profileActivate();
		profileLoad(profileName);
	}

	/**
	 *
	 */
	private void profileActivate() {

		if(logger.isTraceEnabled()) {
			logger.trace("[profileActivate] "+this);
		}

		if (state != ProfileObjectState.POOLED) {
			throw new SLEEException(this.toString());
		}
		if (isSlee11) {
			if (profileConcreteClassInfo.isInvokeProfileActivate()) {
				try {
					profileConcrete.profileActivate();
				}
				catch (RuntimeException e) {
					runtimeExceptionOnProfileInvocation(e);
				}
			}
		}
		this.state = ProfileObjectState.READY;
	}

	/**
	 *
	 */
	private void profileLoad(String profileName) throws UnrecognizedProfileNameException {

		if(logger.isTraceEnabled()) {
			logger.trace("[profileLoad] "+this+" , profileName = "+profileName);
		}

		ProfileEntity profileEntity = loadProfileEntity(profileName);
		profileEntity.setReadOnly(readOnlyProfileTable);
		profileLoad(profileEntity);
	}

	/**
	 *
	 * @param profileEntity
	 */
	private void profileLoad(ProfileEntity profileEntity) {

		if(logger.isTraceEnabled()) {
			logger.trace("[profileLoad] "+this+" , profileEntity = "+profileEntity);
		}

		if (state != ProfileObjectState.READY) {
			throw new SLEEException(this.toString());
		}

		this.profileEntity = profileEntity;

		// create a snapshot copy if the profile table fires events
		if (profileTable.doesFireEvents()) {
			profileEntitySnapshot = cloneEntity(profileEntity);
			profileEntitySnapshot.setReadOnly(true);;
		}
		if (profileConcreteClassInfo.isInvokeProfileLoad()) {
			try {
				this.profileConcrete.profileLoad();
			}
			catch (RuntimeException e) {
				runtimeExceptionOnProfileInvocation(e);
			}
		}
	}

	/**
	 *
	 * @throws ProfileVerificationException
	 */
	public void profileVerify() throws ProfileVerificationException {

		if(logger.isTraceEnabled()) {
			logger.trace("[profileVerify] "+this);
		}

		profileStore();

		if (state != ProfileObjectState.READY) {
			throw new SLEEException(this.toString());
		}

		if(!isSlee11 || profileEntity.getProfileName() != null) {
			// only invoke when it is a slee 1.0 profile or a non default slee 1.1 profile
			if (profileConcreteClassInfo.isInvokeProfileVerify()) {
				try {
					profileConcrete.profileVerify();
				}
				catch (RuntimeException e) {
					runtimeExceptionOnProfileInvocation(e);
				}
			}
		}
	}

	private void runtimeExceptionOnProfileInvocation(RuntimeException e) {
		logger.error("Runtime exception when invoking concrete profile! Setting tx for rollback and invalidating object",e);
		final SleeTransactionManager txManager = profileTable.getSleeContainer().getTransactionManager();
		try {
			if (txManager.getTransaction() != null) {
				txManager.setRollbackOnly();
			}
		} catch (Throwable f) {
			logger.error(f.getMessage(),f);
		}
		invalidateObject();
		throw e;
	}

	/**
	 *
	 */
	public void profileStore() {

		if(logger.isTraceEnabled()) {
			logger.trace("[profileStore] "+this);
		}

		if (state != ProfileObjectState.READY) {
			throw new SLEEException(this.toString());
		}

		if (profileEntity.isReadOnly()) {
			return;
		}

		if (profileConcreteClassInfo.isInvokeProfileStore()) {
			try {
				profileConcrete.profileStore();
			}
			catch (RuntimeException e) {
				runtimeExceptionOnProfileInvocation(e);
			}
		}
	}

	/**
	 *
	 */
	public void profilePassivate() {

		if (state == ProfileObjectState.READY) {

			// FIXME tests/profiles/lifecycle/Test1110227Test.xml enforces profileStore to be called before every profilePassivate(), doing this here to enfore it happens
			profileStore();

			if(logger.isTraceEnabled()) {
				logger.trace("[profilePassivate] "+this);
			}

			if (this.profileEntity.getProfileName() != null) {
				state = ProfileObjectState.POOLED;
			}
			else {
				// FIXME due to tests/profiles/profileabstractclass/Test1110251Test.xml we need to get ridden of the default profile object
				state = ProfileObjectState.DOES_NOT_EXIST;
			}

			if (profileConcreteClassInfo.isInvokeProfilePassivate()) {
				if (isSlee11) {
					try {
						profileConcrete.profilePassivate();
					}
					catch (RuntimeException e) {
						runtimeExceptionOnProfileInvocation(e);
					}
				}
			}

		}

		this.profileEntity = null;
		this.profileEntitySnapshot = null;

	}

	/**
	 *
	 */
	public void profileRemove(boolean invokeConcreteSbb, boolean isUninstall) {

		if(logger.isTraceEnabled()) {
			logger.trace("[profileRemove] "+this);
		}

		if (state != ProfileObjectState.READY) {
			throw new SLEEException(this.toString());
		}

		if (isSlee11 && invokeConcreteSbb) {
			if (profileConcreteClassInfo.isInvokeProfileRemove()) {
				try {
					profileConcrete.profileRemove();
				}
				catch (RuntimeException e) {
					runtimeExceptionOnProfileInvocation(e);
				}
			}
		}

		if (profileTable.doesFireEvents() && profileEntity.getProfileName() != null && profileEntitySnapshot != null && profileTable.getSleeContainer().getSleeState() == SleeState.RUNNING) {
			// fire event
			AbstractProfileEvent event = new ProfileRemovedEventImpl(profileEntity,profileTable.getProfileManagement());
			if (logger.isTraceEnabled()) {
				logger.trace("firing profile removed event for profile named "+profileEntity);
			}
			profileTable.getActivityContext().fireEvent(event.getEventTypeID(), event,
					event.getProfileAddress(), null, null,null,null);
		}

		if(profileEntity.getProfileName() != null && !isUninstall) {
			profileEntityFramework.removeprofile(profileEntity);
		}
		else {
			// the default profile entity is not stored in the framework
			profileTable.setDefaultProfileEntity(null);
		}

		state = ProfileObjectState.POOLED;

		this.profileEntity = null;
		this.profileEntitySnapshot = null;

	}

	/**
	 * Invoked when pool removes object
	 */
	public void unsetProfileContext() {

		if(logger.isTraceEnabled()) {
			logger.trace("[unsetProfileContext] "+this);
		}

		if (state == ProfileObjectState.POOLED  && profileConcreteClassInfo.isInvokeUnsetProfileContext()) {

			final ClassLoader oldClassLoader = SleeContainerUtils.getCurrentThreadClassLoader();
			try	{
				final ClassLoader cl = profileTable.getProfileSpecificationComponent().getClassLoader();
				if (System.getSecurityManager()!=null) {
					AccessController.doPrivileged(new PrivilegedAction<Object>() {
						public Object run()	{
							Thread.currentThread().setContextClassLoader(cl);
							return null;
						}
					});
				}
				else {
					Thread.currentThread().setContextClassLoader(cl);
				}

				if (isSlee11) {
					try {
						profileConcrete.unsetProfileContext();
					}
					catch (RuntimeException e) {
						runtimeExceptionOnProfileInvocation(e);
					}
				}
				profileContext.setProfileObject(null);
				state = ProfileObjectState.DOES_NOT_EXIST;
			}
			finally {
				if (System.getSecurityManager()!=null) {
					AccessController.doPrivileged(new PrivilegedAction<Object>() {
						public Object run() {
							Thread.currentThread().setContextClassLoader(oldClassLoader);
							return null;
						}
					});
				}
				else {
					Thread.currentThread().setContextClassLoader(oldClassLoader);
				}
			}
		}
	}

	// ------------

	/**
	 *
	 */
	public ProfileConcrete getProfileConcrete() {
		return profileConcrete;
	}

	/**
	 *
	 */
	public ProfileEntity getProfileEntity() {
		return profileEntity;
	}

	/**
	 * Retrieves the local representation for this profile object
	 * @return
	 */
	public ProfileLocalObject getProfileLocalObject() {
		final Class<?> profileLocalObjectConcreteClass = profileTable.getProfileSpecificationComponent().getProfileLocalObjectConcreteClass();
		ProfileLocalObject profileLocalObject = null;
		if (profileLocalObjectConcreteClass == null) {
			profileLocalObject = new ProfileLocalObjectImpl(this);
		}
		else {
			try {
				profileLocalObject = (ProfileLocalObject) profileLocalObjectConcreteClass.getConstructor(ProfileObjectImpl.class).newInstance(this);
			} catch (Throwable e) {
				throw new SLEEException(e.getMessage(),e);
			}
		}

		return profileLocalObject;
	}

	/**
	 *
	 * @return
	 */
	public ProfileObjectState getState() {
		return state;
	}

	/**
	 *
	 * @return
	 */
	public boolean isProfileReentrant() {
		return profileReentrant;
	}

	/**
	 *
	 * @return
	 */
	public ProfileTableImpl getProfileTable() {
		return profileTable;
	}

	private ProfileEntity cloneEntity(final ProfileEntity source) {
		final ProfileEntityFactory profileEntityFactory = profileTable.getProfileSpecificationComponent().getProfileEntityFramework().getProfileEntityFactory();
		final ProfileEntity result = profileEntityFactory.newInstance(source.getTableName(), source.getProfileName());
		if(System.getSecurityManager()==null)
		{
			profileEntityFactory.copyAttributes(source, result);
		}else
		{
			AccessController.doPrivileged(new PrivilegedAction<Object>(){

				public Object run() {
					profileEntityFactory.copyAttributes(source, result);
					return null;
				}});
		}
		return result;
	}

	/**
	 *
	 */
	private ProfileEntity loadProfileEntity(String profileName) throws UnrecognizedProfileNameException {

		if (profileName != null) {
			ProfileEntity profileEntity = profileEntityFramework.retrieveProfile(profileTable.getProfileTableName(), profileName);
			if (profileEntity == null) {
				throw new UnrecognizedProfileNameException();
			}
			return profileEntity;
		}
		else {
			// clone default profile entity
			final ProfileEntity profileEntity = cloneEntity(profileTable.getDefaultProfileEntity());
			// add a tx action after commit to update the state on the one stored in the table
			TransactionalAction action = new TransactionalAction() {
				public void execute() {
					profileTable.setDefaultProfileEntity(cloneEntity(profileEntity));
				}
			};
			profileTable.getSleeContainer().getTransactionManager().getTransactionContext().getAfterCommitActions().add(action);
			return profileEntity;
		}
	}

	/**
	 *
	 */
	private void persistProfileConcrete() {
		if (profileEntity.isCreate()) {
			if (logger.isTraceEnabled()) {
				logger.trace("Persisting "+this);

			}
			if (profileEntity.getProfileName() != null) {
				// the default profile entity is not persisted using the framework
				profileEntityFramework.persistProfile(profileEntity);
			}
			else {
				profileTable.setDefaultProfileEntity(cloneEntity(profileEntity));
			}
		}
	}

	public String toString() {
		return "ProfileObject( table= "+profileTable.getProfileTableName()+" , state = "+state+" , entity = "+ profileEntity+" )";
	}

	/**
	 * use this method to move the object to {@link ProfileObjectState#DOES_NOT_EXIST} state and indicate to the pool that the object should be discarded
	 */
	public void invalidateObject() {
		state = ProfileObjectState.DOES_NOT_EXIST;
	}

	/**
	 * Fires a profile added or updated event if the profile object state is ready and the persistent state is dirty
	 */
	public void fireAddOrUpdatedEventIfNeeded() {

		if (state == ProfileObjectState.READY) {
			if (profileEntity.isDirty()) {
				// check the table fires events and the object is not assigned to a default profile
				if (profileTable.doesFireEvents() && profileEntity.getProfileName() != null && profileTable.getSleeContainer().getSleeState() == SleeState.RUNNING) {
					// Fire a Profile Added or Updated Event
					ActivityContext ac = profileTable.getActivityContext();
					AbstractProfileEvent event = null;
					if (profileEntity.isCreate()) {
						if (persisted) {
							event = new ProfileAddedEventImpl(profileEntity,profileTable.getProfileManagement());
							persisted = false;
							if (logger.isTraceEnabled()) {
								logger.trace("firing profile added event for profile named "+profileEntity);
							}
						}
						else {
							return;
						}
					}
					else {
						event = new ProfileUpdatedEventImpl(profileEntitySnapshot,profileEntity,profileTable.getProfileManagement());
						if (logger.isTraceEnabled()) {
							logger.trace("firing profile updated event for profile named "+profileEntity);
						}
					}
					ac.fireEvent(event.getEventTypeID(), event,
							event.getProfileAddress(), null, null,null,null);
				}
			}
		}

	}

	/**
	 * the profile cmp slee 1.0 wrapper for this profile object
	 */
	private AbstractProfileCmpSlee10Wrapper profileCmpSlee10Wrapper;

	/**
	 * Retrieves the profile cmp slee 1.0 wrapper for this profile object
	 * @return
	 */
	public AbstractProfileCmpSlee10Wrapper getProfileCmpSlee10Wrapper() {
		if (profileCmpSlee10Wrapper == null) {
			try {
				profileCmpSlee10Wrapper = (AbstractProfileCmpSlee10Wrapper) profileTable.getProfileSpecificationComponent().getProfileCmpSlee10WrapperClass().getConstructor(ProfileObjectImpl.class).newInstance(this);
			} catch (Throwable e) {
				throw new SLEEException(e.getMessage(),e);
			}
		}
		return profileCmpSlee10Wrapper;
	}

}


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

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

import javax.slee.ServiceID;

import org.mobicents.slee.container.activity.ActivityContextHandle;
import org.mobicents.slee.container.activity.ActivityType;

/**
 * @author martins
 *
 */
public class ServiceActivityContextHandle implements ActivityContextHandle {

	/**
	 *
	 */
	private static final long serialVersionUID = 1L;

	private ServiceActivityHandleImpl activityHandle;

	/**
	 * not to be used, needed due to externalizable
	 */
	public ServiceActivityContextHandle() {

	}

	/**
	 *
	 */
	public ServiceActivityContextHandle(ServiceActivityHandleImpl activityHandle) {
		this.activityHandle = activityHandle;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.runtime.activity.ActivityContextHandle#getActivity()
	 */
	public Object getActivityObject() {
		return new ServiceActivityImpl(activityHandle.getServiceID());
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.runtime.activity.ActivityContextHandle#getActivityHandle
	 * ()
	 */
	public ServiceActivityHandleImpl getActivityHandle() {
		return activityHandle;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.runtime.activity.ActivityContextHandle#getActivityType
	 * ()
	 */
	public ActivityType getActivityType() {
		return ActivityType.SERVICE;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (obj.getClass() == this.getClass()) {
			final ServiceActivityContextHandle other = (ServiceActivityContextHandle) obj;
			return other.activityHandle.equals(this.activityHandle);
		} else {
			return false;
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		return activityHandle.hashCode();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return new StringBuilder("ACH=").append(getActivityType()).append('>')
				.append(activityHandle).toString();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
	 */
	@Override
	public void readExternal(ObjectInput in) throws IOException,
			ClassNotFoundException {
		final ServiceID serviceID = new ServiceID(in.readUTF(), in.readUTF(),
				in.readUTF());
		activityHandle = new ServiceActivityHandleImpl(serviceID);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
	 */
	@Override
	public void writeExternal(ObjectOutput out) throws IOException {
		final ServiceID serviceID = activityHandle.getServiceID();
		out.writeUTF(serviceID.getName());
		out.writeUTF(serviceID.getVendor());
		out.writeUTF(serviceID.getVersion());
	}
}


/*
 * 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:00:46:57 2009-02-04

 * Project: restcomm-jainslee-server-core

 *
 * @author baranowb - Bartosz Baranowski
 *
 * @author  Alexandre Mendonca
 */
package org.mobicents.slee.container.component;

import java.io.File;
import java.net.URI;
import java.util.Set;

import javax.slee.ComponentID;
import javax.slee.management.ComponentDescriptor;
import javax.slee.management.DependencyException;
import javax.slee.management.DeploymentException;
import javax.slee.management.LibraryID;

import org.mobicents.slee.container.component.deployment.jaxb.descriptors.LibraryDescriptorImpl;
import org.mobicents.slee.container.component.library.JarDescriptor;
import org.mobicents.slee.container.component.library.LibraryComponent;
import org.mobicents.slee.container.component.security.PermissionHolderImpl;

/**
 * Start time:00:46:57 2009-02-04

 * Project: restcomm-jainslee-server-core

 *
 * @author baranowb - Bartosz Baranowski
 *
 * @author  Alexandre Mendonca
 */
public class LibraryComponentImpl extends AbstractSleeComponent implements LibraryComponent {

	/**
	 * the library descriptor
	 */
	private final LibraryDescriptorImpl descriptor;

	/**
	 * the JAIN SLEE specs descriptor
	 */
	private javax.slee.management.LibraryDescriptor specsDescriptor;

	/**
	 *
	 * @param descriptor
	 */
	public LibraryComponentImpl(LibraryDescriptorImpl descriptor) {
		this.descriptor = descriptor;
	}

	/**
	 * Retrieves the library descriptor
	 *
	 * @return
	 */
	public LibraryDescriptorImpl getDescriptor() {
		return descriptor;
	}

	/**
	 * Retrieves the library id
	 *
	 * @return
	 */
	public LibraryID getLibraryID() {
		return descriptor.getLibraryID();
	}

	@Override
	public boolean addToDeployableUnit() {
		return getDeployableUnit().getLibraryComponents().put(getLibraryID(), this) == null;
	}

	@Override
	public Set<ComponentID> getDependenciesSet() {
		return descriptor.getDependenciesSet();
	}

	@Override
	public boolean isSlee11() {
		return descriptor.isSlee11();
	}

	@Override
	public ComponentID getComponentID() {
		return getLibraryID();
	}

	@Override
	public boolean validate() throws DependencyException, DeploymentException {
		// nothing to validate ?
		return true;
	}

	/**
	 * Retrieves the JAIN SLEE specs descriptor
	 *
	 * @return
	 */
	public javax.slee.management.LibraryDescriptor getSpecsDescriptor() {
		if (specsDescriptor == null) {
			final LibraryID[] libraryIDs = descriptor.getLibraryRefs().toArray(new LibraryID[descriptor.getLibraryRefs().size()]);
			final JarDescriptor[] jars = descriptor.getJars().toArray(new JarDescriptor[descriptor.getJars().size()]);
			String[] libraryJars = new String[jars.length];
			int i = 0;
			for(JarDescriptor jar : jars) {
			  libraryJars[i++] = jar.getJarName();
			}
			specsDescriptor = new javax.slee.management.LibraryDescriptor(getLibraryID(), getDeployableUnit().getDeployableUnitID(), getDeploymentUnitSource(), libraryIDs, libraryJars);
		}
		return specsDescriptor;
	}

	@Override
	public ComponentDescriptor getComponentDescriptor() {
		return getSpecsDescriptor();
	}

	@Override
	public void processSecurityPermissions() throws DeploymentException {

		PermissionHolderImpl master = null;
		PermissionHolderImpl child = null;
		try {
			if (this.descriptor.getSecurityPermissions() != null) {

				URI deployURI =super.getDeploymentDir().toURI();

				//deployURI = new URI(deployURI.toString()+"-");

				master=new PermissionHolderImpl(deployURI, this.descriptor.getSecurityPermissions());
				super.permissions.add(master);
				//System.err.println("ADD MASTER: "+super.permissions.add(master));
			}

			for (JarDescriptor mjar : this.descriptor.getJars()) {
				if (mjar.getSecurityPermissions() != null) {
					File f = new File(super.getDeploymentDir(), mjar.getJarName());
					//System.err.println("PERMISSION FOR LIB1:"+Arrays.toString(super.permissions.toArray()));
					child = new PermissionHolderImpl(f.toURI(), mjar.getSecurityPermissions());
					super.permissions.add(child);
					//System.err.println("ADD: "+super.permissions.add(child));
					//System.err.println("PERMISSION FOR LIB2:"+Arrays.toString(super.permissions.toArray()));
				}
			}

		} catch (Exception e) {
			throw new DeploymentException("Failed to make permissions usable.", e);
		}
	}

	@Override
	public void undeployed() {
		super.undeployed();
		specsDescriptor = null;
	}

}


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

import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewConstructor;
import javassist.CtNewMethod;
import javassist.CtPrimitiveType;
import javassist.NotFoundException;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool;
import javassist.bytecode.FieldInfo;
import javassist.bytecode.MethodInfo;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.AnnotationMemberValue;
import javassist.bytecode.annotation.ArrayMemberValue;
import javassist.bytecode.annotation.BooleanMemberValue;
import javassist.bytecode.annotation.ByteMemberValue;
import javassist.bytecode.annotation.CharMemberValue;
import javassist.bytecode.annotation.ClassMemberValue;
import javassist.bytecode.annotation.DoubleMemberValue;
import javassist.bytecode.annotation.EnumMemberValue;
import javassist.bytecode.annotation.FloatMemberValue;
import javassist.bytecode.annotation.IntegerMemberValue;
import javassist.bytecode.annotation.LongMemberValue;
import javassist.bytecode.annotation.MemberValue;
import javassist.bytecode.annotation.ShortMemberValue;
import javassist.bytecode.annotation.StringMemberValue;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.deployment.ClassUtils;
import org.mobicents.slee.container.profile.ProfileCallRecorderTransactionData;
import org.mobicents.slee.container.profile.ProfileCmpHandler;
import org.mobicents.slee.container.profile.ProfileManagementHandler;
import org.mobicents.slee.container.security.Utility;

/**
 *
 * ClassGeneratorUtils.java
 *
 *
Project:  mobicents
 *
9:22:57 AM Mar 26, 2009
 *

 * @author  Alexandre Mendonca
 * @author  Bartosz Baranowski
 */
public class ClassGeneratorUtils {

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

  private static ClassPool classPool = null;

  public static final String _PLO_PO_ALLOCATION = "";//"allocateProfileObject();";

  public static final String CMP_HANDLER = ProfileCmpHandler.class.getName();
  public static final String MANAGEMENT_HANDLER = ProfileManagementHandler.class.getName();

  /**
   * Creates a class with the desired name and linked to the mentioned interfaces.
   *
   * @param className
   * @param interfaces
   * @return
   * @throws Exception
   */
  public static CtClass createClass(String className, String[] interfaces) throws Exception
  {
    if(className == null)
    {
      throw new NullPointerException("Class name cannot be null");
    }

    CtClass clazz = classPool.makeClass(className);

    if(interfaces != null && interfaces.length > 0)
    {
      clazz.setInterfaces( classPool.get( interfaces ) );
    }

    return clazz;
  }

  /**
   * Gets the desired class from the pool.
   *
   * @param className
   * @return
   * @throws Exception
   */
  public static CtClass getClass(String className) throws Exception
  {
    return classPool.get(className);
  }

  /**
   * Create the links with possible interfaces
   *
   * @param concreteClass
   * @param interfaces
   */
  public static void createInterfaceLinks(CtClass concreteClass, String[] interfaceNames)
  {
    if(interfaceNames != null && interfaceNames.length > 0)
    {
      try
      {
        for(String interfaceName : interfaceNames)
        {
          boolean found = false;
          for(CtClass existingInterfaces : concreteClass.getInterfaces())
          {
            if(existingInterfaces.getName().equals(interfaceName))
              found = true;
          }

          if(!found)
            concreteClass.addInterface(classPool.get(interfaceName));
        }
      }
      catch ( NotFoundException e ) {
        e.printStackTrace();
      }
    }
  }

  /**
   * Create the inheritance link with the absract class provided by the developer
   *
   * @param concreteClass the concrete class to which to add the inheritance link
   * @param superClass the superClass to set
   */
  public static void createInheritanceLink(CtClass concreteClass, String superClassName)
  {
    if(superClassName != null && superClassName.length() >= 0)
    {
      try
      {
        concreteClass.setSuperclass(classPool.get(superClassName));
      }
      catch ( CannotCompileException e ) {
        e.printStackTrace();
      }
      catch ( NotFoundException e ) {
        e.printStackTrace();
      }
    }
  }

  /**
   *
   * @param concreteClass
   * @return
   */
  public static CtConstructor generateDefaultConstructor(CtClass concreteClass)
  {
    CtConstructor constructor = null;

    try
    {
      constructor = CtNewConstructor.defaultConstructor(concreteClass);
      concreteClass.addConstructor(constructor);
    }
    catch ( CannotCompileException e ) {
      e.printStackTrace();
    }

    return constructor;
  }

  /**
   *
   * @param concreteClass
   * @param parameterClasses
   * @param parameterNames
   * @return
   */
  public static CtConstructor generateConstructorWithParameters(CtClass concreteClass, Class<?>[] parameterClasses, String[] parameterNames, boolean[] isTransient)
  {
    CtConstructor constructor = null;
    CtClass[] parameters = new CtClass[parameterClasses.length];

    String constructorBody = "{";

    for (int i = 0; i < parameterClasses.length; i++)
    {
      try
      {
        CtField ctField = null;

        parameters[i] = classPool.get(parameterClasses[i].getName());

        try
        {
          ctField = concreteClass.getField(parameterNames[i]);
        }
        catch (NotFoundException nfe)
        {
          ctField = new CtField(parameters[i], parameterNames[i], concreteClass);

          if (ctField.getName().equals("java.lang.Object"))
          {
            ctField.setModifiers(Modifier.PUBLIC);
          }
          else
          {
            ctField.setModifiers(Modifier.PRIVATE);
          }

          concreteClass.addField(ctField);
        }

        if(isTransient[i])
        {
          addAnnotation( "javax.persistence.Transient", null, ctField );
        }
      }
      catch (Exception cce) {
        cce.printStackTrace();
      }

      constructorBody += "this." + parameterNames[i] + "=$" + (i+1) + ";";
    }

    constructorBody += "}";

    try {
      constructor = CtNewConstructor.make(parameters, new CtClass[]{}, constructorBody, concreteClass);
      concreteClass.addConstructor( constructor );
    } catch (CannotCompileException e) {
      e.printStackTrace();
    }

    return constructor;
  }

  /**
   * Adds a field of the desired type to the declaring class.
   *
   * @param fieldType
   * @param fieldName
   * @param declaringClass
   * @return
   * @throws CannotCompileException
   */
  public static CtField addField(CtClass fieldType, String fieldName, CtClass declaringClass) throws CannotCompileException
  {
    return addField( fieldType, fieldName, declaringClass, Modifier.PRIVATE );
  }

  /**
   * Adds a field of the desired type to the declaring class.
   *
   * @param fieldType
   * @param fieldName
   * @param declaringClass
   * @return
   * @throws CannotCompileException
   */
  public static CtField addField(CtClass fieldType, String fieldName, CtClass declaringClass, int modifier) throws CannotCompileException
  {
    return addField( fieldType, fieldName, declaringClass, modifier, null );
  }

  /**
   * Adds a field of the desired type to the declaring class.
   *
   * @param fieldType
   * @param fieldName
   * @param declaringClass
   * @param modifier
   * @return
   * @throws CannotCompileException
   */
  public static CtField addField(CtClass fieldType, String fieldName, CtClass declaringClass, int modifier, String initializerExpr) throws CannotCompileException
  {
    CtField field = new CtField( fieldType, decapitalize(fieldName), declaringClass );
    field.setModifiers(modifier);

    if(initializerExpr != null)
    {
      declaringClass.addField(field, CtField.Initializer.byExpr(initializerExpr));
    }
    else
    {
      declaringClass.addField(field);
    }

    return field;
  }

  /**
   * Generates a getter for the field (get<FieldName>) and adds it to the declaring class.
   *
   * @param field
   * @param interceptorAccess
   * @return
   * @throws NotFoundException
   * @throws CannotCompileException
   */
  public static CtMethod generateGetter(CtField field, String interceptorAccess) throws NotFoundException, CannotCompileException
  {
    String getterName = "get" + capitalize(field.getName());

    CtMethod getter = CtNewMethod.getter( getterName, field );

    if(interceptorAccess != null)
      getter.setBody( interceptorAccess + "." + getterName + "($$);" );

    field.getDeclaringClass().addMethod(getter);

    return getter;
  }

  /**
   * Generates a setter for the field (get<FieldName>) and adds it to the declaring class.
   *
   * @param field
   * @return
   * @throws NotFoundException
   * @throws CannotCompileException
   */
  public static CtMethod generateSetter(CtField field, String interceptorAccess) throws NotFoundException, CannotCompileException
  {
    String setterName = "set" + capitalize(field.getName());

    CtMethod setter = CtNewMethod.setter( setterName, field );

    if(interceptorAccess != null)
      setter.setBody( interceptorAccess + "." + setterName + "($$);" );

    field.getDeclaringClass().addMethod(setter);

    return setter;
  }

  /**
   * Generates getter and setter for the field (get/set<FieldName>) and adds them to the declaring class.
   *
   * @param field
   * @throws NotFoundException
   * @throws CannotCompileException
   */
  public static void generateGetterAndSetter(CtField field, String interceptorAccess) throws NotFoundException, CannotCompileException
  {
    generateGetter(field, interceptorAccess);
    generateSetter(field, interceptorAccess);
  }

  /**
   * Retrieves the sufix to add to set/get and obtain the profile cmp acessors method names in the profile pojo
   * @param fieldName
   * @return
   */
  public static String getPojoCmpAccessorSufix(String fieldName) {
	  return "C" + fieldName;
  }

  /**
   * Adds the selected annotation to the Object, along with the specified memberValues.
   *
   * @param annotation the FQDN of the annotation
   * @param memberValues the member values HashMap (name=value)
   * @param toAnnotate the object to be annotated
   */
  public static void addAnnotation(String annotation, LinkedHashMap<String, Object> memberValues, Object toAnnotate)
  {
    if(toAnnotate instanceof CtClass)
    {
      CtClass classToAnnotate = (CtClass) toAnnotate;

      ClassFile cf = classToAnnotate.getClassFile();
      ConstPool cp = cf.getConstPool();

      AnnotationsAttribute attr = (AnnotationsAttribute) cf.getAttribute(AnnotationsAttribute.visibleTag);

      if(attr == null)
      {
        attr = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag);
      }

      Annotation a = new Annotation(annotation, cp);

      if(memberValues != null)
      {
        addMemberValuesToAnnotation(a, cp, memberValues);
      }

      attr.addAnnotation( a );

      cf.addAttribute( attr );
    }
    else if(toAnnotate instanceof CtMethod)
    {
      CtMethod methodToAnnotate = (CtMethod) toAnnotate;

      MethodInfo mi = methodToAnnotate.getMethodInfo();
      ConstPool cp = mi.getConstPool();

      AnnotationsAttribute attr = (AnnotationsAttribute) mi.getAttribute(AnnotationsAttribute.visibleTag);

      if(attr == null)
      {
        attr = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag);
      }

      Annotation a = new Annotation(annotation, cp);

      if(memberValues != null)
      {
        addMemberValuesToAnnotation(a, cp, memberValues);
      }

      attr.addAnnotation( a );

      mi.addAttribute( attr );
    }
    else if(toAnnotate instanceof CtField)
    {
      CtField fieldToAnnotate = (CtField) toAnnotate;

      FieldInfo fi = fieldToAnnotate.getFieldInfo();
      ConstPool cp = fi.getConstPool();

      AnnotationsAttribute attr = (AnnotationsAttribute) fi.getAttribute(AnnotationsAttribute.visibleTag);

      if(attr == null)
      {
        attr = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag);
      }

      Annotation a = new Annotation(annotation, cp);

      if(memberValues != null)
      {
        addMemberValuesToAnnotation(a, cp, memberValues);
      }

      attr.addAnnotation( a );

      fi.addAttribute( attr );
    }
    else
    {
      throw new UnsupportedOperationException("Unknown object type: " + toAnnotate.getClass());
    }
  }

  public static Map<?,?> getInterfaceMethodsFromInterface(String interfaceClassName)
  {
    HashMap<String, CtMethod> interfaceMethods = new HashMap<String, CtMethod>();

    try
    {
      CtClass interfaceClass = classPool.get(interfaceClassName);

      CtMethod[] methods = interfaceClass.getDeclaredMethods();

      for (int i = 0; i < methods.length; i++) {
        interfaceMethods.put(ClassUtils.getMethodKey(methods[i]), methods[i]);
      }

      interfaceMethods.putAll(ClassUtils.getSuperClassesAbstractMethodsFromInterface(interfaceClass));
    }
    catch (Exception e) {
      e.printStackTrace();
    }

    return interfaceMethods;
  }

  public static void instrumentBussinesMethod(CtClass concreteClass, CtMethod method, String interceptorAccess) throws Exception
  {
    boolean hasReturnValue = method.getReturnType().toString().equals("void");

    String body = "{" +
    _PLO_PO_ALLOCATION +
//    "System.out.println(\"Calling " + method.getName() + "\");" +
    "Thread t = Thread.currentThread();"+
    "ClassLoader oldClassLoader = t.getContextClassLoader();"+
    "t.setContextClassLoader(this.profileObject.getProfileSpecificationComponent().getClassLoader());"+
//    "System.out.println(\"profileManagementHandler[\" + this.profileManagementHandler + \"]\");" +
    "try {";

    if(hasReturnValue)
      body += "Object result = " + interceptorAccess + "." + method.getName() + "($$);";
    else
      body += interceptorAccess + "." + method.getName() + "($$);";

    body += hasReturnValue ? "return ($r)result;" : "return;";

    body+=
      "}" +
      "catch(java.lang.RuntimeException re)"+
      "{"+
      "  try {"+
      "    this.sleeTransactionManager.rollback();"+
      "    throw new javax.slee.TransactionRolledbackLocalException(\"ProfileLocalObject invocation results in RuntimeException, rolling back.\",re);"+
      "  }" +
      "  catch (Exception e) {"+
//      "    e.printStackTrace();"+
      "    throw new javax.slee.SLEEException(\"System level failure.\",e);"+
      "  }"+
      "}" +
      "finally"+
      "{"+
      "  if(this.getProfileObject().getProfileContext().getRollbackOnly()){" +
      "  try {"+
      "    this.sleeTransactionManager.rollback();"+
      "  }" +
      "  catch (Exception e) {"+
//      "    e.printStackTrace();"+
      "    throw new javax.slee.SLEEException(\"System level failure.\",e);"+
      "  }"+
      "}" +
      "  t.setContextClassLoader(oldClassLoader);"+
      "}"+
      "}";

    if(logger.isTraceEnabled())
    {
      logger.trace("Instrumented method, name:"+method.getName()+", with body:\n"+body);
    }

    CtMethod newMethod = CtNewMethod.make(method.getReturnType(), method.getName(), method.getParameterTypes(), method.getExceptionTypes(), body, concreteClass);
    newMethod.setModifiers(method.getModifiers() & ~Modifier.ABSTRACT);

    concreteClass.addMethod(newMethod);
  }

  public static void generateDelegateMethod(CtClass classToBeInstrumented, CtMethod method, String interceptorAccess, boolean recordTxData) throws CannotCompileException, NotFoundException, IllegalArgumentException, SecurityException, IllegalAccessException, NoSuchFieldException, ClassNotFoundException
  {
    // FIXME: should we add check for concrete methods from profileManagementAbstractClass and do clone?

    if (logger.isTraceEnabled()) {
      logger.trace("About to instrument: " + method.getName() + ", into: " + classToBeInstrumented.getName());
    }

    method = CtNewMethod.copy(method, classToBeInstrumented, null);
    method.setModifiers(method.getModifiers() & ~Modifier.ABSTRACT);

    String retStatement = null;
    String retType = null;

    try
    {
      if(method.getReturnType() != CtClass.voidType)
      {
        retStatement = "return ($r) result;";
      }
    }
    catch (NotFoundException e) {
      throw e;
    }

    boolean hasImpl = interceptorAccess.equals("super");

    String body = "{ "

    	+ClassLoader.class.getName()+ " cl = "+Utility.class.getName()+".switchSafelyClassLoader(null,profileObject);" +
    	//ClassLoader.class.getName()+ " cl = "+Thread.class.getName()+".currentThread().getContextClassLoader();" +
    	///Thread.class.getName()+".currentThread().setContextClassLoader(profileObject.getProfileTable().getProfileSpecificationComponent().getClassLoader());"+
        "  try {" +
      (recordTxData ? ProfileCallRecorderTransactionData.class.getName() + ".addProfileCall(profileObject);" : "");

    if(retStatement != null)
    {
      if(method.getReturnType().isPrimitive())
        retType = ((Class<?>)Class.forName( ((CtPrimitiveType)method.getReturnType()).getWrapperName() ).getField( "TYPE" ).get( null )).getName();
      else if(method.getReturnType().isArray())
        retType = method.getReturnType().getName();
      else
        retType = Class.forName(method.getReturnType().getClassFile().getName()).getName();
    }

    body += (retStatement != null ? retType + " result = " : "") + interceptorAccess + "." + method.getName() + "(" + (hasImpl ? "" : "profileObject, ") + "$$);";
    body += retStatement != null ? retStatement : "";

    body += "  }" +
      "  finally {" +
      Utility.class.getName()+".switchSafelyClassLoader(cl,null);" +
      //Thread.class.getName()+".currentThread().setContextClassLoader(cl);" +
      (recordTxData ? ProfileCallRecorderTransactionData.class.getName() + ".removeProfileCall(profileObject);" : "") +
      "  }" +
      "}";

    if(logger.isTraceEnabled())
    {
      logger.trace("Instrumented method, name:"+method.getName()+", with body:\n"+body);
    }

    method.setBody(body);
    classToBeInstrumented.addMethod(method);
  }

  private static MemberValue getMemberValue(Object mvValue,ConstPool cp) {

	  MemberValue mv = null;

	  if(mvValue instanceof MemberValue){
		  mv = (MemberValue) mvValue;
	  }
	  else if(mvValue instanceof String)
      {
        mv = new StringMemberValue((String)mvValue, cp);
      }
      else if(mvValue instanceof Annotation)
      {
        mv = new AnnotationMemberValue((Annotation)mvValue, cp);
      }
      else if(mvValue instanceof Boolean)
      {
        mv = new BooleanMemberValue((Boolean)mvValue, cp);
      }
      else if(mvValue instanceof Byte)
      {
        mv = new ByteMemberValue((Byte)mvValue, cp);
      }
      else if(mvValue instanceof Character)
      {
        mv = new CharMemberValue((Character)mvValue, cp);
      }
      else if(mvValue instanceof Class)
      {
        mv = new ClassMemberValue(((Class<?>)mvValue).getName(), cp);
      }
      else if(mvValue instanceof Double)
      {
        mv = new DoubleMemberValue((Double)mvValue, cp);
      }
      else if(mvValue instanceof Enum)
      {
        EnumMemberValue emv = new EnumMemberValue(cp);
    	emv.setType(((Enum<?>)mvValue).getClass().getName());
    	emv.setValue(((Enum<?>)mvValue).name());
        mv = emv;
      }
      else if(mvValue instanceof Float)
      {
        mv = new FloatMemberValue((Float)mvValue, cp);
      }
      else if(mvValue instanceof Integer)
      {
        IntegerMemberValue imv = new IntegerMemberValue(cp);
        imv.setValue(((Integer)mvValue).intValue());
        mv = imv;
      }
      else if(mvValue instanceof Long)
      {
        mv = new LongMemberValue((Long)mvValue, null);
      }
      else if(mvValue instanceof Short)
      {
        mv = new ShortMemberValue((Short)mvValue, null);
      }
      else if(mvValue.getClass().isArray() ) {
    	  ArrayMemberValue amv = new ArrayMemberValue(cp);
    	  MemberValue[] elements = new MemberValue[Array.getLength(mvValue)];
    	  for(int i=0;i<elements.length;i++) {
    		  elements[i] = getMemberValue(Array.get(mvValue, i), cp);
    	  }
    	  amv.setValue(elements);
    	  mv = amv;
      }
      else
      {
        throw new UnsupportedOperationException("Unknown object type: " + mvValue.getClass());
      }

	  return mv;
  }

  /**
   * Private method to add member values to annotation
   *
   * @param annotation
   * @param cp
   * @param memberValues
   */
  private static void addMemberValuesToAnnotation(Annotation annotation, ConstPool cp, LinkedHashMap<String, Object> memberValues)
  {
    // Get the member value object
    for(String mvName : memberValues.keySet())
    {
      Object mvValue = memberValues.get(mvName);
      MemberValue mv = getMemberValue(mvValue, cp);
      annotation.addMemberValue( mvName, mv );
    }
  }

  /**
   *
   * @param s
   * @return
   */
  public static String capitalize(String s)
  {
    return s.length() > 0 ? s.substring(0, 1).toUpperCase() + s.substring(1) : s;
  }

  /**
   *
   * @param s
   * @return
   */
  public static String decapitalize(String s)
  {
    return s.length() > 0 ? s.substring(0, 1).toLowerCase() + s.substring(1) : s;
  }

  public static void setClassPool(ClassPool classPool)
  {
    ClassGeneratorUtils.classPool = classPool;
  }

}


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

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;

import javax.slee.ActivityContextInterface;
import javax.slee.FactoryException;
import javax.slee.UnrecognizedActivityException;
import javax.slee.resource.ActivityHandle;
import javax.slee.resource.ResourceAdaptorTypeID;

import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.activity.ActivityContext;
import org.mobicents.slee.container.activity.ActivityContextHandle;
import org.mobicents.slee.container.management.ResourceManagementImpl;
import org.mobicents.slee.container.resource.ResourceAdaptorEntity;

/**
 * Implementation of the abstract resource adaptor aci factory code.
 *
 * @author martins
 *
 */
public class AbstractActivityContextInterfaceFactory implements Serializable {

	/**
	 *
	 */
	private static final long serialVersionUID = 1L;

	/**
	 *
	 */
	private transient SleeContainer sleeContainer;

	/**
	 *
	 */
	private final ResourceAdaptorTypeID resourceAdaptorTypeID;

	/**
	 *
	 * @param sleeContainer
	 * @param resourceAdaptorTypeID
	 */
	protected AbstractActivityContextInterfaceFactory(
			SleeContainer sleeContainer,
			ResourceAdaptorTypeID resourceAdaptorTypeID) {
		this.sleeContainer = sleeContainer;
		this.resourceAdaptorTypeID = resourceAdaptorTypeID;
	}

	/**
	 * This method returns the aci for the specified activity, if exists, it
	 * should be invoked by each impl of methods of an ra type aci factory.
	 *
	 * @param activity
	 * @return
	 * @throws NullPointerException
	 * @throws UnrecognizedActivityException
	 * @throws FactoryException
	 */
	protected ActivityContextInterface getACI(Object activity)
			throws NullPointerException, UnrecognizedActivityException,
			FactoryException {
		if (activity == null) {
			throw new NullPointerException("null activity object");
		}
		ActivityHandle handle = null;
		for (ResourceAdaptorEntity raEntity : sleeContainer
				.getResourceManagement().getResourceAdaptorEntitiesPerType(resourceAdaptorTypeID)) {
			handle = raEntity.getResourceAdaptorObject().getActivityHandle(
					activity);
			if (handle != null) {
				ActivityContextHandle ach = new ResourceAdaptorActivityContextHandleImpl(raEntity, handle);
				ActivityContext ac = sleeContainer.getActivityContextFactory()
						.getActivityContext(ach);
				if (ac != null) {
					return ac.getActivityContextInterface();
				}
				break;
			}
		}

		throw new UnrecognizedActivityException(activity.toString());
	}

	@Override
	public int hashCode() {
		return resourceAdaptorTypeID.hashCode();
	}

	@Override
	public boolean equals(Object obj) {
		if (obj != null && obj.getClass() == this.getClass()) {
			return ((AbstractActivityContextInterfaceFactory) obj).resourceAdaptorTypeID
					.equals(this.resourceAdaptorTypeID);
		} else {
			return false;
		}
	}

	private void readObject(ObjectInputStream is)
			throws ClassNotFoundException, IOException {
		is.defaultReadObject();
		sleeContainer = ResourceManagementImpl.getInstance().getSleeContainer();
	}

}


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

package org.mobicents.slee.container.component;

import java.io.File;
import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;

import javassist.LoaderClassPath;

import javax.slee.ComponentID;
import javax.slee.management.AlreadyDeployedException;
import javax.slee.management.ComponentDescriptor;
import javax.slee.management.DependencyException;
import javax.slee.management.DeploymentException;

import org.mobicents.slee.container.component.deployment.ClassPool;
import org.mobicents.slee.container.component.deployment.classloading.ComponentClassLoaderImpl;
import org.mobicents.slee.container.component.deployment.classloading.URLClassLoaderDomainImpl;
import org.mobicents.slee.container.component.du.DeployableUnit;
import org.mobicents.slee.container.component.security.PermissionHolder;

/**
 * Base class for a SLEE component, providing features related with class
 * loading, deployable unit and other component references
 *
 * @author martins
 *
 */
public abstract class AbstractSleeComponent implements SleeComponent {

	/**
	 * the component class loader
	 */
	private ComponentClassLoaderImpl classLoader;

	/**
	 * the class loader domain for the component jar this component belongs,
	 * components that depend on this component must add this in its domain
	 */
	private URLClassLoaderDomainImpl classLoaderDomain;

	/**
	 * the javassist class pool
	 */
	private ClassPool classPool;

	/**
	 * the DU the component belongs
	 */
	private DeployableUnit deployableUnit;

	/**
	 * where this component is deployed
	 */
	private File deploymentDir;

	/**
	 * the source for this component (component jar/service descriptor) in the
	 * deployable unit
	 */
	private String deploymentUnitSource;

	protected Set<PermissionHolder> permissions = new TreeSet<PermissionHolder>();

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.core.component.SleeComponent#getClassLoader()
	 */
	public ComponentClassLoaderImpl getClassLoader() {
		return classLoader;
	}

	/**
	 * Sets the component class loader
	 *
	 * @param classLoader
	 */
	public void setClassLoader(ComponentClassLoaderImpl classLoader) {
		this.classLoader = classLoader;
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.core.component.SleeComponent#getClassLoaderDomain()
	 */
	public URLClassLoaderDomainImpl getClassLoaderDomain() {
		return classLoaderDomain;
	}

	/**
	 * Sets the class loader domain for the component jar this component belongs
	 *
	 * @param classLoaderDomain
	 */
	public void setClassLoaderDomain(URLClassLoaderDomainImpl classLoaderDomain) {
		this.classLoaderDomain = classLoaderDomain;
	}

	/**
	 * Retrieves the component javassist class pool
	 *
	 * @return
	 */
	public ClassPool getClassPool() {
		if (classPool == null) {
			if (classLoader == null) {
				throw new IllegalStateException("can't init javassit classpool, there is no class loader set for the component");
			}
			classPool = new ClassPool();
			// add class path for domain and dependencies
			classPool.appendClassPath(new LoaderClassPath(classLoaderDomain));
			for(ClassLoader domainDependencies : classLoaderDomain.getAllDependencies()) {
				classPool.appendClassPath(new LoaderClassPath(domainDependencies));
			}
			// add class path also for slee
			classPool.appendClassPath(new LoaderClassPath(classLoaderDomain.getParent()));
		}
		return classPool;
	}

	/**
	 * Retrieves the file pointing to where this component is deployed
	 *
	 * @return
	 */
	public File getDeploymentDir() {
		return deploymentDir;
	}

	/**
	 * Sets the the file pointing where this component is deployed
	 *
	 * @param deploymentDir
	 */
	public void setDeploymentDir(File deploymentDir) {
		this.deploymentDir = deploymentDir;
	}

	/**
	 * Retrieves the source for this component (component jar/service
	 * descriptor) in the deployable unit
	 *
	 * @return
	 */
	public String getDeploymentUnitSource() {
		return deploymentUnitSource;
	}

	/**
	 * Sets the source for this component (component jar/service descriptor) in
	 * the deployable unit
	 *
	 * @param deploymentUnitSource
	 */
	public void setDeploymentUnitSource(String deploymentUnitSource) {
		this.deploymentUnitSource = deploymentUnitSource;
	}

	/**
	 * Retrieves the Deployable Unit this component belongs
	 *
	 * @return
	 */
	public DeployableUnit getDeployableUnit() {
		return deployableUnit;
	}

	/**
	 * Specifies the the Deployable Unit this component belongs. This method
	 * also sets the reverse relation, adding the component to the deployable
	 * unit
	 *
	 * @param deployableUnit
	 * @throws AlreadyDeployedException
	 *             if a component with same id already exists in the du
	 * @throws IllegalStateException
	 *             if this method is invoked and the deployable unit was already
	 *             set before
	 */
	public void setDeployableUnit(DeployableUnit deployableUnit)
			throws AlreadyDeployedException {
		if (this.deployableUnit != null) {
			throw new IllegalStateException(
					"deployable unit already set. du = " + this.deployableUnit);
		}
		this.deployableUnit = deployableUnit;
		if (!addToDeployableUnit()) {
			throw new AlreadyDeployedException(
					"unable to install du having multiple components with id "
							+ getComponentID());
		}
	}

	/**
	 * Gets set with permissions. This may be empty list in case of components that dont have them.
	 * In case of compoennts that can have xml-desc wide permissions - this set contains this permissions,
	 *  as does any other components set defined in that xml-descr. however impl of Policy MUST
	 *  handle double defined polic
	 * @return
	 */
	public Set<PermissionHolder> getPermissions() {
		return Collections.unmodifiableSet(this.permissions);
	}

	/**
	 * adds the component to the deployable unit
	 *
	 * @return true if the component was added
	 */
	public abstract boolean addToDeployableUnit();

	/**
	 * Retrieves the set of components IDs this component depends
	 *
	 * @return
	 */
	public abstract Set<ComponentID> getDependenciesSet();

	/**
	 * Retrieves the ID of this component
	 *
	 * @return
	 */
	public abstract ComponentID getComponentID();

	/**
	 * Indicates if the component is new to SLEE 1.1 specs
	 *
	 * @return
	 */
	public abstract boolean isSlee11();

	/**
	 * Validates the component.
	 *
	 * @return
	 * @throws DependencyException
	 * @throws DeploymentException
	 */
	public abstract boolean validate() throws DependencyException,
			DeploymentException;

	@Override
	public int hashCode() {
		return getComponentID().hashCode();
	}

	@Override
	public boolean equals(Object obj) {
		if (obj != null && obj.getClass() == this.getClass()) {
			return ((AbstractSleeComponent) obj).getComponentID().equals(
					this.getComponentID());
		} else {
			return false;
		}
	}

	@Override
	public String toString() {
		return getComponentID().toString();
	}

	/**
	 * Retrieves the JAIN SLEE specs component descriptor
	 *
	 * @return
	 */
	public abstract ComponentDescriptor getComponentDescriptor();

	public abstract void processSecurityPermissions() throws DeploymentException;

	/**
	 * Indicates that the component was undeployed and thus should clean up any resources
	 */
	public void undeployed() {

		classLoader = null;

		if (classLoaderDomain != null) {
			classLoaderDomain.clear();
			classLoaderDomain = null;
		}

		if (classPool != null) {
			classPool.clean();
			classPool = null;
		}

		if (permissions != null) {
			permissions.clear();
			permissions = null;
		}
	}

}


/*
 * TeleStax, Open Source Cloud Communications
 * Copyright 2011-2014, Telestax Inc and individual contributors
 * by the @authors tag.
 *
 * This program is free software: you can redistribute it and/or modify
 * under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 *
 * This file incorporates work covered by the following copyright contributed under the GNU LGPL : Copyright 2007-2011 Red Hat.
 */

package org.mobicents.slee.container.deployment.jboss;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.AbstractSleeContainerModule;
import org.mobicents.slee.container.deployment.ExternalDeployer;
import org.mobicents.slee.container.deployment.InternalDeployer;
import org.mobicents.slee.container.deployment.SleeContainerDeployer;
import org.mobicents.slee.util.concurrent.SleeThreadFactory;
import org.xml.sax.SAXException;

import javax.slee.management.DeployableUnitID;
import javax.slee.management.DeploymentException;
import javax.slee.management.DeploymentMBean;
import javax.slee.management.ManagementException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * The SLEE module responsible for persistent deployments. It complements the
 * JMX MBeans provided by the SLEE spec, providing "automated" (de)activations
 * of components in DUs, and is able to hold a deployment till all its
 * dependencies are deployed.
 *
 * @author martins
 *
 */
@SuppressWarnings("deprecation")
public class SleeContainerDeployerImpl extends AbstractSleeContainerModule
		implements InternalDeployer, SleeContainerDeployer {

	private final static Logger LOGGER = Logger
			.getLogger(SleeContainerDeployerImpl.class);

    private final static SleeThreadFactory SLEE_THREAD_FACTORY = new SleeThreadFactory("SLEE-InternalDeployer");

    // FIXME these two need to be merged
	private final SLEESubDeployer sleeSubDeployer = new SLEESubDeployer(this);
	private final DeploymentManager deploymentManager = new DeploymentManager(
			this);

	// the specs MBean used to install/uninstall DUs
	private DeploymentMBean deploymentMBean;

	// the external deployer, responsible for adapting the SLEE to the
	// underlying framework/app server
	private ExternalDeployer externalDeployer;

	private boolean shutdown;

	/**
	 *
	 * @return
	 */
	public ExternalDeployer getExternalDeployer() {
		return externalDeployer;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.deployment.InternalDeployer#setExternalDeployer
	 * (org.mobicents.slee.container.deployment.ExternalDeployer)
	 */
	public void setExternalDeployer(ExternalDeployer externalDeployer) {
		this.externalDeployer = externalDeployer;
	}

	/**
	 *
	 * @return
	 */
	public DeploymentMBean getDeploymentMBean() {
		return deploymentMBean;
	}

	/**
	 *
	 * @param deploymentMBean
	 */
	public void setDeploymentMBean(DeploymentMBean deploymentMBean) {
		this.deploymentMBean = deploymentMBean;
	}

	/**
	 *
	 * @return
	 */
	public DeploymentManager getDeploymentManager() {
		return deploymentManager;
	}

	/**
	 *
	 * @return
	 */
	public SLEESubDeployer getSleeSubDeployer() {
		return sleeSubDeployer;
	}

	@Override
	public void sleeInitialization() {
		// time to trigger the internal deployer
		Runnable r = new Runnable() {
			public void run() {

				// establish link with external deployer
				externalDeployer
						.setInternalDeployer(SleeContainerDeployerImpl.this);

				// lets do some log reporting
				deploymentManager.updateDeployedComponents();

				// log deployed DUs on DEBUG level
				if (LOGGER.isDebugEnabled()) {
					StringBuilder sb = new StringBuilder("Deployed SLEE DUs: ");
					DeployableUnitID[] deployedDUs = null;
					try {
						deployedDUs = deploymentMBean.getDeployableUnits();
					} catch (ManagementException e) {
						LOGGER.error(e.getMessage(), e);
					}
					if (deployedDUs == null || deployedDUs.length == 0) {
						sb.append('0');
					} else {
						for (DeployableUnitID deployedDU : deployedDUs) {
							sb.append("\n").append(deployedDU.getURL());
						}
					}
					LOGGER.debug(sb.toString());
				}

				// log DUs on hold, if exist, on WARN level

				Collection<DeployableUnit> waitingForInstallDUs = deploymentManager
						.getWaitingForInstallDUs();
				if (waitingForInstallDUs != null
						&& !waitingForInstallDUs.isEmpty()) {
					Set<DeployableUnit> dUsWaitingforDeps = new HashSet<DeployableUnit>();
					Set<DeployableUnit> dUsWithErrors = new HashSet<DeployableUnit>();
					for (DeployableUnit du : waitingForInstallDUs) {
						if (du.hasDependenciesSatisfied(false)) {
							dUsWithErrors.add(du);
						} else {
							dUsWaitingforDeps.add(du);
						}
					}
					if (!dUsWithErrors.isEmpty()) {
						StringBuilder sb = new StringBuilder(
								"SLEE DUs not deployed, due to error(s):");
						for (DeployableUnit du : dUsWithErrors) {
							sb.append("\n").append(du.getURL());
						}
						LOGGER.warn(sb.toString());
					}
					if (!dUsWaitingforDeps.isEmpty()) {
						StringBuilder sb = new StringBuilder(
								"SLEE DUs not deployed, due to missing dependencies:");
						for (DeployableUnit du : dUsWaitingforDeps) {
							sb.append("\n").append(du.getURL());
							sb.append("\n\tMissing Dependencies:");
							Collection<String> deps = du.getExternalDependencies();
							deps.removeAll(deploymentManager.getDeployedComponents());
							for (String dependency : deps) {
								sb.append("\n\t\t").append(dependency);
							}
						}
						LOGGER.warn(sb.toString());
					}

				}
			}
		};
		ExecutorService executorService = Executors.newSingleThreadExecutor(SLEE_THREAD_FACTORY);
		try {
			executorService.submit(r).get();
		} catch (Exception e) {
			LOGGER.error(e.getMessage(), e);
		}
		executorService.shutdown();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.AbstractSleeContainerModule#sleeShutdown()
	 */
	@Override
	public void sleeShutdown() {
		synchronized (this) {
			shutdown = true;
			// let the deployment manager know about that, it will undeploy DUs
			deploymentManager.sleeShutdown();
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.deployment.InternalDeployer#accepts(java
	 * .net.URL)
	 */
	public boolean accepts(URL deployableUnitURL, String deployableUnitName) {
		return sleeSubDeployer.accepts(deployableUnitURL, deployableUnitName);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.deployment.InternalDeployer#init(java.net
	 * .URL)
	 */
	public void init(URL deployableUnitURL, String deployableUnitName) throws DeploymentException {
		synchronized (this) {
			if (!shutdown) {
				sleeSubDeployer.init(deployableUnitURL, deployableUnitName);
			}
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.deployment.InternalDeployer#start(java.net
	 * .URL)
	 */
	public void start(URL deployableUnitURL, String deployableUnitName) throws DeploymentException {
		synchronized (this) {
			if (!shutdown) {
				sleeSubDeployer.start(deployableUnitURL, deployableUnitName);
			}
			else {
				if (LOGGER.isDebugEnabled())
					LOGGER.debug("Ignoring deploy invoked from external deployer, SLEE in shutdown");
			}
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.deployment.InternalDeployer#stop(java.net
	 * .URL)
	 */
	public void stop(URL deployableUnitURL, String deployableUnitName) throws DeploymentException {
		synchronized (this) {
			if (!shutdown) {
				sleeSubDeployer.stop(deployableUnitURL, deployableUnitName);
			}
			else {
				if (LOGGER.isDebugEnabled())
					LOGGER.debug("Ignoring undeploy invoked from external deployer, SLEE in shutdown");
			}
		}
	}

	public DeployConfigParser getSLEEDeployConfigParser() throws IOException, SAXException, ParserConfigurationException {
		File file = new File(sleeContainer.getDeployPath(), "deploy-config.xml");
		if(!file.exists() || file.isDirectory()) {
			return null;
		}
		FileInputStream in = new FileInputStream(file);
		try {
			return new DeployConfigParser(
						in,
						getSleeContainer()
								.getResourceManagement());
		} finally {
			in.close();
		}
	}
}


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

import java.util.HashSet;
import java.util.Set;

import javax.slee.EventTypeID;
import javax.slee.SbbID;
import javax.slee.ServiceID;
import javax.slee.UnrecognizedServiceException;
import javax.slee.facilities.FacilityException;
import javax.slee.facilities.ServiceLookupFacility;
import javax.slee.resource.ReceivableService;
import javax.slee.resource.ReceivableService.ReceivableEvent;

import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.component.ComponentRepository;
import org.mobicents.slee.container.component.sbb.EventEntryDescriptor;
import org.mobicents.slee.container.component.sbb.SbbComponent;
import org.mobicents.slee.container.component.service.ServiceComponent;
import org.mobicents.slee.container.resource.ResourceAdaptorEntity;

/**
 * Implementation of the SLEE 1.1 specs {@link ServiceLookupFacility} class.
 *
 * @author martins
 *
 */
public class ServiceLookupFacilityImpl implements ServiceLookupFacility {

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

	/**
	 * the ra entity
	 */
	private final ResourceAdaptorEntity raEntity;

	public ServiceLookupFacilityImpl(ResourceAdaptorEntity raEntity,SleeContainer container) {
		this.container = container;
		this.raEntity = raEntity;
	}

	public ReceivableService getReceivableService(ServiceID serviceID)
			throws NullPointerException, UnrecognizedServiceException,
			FacilityException {

		if (serviceID == null) {
			throw new NullPointerException("null ServiceID");
		}

		ServiceComponent serviceComponent = container
				.getComponentRepository().getComponentByID(serviceID);
		if (serviceComponent == null) {
			throw new UnrecognizedServiceException(serviceID.toString());
		}

		return createReceivableService(serviceComponent);

	}

	/**
	 * Creates a {@link ReceivableServiceImpl} instance from the specified
	 * service component
	 *
	 * @param serviceComponent
	 * @return
	 */
	private ReceivableService createReceivableService(
			ServiceComponent serviceComponent) {
		ComponentRepository componentRepository = container
				.getComponentRepository();
		HashSet<ReceivableEvent> resultSet = new HashSet<ReceivableEvent>();
		for (SbbID sbbID : serviceComponent.getSbbIDs(componentRepository)) {
			SbbComponent sbbComponent = componentRepository
					.getComponentByID(sbbID);
			for (EventEntryDescriptor eventEntry : sbbComponent.getDescriptor()
					.getEventEntries().values()) {
				EventTypeID eventTypeID = eventEntry.getEventReference();
				final Set<EventTypeID> allowedEventTypes = raEntity.getAllowedEventTypes();
				if (allowedEventTypes == null
						|| allowedEventTypes.contains(eventTypeID)) {
					/*
					 * The Service Lookup Facility will only return Service
					 * event type information forthe event types referenced by
					 * the resource adaptor types implemented by the Resource
					 * Adaptor.
					 */
					ReceivableEventImpl receivableEventImpl = new ReceivableEventImpl(
							eventTypeID, eventEntry.getResourceOption(),
							eventEntry.isInitialEvent());
					// add it if it's not in the set or if it is but initial
					// event is set (this way if there is a conflict the one
					// with initial as true wins)
					if (!resultSet.contains(receivableEventImpl)
							|| receivableEventImpl.isInitialEvent()) {
						resultSet.add(receivableEventImpl);
					}
				}
			}
		}
		return new ReceivableServiceImpl(serviceComponent.getServiceID(),
				resultSet.toArray(new ReceivableEventImpl[resultSet.size()]));
	}

}


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

import javax.slee.SLEEException;
import javax.slee.resource.ActivityFlags;
import javax.slee.resource.ActivityHandle;

import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.activity.ActivityContextHandle;
import org.mobicents.slee.container.transaction.SleeTransaction;

/**
 *
 * @author martins
 *
 */
public class SleeEndpointStartActivityNotTransactedExecutor extends
		SleeEndpointOperationNotTransactedExecutor {

	/**
	 *
	 * @param sleeContainer
	 * @param sleeEndpoint
	 */
	public SleeEndpointStartActivityNotTransactedExecutor(
			SleeContainer sleeContainer, SleeEndpointImpl sleeEndpoint) {
		super(sleeContainer, sleeEndpoint);
	}

	/**
	 * Executes a non transacted start activity operation.
	 * @param handle
	 * @param activityFlags
	 * @throws SLEEException
	 */
	void execute(final ActivityHandle handle, final int activityFlags, boolean suspendActivity)
			throws SLEEException {

		final SleeTransaction tx = super.suspendTransaction();
		ActivityContextHandle ach = null;
		try {
			ach = sleeEndpoint._startActivity(handle, activityFlags, suspendActivity ? tx : null);
		} finally {
			if (tx != null) {
				super.resumeTransaction(tx);
				// the activity was started out of the tx but it will be suspended, if the flags request the unreferenced callback then
				// we can load the ac now, which will schedule a check for references in the end of the tx, this ensures that the callback is received if no events are fired or
				// events are fired but not handled, that is, no reference is ever ever created
				if (ach != null && ActivityFlags.hasRequestSleeActivityGCCallback(activityFlags)) {
					acFactory.getActivityContext(ach);
				}
			}
		}
	}
}


package javax.slee.profile.query;

import java.io.Serializable;
import java.text.Collator;
import java.util.Locale;

/**
 * The QueryCollator class describes a collator that can be
 * used in dynamic profile queries in a Java serializable form.
 */
public final class QueryCollator implements Serializable {
    /**
     * Create a collator identified by locale only.  The collator uses the
     * default strength and decomposition for the locale.
     * @param locale the locale for which the collator should be obtained.
     * @throws NullPointerException if locale is null.
     */
    public QueryCollator(Locale locale) {
        this(locale, false, 0, false, 0);
    }

    /**
     * Create a collator for a given locale using the specified strength.
     * The collator uses the default decomposition for the locale.
     * @param locale the locale for which the collator should be obtained.
     * @param strength the strength of collator comparisions.  This must
     *        be one of {@link Collator#PRIMARY}, {@link Collator#SECONDARY},
     *        {@link Collator#TERTIARY}, or {@link Collator#IDENTICAL}.
     * @throws NullPointerException if locale is null.
     */
    public QueryCollator(Locale locale, int strength) {
        this(locale, true, strength, false, 0);
    }

    /**
     * Create a collator for a given locale using the specified strength
     * and decomposition.
     * @param locale the locale for which the collator should be obtained.
     * @param strength the strength of collator comparisions.  This must
     *        be one of {@link Collator#PRIMARY}, {@link Collator#SECONDARY},
     *        {@link Collator#TERTIARY}, or {@link Collator#IDENTICAL}.
     * @param decomposition the decomposition mode to use in the collator.
     *        This must be one of {@link Collator#NO_DECOMPOSITION},
     *        {@link Collator#CANONICAL_DECOMPOSITION}, or
     *        {@link Collator#FULL_DECOMPOSITION}.
     * @throws NullPointerException if locale is null.
     */
    public QueryCollator(Locale locale, int strength, int decomposition) {
        this(locale, true, strength, true, decomposition);
    }

    /**
     * Get the locale for this collator.
     * @return the locale for this collator.
     */
    public Locale getLocale() { return locale; }

    /**
     * Determine whether a collator strength has been defined for this collator.
     * @return true if a collator strength has been defined for this
     *        collator, false otherwise.
     */
    public boolean hasStrength() { return hasStrength; }

    /**
     * Get the collator strength specified for this collator.  The return value
     * only has meaning if {@link #hasStrength()} == true.
     * @return the collator strength specified for this collator.
     */
    public int getStrength() { return strength; }

    /**
     * Determine whether a decomposition mode has been defined for this collator.
     * @return true if a decomposition mode has been defined for this
     *        collator, false otherwise.
     */
    public boolean hasDecomposition() { return hasDecomposition; }

    /**
     * Get the decomposition mode specified for this collator.  The return value
     * only has meaning if {@link #hasDecomposition()} == true.
     * @return the decomposition mode specified for this collator.
     */
    public int getDecomposition() { return decomposition; }

    /**
     * Get the {@link Collator java.text.Collator} described by this
     * QueryCollator object.
     * @return the Collator described by this object.
     */
    public Collator getCollator() {
        if (collator == null) {
            collator = Collator.getInstance(locale);
            if (hasStrength) collator.setStrength(strength);
            if (hasDecomposition) collator.setDecomposition(decomposition);
        }
        return collator;
    }

    /**
     * Compare this query collator for equality with another object.
     * @param obj the object to compare this with.
     * @return true if obj is a QueryCollator
     *        with the same locale, strength, and decomposition properties as
     *        this, false otherwise.
     */
    public boolean equals(Object obj) {
        if (obj == this) return true;
        if (!(obj instanceof QueryCollator)) return false;

        QueryCollator that = (QueryCollator)obj;
        return this.locale.equals(that.locale)
            && this.hasStrength == that.hasStrength
            && this.strength == that.strength
            && this.hasDecomposition == that.hasDecomposition
            && this.decomposition == that.decomposition;
    }

    /**
     * Get a hash code value for this query collator.
     * @return as hash code.  The hash code is equal to the hash code of
     *        the collator's locale.
     */
    public int hashCode() {
        return locale.hashCode();
    }

    /**
     * Get a string representation for this query collator.
     * @return a string representation for this query collator.
     */
    public String toString() {
        StringBuffer buf = new StringBuffer();
        buf.append(locale);
        if (hasStrength) buf.append(":strength=").append(getStrengthString());
        if (hasDecomposition) buf.append(":decomposition=").append(getDecompositionString());
        return buf.toString();
    }

    // private

    private QueryCollator(Locale locale, boolean hasStrength, int strength, boolean hasDecomposition, int decomposition) {
        if (locale == null) throw new NullPointerException("locale is null");
        this.locale = locale;
        this.hasStrength = hasStrength;
        this.strength = strength;
        this.hasDecomposition = hasDecomposition;
        this.decomposition = decomposition;
    }

    private String getStrengthString() {
        switch (strength) {
            case Collator.PRIMARY: return "primary";
            case Collator.SECONDARY: return "secondary";
            case Collator.TERTIARY: return "tertiary";
            case Collator.IDENTICAL: return "identical";
            default: return "unknown";
        }
    }

    private String getDecompositionString() {
        switch (decomposition) {
            case Collator.NO_DECOMPOSITION: return "none";
            case Collator.CANONICAL_DECOMPOSITION: return "canonical";
            case Collator.FULL_DECOMPOSITION: return "full";
            default: return "unknown";
        }
    }

    private final Locale locale;
    private final boolean hasStrength;
    private final int strength;
    private final boolean hasDecomposition;
    private final int decomposition;
    private transient Collator collator;
}