/*
 * 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.Address;
import javax.slee.SLEEException;
import javax.slee.TransactionRequiredLocalException;
import javax.slee.resource.ActivityAlreadyExistsException;
import javax.slee.resource.ActivityFlags;
import javax.slee.resource.ActivityHandle;
import javax.slee.resource.ActivityIsEndingException;
import javax.slee.resource.EventFlags;
import javax.slee.resource.FireEventException;
import javax.slee.resource.FireableEventType;
import javax.slee.resource.IllegalEventException;
import javax.slee.resource.ReceivableService;
import javax.slee.resource.StartActivityException;
import javax.slee.resource.UnrecognizedActivityHandleException;
import javax.transaction.SystemException;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.activity.ActivityContext;
import org.mobicents.slee.container.activity.ActivityContextFactory;
import org.mobicents.slee.container.activity.ActivityContextHandle;
import org.mobicents.slee.container.activity.ActivityEventQueueManager;
import org.mobicents.slee.container.component.ComponentRepository;
import org.mobicents.slee.container.component.event.EventTypeComponent;
import org.mobicents.slee.container.event.EventProcessingFailedCallback;
import org.mobicents.slee.container.event.EventProcessingSucceedCallback;
import org.mobicents.slee.container.event.EventUnreferencedCallback;
import org.mobicents.slee.container.resource.ResourceAdaptorObjectState;
import org.mobicents.slee.container.resource.SleeEndpoint;
import org.mobicents.slee.container.transaction.SleeTransaction;
import org.mobicents.slee.container.transaction.SleeTransactionManager;
import org.mobicents.slee.container.transaction.TransactionContext;
import org.mobicents.slee.container.transaction.TransactionalAction;

/**
 *
 * Implementation of SLEE 1.1 {@link SleeEndpoint}
 *
 * @author Eduardo Martins
 */
public class SleeEndpointImpl implements SleeEndpoint {

	private final SleeTransactionManager txManager;
	private final ActivityContextFactory acFactory;
	private final ComponentRepository componentRepository;

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

	private final ResourceAdaptorEntityImpl raEntity;

	private final SleeEndpointFireEventNotTransactedExecutor fireEventNotTransactedExecutor;
	private final SleeEndpointStartActivityNotTransactedExecutor startActivityNotTransactedExecutor;
	private final SleeEndpointEndActivityNotTransactedExecutor endActivityNotTransactedExecutor;

	private final boolean doTraceLogs = logger.isTraceEnabled();

	public SleeEndpointImpl(ResourceAdaptorEntityImpl raEntity) {
		SleeContainer container = raEntity.getSleeContainer();
		this.txManager = container.getTransactionManager();
		this.acFactory = container.getActivityContextFactory();
		this.componentRepository = container.getComponentRepository();
		this.raEntity = raEntity;
		this.fireEventNotTransactedExecutor = new SleeEndpointFireEventNotTransactedExecutor(
				container, this);
		this.startActivityNotTransactedExecutor = new SleeEndpointStartActivityNotTransactedExecutor(
				container, this);
		this.endActivityNotTransactedExecutor = new SleeEndpointEndActivityNotTransactedExecutor(
				container, this);
	}

	/**
	 * @return the raEntity
	 */
	public ResourceAdaptorEntityImpl getRaEntity() {
		return raEntity;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.resource.SleeEndpoint#activityExists(javax
	 * .slee.resource.ActivityHandle)
	 */
	public boolean activityExists(ActivityHandle handle)
			throws IllegalStateException, NullPointerException, SLEEException {

		return activityExists(handle,true);
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.resource.SleeEndpoint#replicatedActivityExists(javax.slee.resource.ActivityHandle)
	 */
	public boolean replicatedActivityExists(ActivityHandle handle)
		throws IllegalStateException, NullPointerException, SLEEException {

		return activityExists(handle,false);
	}

	private boolean activityExists(ActivityHandle handle,boolean checkHandleRef)
		throws IllegalStateException, NullPointerException, SLEEException {

		if (handle == null)
			throw new NullPointerException("handle is null");

		// get ref handle if we are in cluster and the handle is to be not
		// replicated
		final ActivityHandle ah = checkHandleRef && raEntity.getHandleReferenceFactory() != null ? raEntity
				.getHandleReferenceFactory().getReferenceTransacted(handle)
				: handle;

		final ActivityContextHandle ach = new ResourceAdaptorActivityContextHandleImpl(
				raEntity, ah);

		return acFactory.activityContextExists(ach);

	}

	// --- ACTIVITY START

	/*
	 * (non-Javadoc)
	 *
	 * @seejavax.slee.resource.SleeEndpoint#startActivity(javax.slee.resource.
	 * ActivityHandle, java.lang.Object)
	 */
	public void startActivity(ActivityHandle handle, Object activity)
			throws NullPointerException, IllegalStateException,
			ActivityAlreadyExistsException, StartActivityException,
			SLEEException {
		startActivity(handle, activity, ActivityFlags.NO_FLAGS);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seejavax.slee.resource.SleeEndpoint#startActivity(javax.slee.resource.
	 * ActivityHandle, java.lang.Object, int)
	 */
	public void startActivity(final ActivityHandle handle, Object activity,
			final int activityFlags) throws NullPointerException,
			IllegalStateException, ActivityAlreadyExistsException,
			StartActivityException, SLEEException {

		if (doTraceLogs) {
			logger.trace("startActivity( handle = " + handle + " , activity = "
					+ activity + " , flags = " + activityFlags + " )");
		}

		checkStartActivityParameters(handle, activity);
		startActivityNotTransactedExecutor.execute(handle, activityFlags,false);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.resource.SleeEndpoint#startActivitySuspended(javax.slee.resource
	 * .ActivityHandle, java.lang.Object)
	 */
	public void startActivitySuspended(ActivityHandle handle, Object activity)
			throws NullPointerException, IllegalStateException,
			TransactionRequiredLocalException, ActivityAlreadyExistsException,
			StartActivityException, SLEEException {
		startActivitySuspended(handle, activity, ActivityFlags.NO_FLAGS);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.resource.SleeEndpoint#startActivitySuspended(javax.slee.resource
	 * .ActivityHandle, java.lang.Object, int)
	 */
	public void startActivitySuspended(ActivityHandle handle, Object activity,
			int activityFlags) throws NullPointerException,
			IllegalStateException, TransactionRequiredLocalException,
			ActivityAlreadyExistsException, StartActivityException,
			SLEEException {

		if (doTraceLogs) {
			logger.trace("startActivitySuspended( handle = " + handle
					+ " , activity = " + activity + " , flags = "
					+ activityFlags + " )");
		}

		// need to check tx before doing out of tx scope activity start
		txManager.mandateTransaction();
		checkStartActivityParameters(handle, activity);
		startActivityNotTransactedExecutor.execute(handle, activityFlags,true);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.resource.SleeEndpoint#startActivityTransacted(javax.slee.resource
	 * .ActivityHandle, java.lang.Object)
	 */
	public void startActivityTransacted(ActivityHandle handle, Object activity)
			throws NullPointerException, IllegalStateException,
			TransactionRequiredLocalException, ActivityAlreadyExistsException,
			StartActivityException, SLEEException {
		startActivityTransacted(handle, activity, ActivityFlags.NO_FLAGS);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.resource.SleeEndpoint#startActivityTransacted(javax.slee.resource
	 * .ActivityHandle, java.lang.Object, int)
	 */
	public void startActivityTransacted(ActivityHandle handle, Object activity,
			int activityFlags) throws NullPointerException,
			IllegalStateException, TransactionRequiredLocalException,
			ActivityAlreadyExistsException, StartActivityException,
			SLEEException {

		if (doTraceLogs) {
			logger.trace("startActivityTransacted( handle = " + handle
					+ " , activity = " + activity + " , flags = "
					+ activityFlags + " )");
		}

		checkStartActivityParameters(handle, activity);
		// check tx state
		txManager.mandateTransaction();
		_startActivity(handle, activityFlags,null);
	}

	/**
	 * Checks the parameters of startActivity* methods
	 *
	 * @param handle
	 * @param activity
	 * @throws NullPointerException
	 * @throws IllegalStateException
	 */
	private void checkStartActivityParameters(ActivityHandle handle,
			Object activity) throws NullPointerException, IllegalStateException {

		// check args
		if (handle == null) {
			throw new NullPointerException("null handle");
		}
		if (activity == null) {
			throw new NullPointerException("null activity");
		}
		// check ra state
		if (raEntity.getResourceAdaptorObject().getState() != ResourceAdaptorObjectState.ACTIVE) {
			throw new IllegalStateException("ra is in state "
					+ raEntity.getResourceAdaptorObject().getState());
		}
	}

	/**
	 * Start activity logic, independent of transaction management.
	 * @param handle
	 * @param activityFlags
	 * @param barrierTx
	 * @return
	 */
	ActivityContextHandle _startActivity(ActivityHandle handle,
			int activityFlags, final SleeTransaction barrierTx) {

		ActivityContext ac = null;
		if (raEntity.getHandleReferenceFactory() != null
				&& !ActivityFlags.hasSleeMayMarshal(activityFlags)) {
			final ActivityHandleReference reference = raEntity
					.getHandleReferenceFactory().createActivityHandleReference(
							handle);
			try {
				// create activity context with ref instead
				ac = acFactory.createActivityContext(
						new ResourceAdaptorActivityContextHandleImpl(raEntity,
								reference), activityFlags);
			} catch (ActivityAlreadyExistsException e) {
				throw e;
			} catch (RuntimeException e) {
				raEntity.getHandleReferenceFactory()
						.removeActivityHandleReference(reference);
				throw e;
			}
		} else {
			// create activity context
			ac = acFactory.createActivityContext(
					new ResourceAdaptorActivityContextHandleImpl(raEntity,
							handle), activityFlags);
		}
		// suspend activity if needed
		if (barrierTx != null && ac != null) {
			final ActivityEventQueueManager aeqm = ac.getLocalActivityContext().getEventQueueManager();
			aeqm.createBarrier(barrierTx);
			TransactionalAction action = new TransactionalAction() {
				public void execute() {
					aeqm.removeBarrier(barrierTx);
				}
			};
			final TransactionContext tc = barrierTx.getTransactionContext();
			tc.getAfterCommitActions().add(action);
			tc.getAfterRollbackActions().add(action);
		}
		return ac.getActivityContextHandle();
	}

	// --- ACTIVITY END

	/*
	 * (non-Javadoc)
	 *
	 * @seejavax.slee.resource.SleeEndpoint#endActivity(javax.slee.resource.
	 * ActivityHandle)
	 */
	public void endActivity(ActivityHandle handle) throws NullPointerException,
			UnrecognizedActivityHandleException {
		endActivity(handle, true);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.resource.SleeEndpoint#endReplicatedActivity
	 * (javax.slee.resource.ActivityHandle)
	 */
	public void endReplicatedActivity(ActivityHandle handle)
			throws NullPointerException, UnrecognizedActivityHandleException {
		endActivity(handle, false);
	}

	private void endActivity(final ActivityHandle handle, boolean checkHandleRef)
			throws NullPointerException, UnrecognizedActivityHandleException {

		if (doTraceLogs) {
			logger.trace("endActivity( handle = " + handle + " )");
		}

		if (handle == null)
			throw new NullPointerException("handle is null");

		// get ref handle if we are in cluster and the handle is to be not
		// replicated
		final ActivityHandle ah = checkHandleRef
				&& raEntity.getHandleReferenceFactory() != null ? raEntity
				.getHandleReferenceFactory().getReference(handle) : handle;
		endActivityNotTransactedExecutor.execute(ah);

	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.resource.SleeEndpoint#endActivityTransacted(javax.slee.resource
	 * .ActivityHandle)
	 */
	public void endActivityTransacted(ActivityHandle handle)
			throws NullPointerException, TransactionRequiredLocalException,
			UnrecognizedActivityHandleException {

		endActivityTransacted(handle, true);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.container.resource.SleeEndpoint#
	 * endReplicatedActivityTransacted(javax.slee.resource.ActivityHandle)
	 */
	public void endReplicatedActivityTransacted(ActivityHandle handle)
			throws NullPointerException, TransactionRequiredLocalException,
			UnrecognizedActivityHandleException {

		endActivityTransacted(handle, false);
	}

	private void endActivityTransacted(ActivityHandle handle,
			boolean checkHandleRef) throws NullPointerException,
			TransactionRequiredLocalException,
			UnrecognizedActivityHandleException {

		if (doTraceLogs) {
			logger.trace("endActivityTransacted( handle = " + handle + " )");
		}

		if (handle == null)
			throw new NullPointerException("handle is null");

		txManager.mandateTransaction();

		// get ref handle if we are in cluster and the handle is to be not
		// replicated
		final ActivityHandle ah = checkHandleRef
				&& raEntity.getHandleReferenceFactory() != null ? raEntity
				.getHandleReferenceFactory().getReferenceTransacted(handle)
				: handle;

		_endActivity(ah,null);
	}

	/**
	 * End activity logic independent of transaction management.
	 * @param handle
	 * @param barrierTx
	 * @throws UnrecognizedActivityHandleException
	 */
	void _endActivity(ActivityHandle handle, final SleeTransaction barrierTx)
			throws UnrecognizedActivityHandleException {
		final ActivityContextHandle ach = new ResourceAdaptorActivityContextHandleImpl(
				raEntity, handle);
		// get ac
		final ActivityContext ac = acFactory.getActivityContext(ach);
		if (ac != null) {
			// suspend activity if needed
			if (barrierTx != null) {
				final ActivityEventQueueManager aeqm = ac.getLocalActivityContext().getEventQueueManager();
				aeqm.createBarrier(barrierTx);
				TransactionalAction action = new TransactionalAction() {
					public void execute() {
						aeqm.removeBarrier(barrierTx);
					}
				};
				final TransactionContext tc = barrierTx.getTransactionContext();
				tc.getAfterCommitActions().add(action);
				tc.getAfterRollbackActions().add(action);
			}
			// end the activity
			ac.endActivity();
		} else {
			throw new UnrecognizedActivityHandleException(handle.toString());
		}
	}

	// EVENT FIRING

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.resource.SleeEndpoint#fireEvent(javax.slee.resource.ActivityHandle
	 * , javax.slee.resource.FireableEventType, java.lang.Object,
	 * javax.slee.Address, javax.slee.resource.ReceivableService)
	 */
	public void fireEvent(ActivityHandle handle, FireableEventType eventType,
			Object event, Address address, ReceivableService receivableService)
			throws NullPointerException, UnrecognizedActivityHandleException,
			IllegalEventException, ActivityIsEndingException,
			FireEventException, SLEEException {
		fireEvent(handle, eventType, event, address, receivableService,
				EventFlags.NO_FLAGS, true);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.container.resource.SleeEndpoint#
	 * fireEventOnReplicatedActivity(javax.slee.resource.ActivityHandle,
	 * javax.slee.resource.FireableEventType, java.lang.Object,
	 * javax.slee.Address, javax.slee.resource.ReceivableService)
	 */
	public void fireEventOnReplicatedActivity(ActivityHandle handle,
			FireableEventType eventType, Object event, Address address,
			ReceivableService receivableService) throws NullPointerException,
			UnrecognizedActivityHandleException, IllegalEventException,
			ActivityIsEndingException, FireEventException, SLEEException {
		fireEvent(handle, eventType, event, address, receivableService,
				EventFlags.NO_FLAGS, false);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.resource.SleeEndpoint#fireEvent(javax.slee.resource.ActivityHandle
	 * , javax.slee.resource.FireableEventType, java.lang.Object,
	 * javax.slee.Address, javax.slee.resource.ReceivableService, int)
	 */
	public void fireEvent(final ActivityHandle handle,
			final FireableEventType eventType, final Object event,
			final Address address, final ReceivableService receivableService,
			final int eventFlags) throws NullPointerException,
			UnrecognizedActivityHandleException, IllegalEventException,
			ActivityIsEndingException, FireEventException, SLEEException {

		fireEvent(handle, eventType, event, address, receivableService,
				eventFlags, true);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.container.resource.SleeEndpoint#
	 * fireEventOnReplicatedActivity(javax.slee.resource.ActivityHandle,
	 * javax.slee.resource.FireableEventType, java.lang.Object,
	 * javax.slee.Address, javax.slee.resource.ReceivableService, int)
	 */
	public void fireEventOnReplicatedActivity(ActivityHandle handle,
			FireableEventType eventType, Object event, Address address,
			ReceivableService receivableService, int eventFlags)
			throws NullPointerException, UnrecognizedActivityHandleException,
			IllegalEventException, ActivityIsEndingException,
			FireEventException, SLEEException {

		fireEvent(handle, eventType, event, address, receivableService,
				eventFlags, false);
	}

	private void fireEvent(ActivityHandle handle, FireableEventType eventType,
			Object event, Address address, ReceivableService receivableService,
			int eventFlags, boolean checkHandleRef)
			throws NullPointerException, UnrecognizedActivityHandleException,
			IllegalEventException, ActivityIsEndingException,
			FireEventException, SLEEException {

		if (doTraceLogs) {
			logger.trace("fireEvent( handle = " + handle + " , eventType = "
					+ eventType + " , event = " + event + " , address = "
					+ address + " , service = " + receivableService
					+ " , flags = " + eventFlags + " )");
		}

		checkFireEventPreconditions(handle, eventType, event);

		// get ref handle if we are in cluster and the handle is to be not
		// replicated
		final ActivityHandle refHandle = checkHandleRef
				&& raEntity.getHandleReferenceFactory() != null ? raEntity
				.getHandleReferenceFactory().getReference(handle) : handle;

		fireEventNotTransactedExecutor.execute(handle, refHandle, eventType,
				event, address, receivableService, eventFlags);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.resource.SleeEndpoint#fireEventTransacted(javax.slee.resource
	 * .ActivityHandle, javax.slee.resource.FireableEventType, java.lang.Object,
	 * javax.slee.Address, javax.slee.resource.ReceivableService)
	 */
	public void fireEventTransacted(ActivityHandle handle,
			FireableEventType eventType, Object event, Address address,
			ReceivableService receivableService) throws NullPointerException,
			UnrecognizedActivityHandleException, IllegalEventException,
			TransactionRequiredLocalException, ActivityIsEndingException,
			FireEventException, SLEEException {
		fireEventTransacted(handle, eventType, event, address,
				receivableService, EventFlags.NO_FLAGS, true);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.container.resource.SleeEndpoint#
	 * fireEventTransactedOnReplicatedActivity
	 * (javax.slee.resource.ActivityHandle,
	 * javax.slee.resource.FireableEventType, java.lang.Object,
	 * javax.slee.Address, javax.slee.resource.ReceivableService)
	 */
	public void fireEventTransactedOnReplicatedActivity(ActivityHandle handle,
			FireableEventType eventType, Object event, Address address,
			ReceivableService receivableService) throws NullPointerException,
			UnrecognizedActivityHandleException, IllegalEventException,
			TransactionRequiredLocalException, ActivityIsEndingException,
			FireEventException, SLEEException {
		fireEventTransacted(handle, eventType, event, address,
				receivableService, EventFlags.NO_FLAGS, false);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.resource.SleeEndpoint#fireEventTransacted(javax.slee.resource
	 * .ActivityHandle, javax.slee.resource.FireableEventType, java.lang.Object,
	 * javax.slee.Address, javax.slee.resource.ReceivableService, int)
	 */
	public void fireEventTransacted(ActivityHandle handle,
			FireableEventType eventType, Object event, Address address,
			ReceivableService receivableService, int eventFlags)
			throws NullPointerException, UnrecognizedActivityHandleException,
			IllegalEventException, TransactionRequiredLocalException,
			ActivityIsEndingException, FireEventException, SLEEException {

		fireEventTransacted(handle, eventType, event, address,
				receivableService, eventFlags, true);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.container.resource.SleeEndpoint#
	 * fireEventTransactedOnReplicatedActivity
	 * (javax.slee.resource.ActivityHandle,
	 * javax.slee.resource.FireableEventType, java.lang.Object,
	 * javax.slee.Address, javax.slee.resource.ReceivableService, int)
	 */
	public void fireEventTransactedOnReplicatedActivity(ActivityHandle handle,
			FireableEventType eventType, Object event, Address address,
			ReceivableService receivableService, int eventFlags)
			throws NullPointerException, UnrecognizedActivityHandleException,
			IllegalEventException, TransactionRequiredLocalException,
			ActivityIsEndingException, FireEventException, SLEEException {

		fireEventTransacted(handle, eventType, event, address,
				receivableService, eventFlags, false);
	}

	private void fireEventTransacted(ActivityHandle handle,
			FireableEventType eventType, Object event, Address address,
			ReceivableService receivableService, int eventFlags,
			boolean checkHandleRef) throws NullPointerException,
			UnrecognizedActivityHandleException, IllegalEventException,
			TransactionRequiredLocalException, ActivityIsEndingException,
			FireEventException, SLEEException {

		if (doTraceLogs) {
			logger.trace("fireEventTransacted( handle = " + handle
					+ " , eventType = " + eventType + " , event = " + event
					+ " , address = " + address + " , service = "
					+ receivableService + " , flags = " + eventFlags + " )");
		}

		checkFireEventPreconditions(handle, eventType, event);
		txManager.mandateTransaction();

		// get ref handle if we are in cluster and the handle is to be not
		// replicated
		final ActivityHandle refHandle = checkHandleRef
				&& raEntity.getHandleReferenceFactory() != null ? raEntity
				.getHandleReferenceFactory().getReferenceTransacted(handle)
				: handle;

		_fireEvent(handle, refHandle, eventType, event, address,
				receivableService, eventFlags,null);
	}

	/**
	 * Checks that fire event methods can be invoked
	 *
	 * @param handle
	 * @param eventType
	 * @param event
	 * @throws NullPointerException
	 * @throws IllegalEventException
	 * @throws IllegalStateException
	 */
	private void checkFireEventPreconditions(ActivityHandle handle,
			FireableEventType eventType, Object event)
			throws NullPointerException, IllegalEventException,
			IllegalStateException {

		if (event == null)
			throw new NullPointerException("event is null");

		if (handle == null)
			throw new NullPointerException("handle is null");

		if (eventType == null) {
			throw new NullPointerException("eventType is null");
		}
		final EventTypeComponent eventTypeComponent = componentRepository
				.getComponentByID(eventType.getEventType());
		if (eventTypeComponent == null) {
			throw new IllegalEventException(
					"event type not installed (more on SLEE 1.1 specs 15.14.8)");
		}

		if (!eventTypeComponent.getEventTypeClass().isAssignableFrom(
				event.getClass())) {
			throw new IllegalEventException(
					"the class of the event object fired is not assignable to the event class of the event type (more on SLEE 1.1 specs 15.14.8) ");
		}

		if (eventType.getClass() != FireableEventTypeImpl.class) {
			throw new IllegalEventException(
					"unknown implementation of FireableEventType");
		}

		if (raEntity.getAllowedEventTypes() != null
				&& !raEntity.getAllowedEventTypes().contains(
						eventType.getEventType())) {
			throw new IllegalEventException(
					"Resource Adaptor configured to not ignore ra type event checking and the event "
							+ eventType.getEventType()
							+ " does not belongs to any of the ra types implemented by the resource adaptor");
		}
	}

	/**
	 * Event firing logic independent of transaction management.
	 *
	 * @param realHandle
	 * @param refHandle
	 * @param eventType
	 * @param event
	 * @param address
	 * @param receivableService
	 * @param eventFlags
	 * @param barrierTx
	 * @throws ActivityIsEndingException
	 * @throws SLEEException
	 */
	void _fireEvent(ActivityHandle realHandle, ActivityHandle refHandle,
			FireableEventType eventType, Object event, Address address,
			ReceivableService receivableService, int eventFlags, final SleeTransaction barrierTx)
			throws ActivityIsEndingException, SLEEException {
		final ActivityContextHandle ach = new ResourceAdaptorActivityContextHandleImpl(
				raEntity, refHandle);
		// get ac
		final ActivityContext ac = acFactory.getActivityContext(ach);
		if (ac == null) {
			throw new UnrecognizedActivityHandleException("Unable to fire "
					+ eventType.getEventType() + " on activity handle "
					+ realHandle
					+ " , the handle is not mapped to an activity context");
		} else {
			// suspend activity if needed
			if (barrierTx != null) {
				final ActivityEventQueueManager aeqm = ac.getLocalActivityContext().getEventQueueManager();
				aeqm.createBarrier(barrierTx);
				TransactionalAction action = new TransactionalAction() {
					public void execute() {
						aeqm.removeBarrier(barrierTx);
					}
				};
				final TransactionContext tc = barrierTx.getTransactionContext();
				tc.getAfterCommitActions().add(action);
				tc.getAfterRollbackActions().add(action);
			}
			final EventProcessingCallbacks callbacks = new EventProcessingCallbacks(
					realHandle, eventType, event, address, receivableService,
					eventFlags, raEntity);
			final EventProcessingSucceedCallback succeedCallback = EventFlags
					.hasRequestProcessingSuccessfulCallback(eventFlags) ? callbacks
					: null;
			final EventProcessingFailedCallback failedCallback = EventFlags
					.hasRequestProcessingFailedCallback(eventFlags) ? callbacks
					: null;
			final EventUnreferencedCallback unreferencedCallback = EventFlags
					.hasRequestEventReferenceReleasedCallback(eventFlags) ? callbacks
					: null;
			ac.fireEvent(eventType.getEventType(), event, address,
					receivableService == null ? null : receivableService
							.getService(), succeedCallback, failedCallback,
					unreferencedCallback);
		}
	}

	// OTHER ...

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.resource.SleeEndpoint#suspendActivity(javax.slee.resource.
	 * ActivityHandle)
	 */
	public void suspendActivity(ActivityHandle handle)
			throws NullPointerException, TransactionRequiredLocalException,
			UnrecognizedActivityHandleException, SLEEException {

		suspendActivity(handle, true);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.resource.SleeEndpoint#suspendReplicatedActivity
	 * (javax.slee.resource.ActivityHandle)
	 */
	public void suspendReplicatedActivity(ActivityHandle handle)
			throws NullPointerException, TransactionRequiredLocalException,
			UnrecognizedActivityHandleException, SLEEException {

		suspendActivity(handle, false);
	}

	private void suspendActivity(ActivityHandle handle, boolean checkHandleRef)
			throws NullPointerException, TransactionRequiredLocalException,
			UnrecognizedActivityHandleException, SLEEException {

		if (doTraceLogs) {
			logger.trace("suspendActivity( handle = " + handle + " )");
		}

		if (handle == null)
			throw new NullPointerException("handle is null");

		txManager.mandateTransaction();

		// get ref handle if we are in cluster and the handle is to be not
		// replicated
		final ActivityHandle ah = checkHandleRef
				&& raEntity.getHandleReferenceFactory() != null ? raEntity
				.getHandleReferenceFactory().getReferenceTransacted(handle)
				: handle;

		final ActivityContextHandle ach = new ResourceAdaptorActivityContextHandleImpl(
				raEntity, ah);

		// get ac
		final ActivityContext ac = acFactory.getActivityContext(ach);
		if (ac != null) {
			try {
				// suspend activity
				final SleeTransaction tx = txManager.getTransaction();
				final ActivityEventQueueManager eventQueue = ac
						.getLocalActivityContext().getEventQueueManager();
				eventQueue.createBarrier(tx);
				TransactionalAction action = new TransactionalAction() {
					public void execute() {
						eventQueue.removeBarrier(tx);
					}
				};
				final TransactionContext tc = tx.getTransactionContext();
				tc.getAfterCommitActions().add(action);
				tc.getAfterRollbackActions().add(action);
			} catch (SystemException e) {
				throw new SLEEException(e.getMessage(), e);
			}
		} else {
			throw new UnrecognizedActivityHandleException(handle.toString());
		}
	}

}


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

package org.mobicents.slee.container.deployment;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;

import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.NotFoundException;

import org.apache.log4j.Logger;
import org.mobicents.slee.SbbLocalObjectExt;
import org.mobicents.slee.container.component.ClassPool;
import org.mobicents.slee.runtime.sbb.SbbConcrete;
import org.mobicents.slee.runtime.sbb.SbbLocalObjectConcrete;
import org.mobicents.slee.runtime.sbb.SbbLocalObjectImpl;

/**
 * Class generating the concrete Sbb local object class
 *
 * @author DERUELLE Jean <a
 *         href="mailto:jean.deruelle@gmail.com">jean.deruelle@gmail.com </a>
 * @author martins
 */
public class ConcreteSbbLocalObjectGenerator {

    /**
     * Logger to log information
     */
    private static final Logger logger = Logger.getLogger(ConcreteSbbLocalObjectGenerator.class);

    private final String sbbLocalObjectName;

    private final String sbbAbstractClassName;

    private final String deployPath;

    /**
     * Pool to generate or read classes with javassist
     */
    private final ClassPool pool;

    /**
     *
     */
    protected CtClass sleeSbbLocalObject = null;

    /**
     * The interface from which to generate the concrete class
     */
    protected CtClass sbbLocalObjectInterface = null;

    /**
     * The concrete sbb local object class
     */
    protected CtClass concreteSbbLocalObject = null;

    public ConcreteSbbLocalObjectGenerator(String sbbLocalObjectName, String sbbAbstractClassName, String deployPath,
            ClassPool pool) {
        this.sbbLocalObjectName = sbbLocalObjectName;
        this.sbbAbstractClassName = sbbAbstractClassName;
        this.deployPath = deployPath;
        this.pool = pool;
    }

    /**
     * Generate the Sbb Local Object Class
     *
     * @param sbbLocalObjectName
     *            the name of the Sbb Local Object
     * @return the concrete Sbb Local Object class implementing the Sbb Local
     *         Object
     */
    public Class generateSbbLocalObjectConcreteClass() {
        //Generates the implements link
        if (logger.isTraceEnabled()) {
            logger.trace("generateSbbLocalObjectConcreteClass: sbbLocalObjectInterface = "
                            + sbbLocalObjectName
                            + " deployPath = "
                            + deployPath);
        }

        try {

        	concreteSbbLocalObject = pool.makeClass(ConcreteClassGeneratorUtils.SBB_LOCAL_OBJECT_CLASS_NAME_PREFIX + sbbLocalObjectName + ConcreteClassGeneratorUtils.SBB_LOCAL_OBJECT_CLASS_NAME_SUFFIX);

            try {
                sleeSbbLocalObject = pool.get(SbbLocalObjectImpl.class
                        .getName());
                sbbLocalObjectInterface = pool.get(sbbLocalObjectName);
            } catch (NotFoundException nfe) {
                nfe.printStackTrace();
                String s = "Problem with pool ";
                logger.error(s, nfe);
                throw new RuntimeException(s, nfe);
            }
            // This is our implementation interface.
            CtClass concreteClassInterface;
            try {
                concreteClassInterface = pool.get(SbbLocalObjectConcrete.class
                        .getName());
            } catch (NotFoundException nfe) {
                nfe.printStackTrace();
                String s = "Problem with the pool! ";
                logger.error(s, nfe);
                throw new RuntimeException(s, nfe);
            }

            ConcreteClassGeneratorUtils.createInterfaceLinks(
                    concreteSbbLocalObject, new CtClass[] {
                            sbbLocalObjectInterface, concreteClassInterface });
            //Generates an inheritance link to the slee implementation of the
            // SbbLocalObject interface
            ConcreteClassGeneratorUtils.createInheritanceLink(
                    concreteSbbLocalObject, sleeSbbLocalObject);

            //Generates the methods to implement from the interface

            Map interfaceMethods = ClassUtils
                    .getInterfaceMethodsFromInterface(sbbLocalObjectInterface);

            generateConcreteMethods(interfaceMethods, sbbAbstractClassName);

            try {
            	concreteSbbLocalObject.writeFile(deployPath);
            	if (logger.isDebugEnabled()) {
                    logger
                        .debug("Concrete Class "
                                + concreteSbbLocalObject.getName()
                                + " generated in the following path "
                                + deployPath);
                }
            } catch (CannotCompileException e) {

                String s = " Unexpected exception ! ";
                logger.fatal(s, e);
                throw new RuntimeException(s, e);

            } catch (IOException e) {
                String s = "IO Exception!";
                logger.error(s, e);
                return null;

            }
            //load the class
            try {
				return Thread.currentThread().getContextClassLoader().loadClass(concreteSbbLocalObject.getName());
			} catch (ClassNotFoundException e) {
				logger.error("unable to load sbb local object impl class", e);
				return null;
			}

        } finally {
            if (this.concreteSbbLocalObject != null)
                this.concreteSbbLocalObject.defrost();
        }
    }

    /**
     * Generates the concrete methods of the class
     *
     * @param interfaceMethods
     *            the methods to implement coming from the
     *            ActivityContextInterface developer
     * @param sbbAbstractClassName
     */
    private void generateConcreteMethods(Map interfaceMethods,
            String sbbAbstractClassName) {
        if (interfaceMethods == null)
            return;

        Iterator it = interfaceMethods.values().iterator();
        while (it.hasNext()) {
            CtMethod interfaceMethod = (CtMethod) it.next();
            if (interfaceMethod == null)
                return;

            // The following methods are implemented in the superclass

            if (interfaceMethod.getName().equals("isIdentical")
            		|| interfaceMethod.getName().equals("equals")
            		|| interfaceMethod.getName().equals("hashCode")
            		|| interfaceMethod.getName().equals("getSbbPriority")
                    || interfaceMethod.getName().equals("remove")
                    || interfaceMethod.getName().equals("setSbbPriority")
                	|| interfaceMethod.getName().equals("getName")
            		|| interfaceMethod.getName().equals("getChildRelation")
            		|| interfaceMethod.getName().equals("getParent"))
                continue;

            String methodToAdd = "public ";
            //Add the return type
            boolean hasReturn = false;
            CtClass returnType = null;
            try {
                // There's probably a more elegant way to do this.
                returnType = interfaceMethod.getReturnType();
                if (returnType.equals(CtClass.voidType)) {
                    methodToAdd += "void ";
                } else {
                    methodToAdd = methodToAdd
                            .concat(returnType.getName() + " ");
                    hasReturn = true;
                }
            } catch (NotFoundException nfe) {
                nfe.printStackTrace();
                methodToAdd = methodToAdd + "void ";
            }
            //Add the method name
            methodToAdd += interfaceMethod.getName() + "(";
            //Add the parameters
            CtClass[] parameterTypes = null;
            ;
            try {
                parameterTypes = interfaceMethod.getParameterTypes();
                for (int argNumber = 0; argNumber < parameterTypes.length; argNumber++) {
                    methodToAdd = methodToAdd.concat(parameterTypes[argNumber]
                            .getName()
                            + " arg_" + argNumber);
                    if (argNumber + 1 < parameterTypes.length)
                        methodToAdd = methodToAdd + ",";
                }
            } catch (NotFoundException nfe) {
                nfe.printStackTrace();
                throw new RuntimeException("unexpected Exception ! ", nfe);
            }
            methodToAdd = methodToAdd + ") { ";

            // We need to do this in a type neutral way !
            methodToAdd += SbbConcrete.class.getName() + " concrete = "
                    + " getSbbEntity().getSbbObject().getSbbConcrete();";

            //These methods are delegated to superclass.
            // Note the convoluted code here because finally is not supported
            // yet by javaassist.

            methodToAdd += "Object[] args = new Object ["
                    + parameterTypes.length + "];";

            methodToAdd += "Class[] types = new Class ["
                    + parameterTypes.length + "];";

            if (parameterTypes != null && parameterTypes.length > 0) {
                for (int argNumber = 0; argNumber < parameterTypes.length; argNumber++) {
                    methodToAdd += "args[" + argNumber + "]  = ";
                    // Check if parameter type is primitive and add the wrapper
                    // types.
                    if (parameterTypes[argNumber].isPrimitive()) {
                        CtClass ptype = parameterTypes[argNumber];
                        if (ptype.equals(CtClass.intType)) {
                            methodToAdd += "Integer.valueOf(" + "arg_" + argNumber
                                    + ");";
                        } else if (ptype.equals(CtClass.booleanType)) {
                            methodToAdd += "Boolean.valueOf(" + "arg_" + argNumber
                                    + ");";
                        } else if (ptype.equals(CtClass.longType)) {
                            methodToAdd += "Long.valueOf(" + "arg_" + argNumber
                                    + ");";
                        } else if (ptype.equals(CtClass.shortType)) {
                            methodToAdd += "Short.valueOf(" + "arg_" + argNumber
                                    + ");";
                        } else if (ptype.equals(CtClass.floatType)) {
                            methodToAdd += "Float.valueOf(" + "arg_" + argNumber
                                    + ");";
                        } else if (ptype.equals(CtClass.doubleType)) {
                            methodToAdd += "Double.valueOf(" + "arg_" + argNumber
                                    + ");";
                        } else if (ptype.equals(CtClass.charType)) {
                            methodToAdd += "Character.valueOf(" + "arg_"
                                    + argNumber + ");";
                        }
                    } else {
                        methodToAdd += "arg_" + argNumber + ";";
                    }

                }

                for (int i = 0; i < parameterTypes.length; i++) {
                    methodToAdd += "types[" + i + "] = ";
                    if (parameterTypes[i].isPrimitive()) {
                        CtClass ptype = parameterTypes[i];
                        if (ptype.equals(CtClass.intType)) {
                            methodToAdd += "Integer.TYPE;";
                        } else if (ptype.equals(CtClass.booleanType)) {
                            methodToAdd += "Boolean.TYPE;";
                        } else if (ptype.equals(CtClass.longType)) {
                            methodToAdd += "Long.TYPE;";
                        } else if (ptype.equals(CtClass.shortType)) {
                            methodToAdd += "Short.TYPE;";
                        } else if (ptype.equals(CtClass.floatType)) {
                            methodToAdd += "Float.TYPE;";
                        } else if (ptype.equals(CtClass.doubleType)) {
                            methodToAdd += "Double.TYPE;";
                        } else if (ptype.equals(CtClass.charType)) {
                            methodToAdd += "Character.TYPE;";
                        }
                    } else {
                    	methodToAdd += parameterTypes[i].getName() + ".class; ";
                    }
                }
            }
            if (hasReturn) {
                methodToAdd += " return  " + "(" + returnType.getName() + ")";
            }

            if (returnType.isPrimitive()) {
                methodToAdd += "sbbLocalObjectInterceptor.invokeAndReturn"
                        + returnType.getSimpleName() + "(concrete," + "\""
                        + interfaceMethod.getName() + "\"" + ", args, types); ";
            } else {
                methodToAdd += "sbbLocalObjectInterceptor.invokeAndReturnObject(concrete,"
                        + "\""
                        + interfaceMethod.getName()
                        + "\""
                        + ", args, types );";
            }
            methodToAdd += "}";

            //Add the implementation code
            if (logger.isTraceEnabled()) {
                logger.trace("Method " + methodToAdd + " added");
            }
            CtMethod methodTest;
            try {
                methodTest = CtNewMethod.make(methodToAdd,
                        concreteSbbLocalObject);
                concreteSbbLocalObject.addMethod(methodTest);
            } catch (CannotCompileException cce) {
                cce.printStackTrace();
                throw new RuntimeException("error generating method ", cce);
            }
        }
    }

}


package org.mobicents.tools.twiddle.op;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import gnu.getopt.Getopt;

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;

/**
 * Simple class for commom part of set/get ops. It should be used in case of
 * simple, bean like setters. User should not associate 'g' and 's' chars for
 * Getopt since those are reserved by this op.
 *
 * @author baranowb
 *
 */
public class AccessorOperation extends AbstractOperation {

	public static final char set = 's';
	public static final char get = 'g';
	/**
	 * Name of bean field, it will be used to create get/set method name.
	 */
	protected String beanFieldName;
    protected Class<?> fieldClass;
	protected boolean usJMXEditors;

    public AccessorOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand, String beanFieldName, Class<?> fieldClass, boolean useJMXEditors) {
		super(context, log, sleeCommand);

		// TODO: replace first char.
		this.beanFieldName = beanFieldName;
		if (Character.isLowerCase(this.beanFieldName.charAt(0))) {
			char c = this.beanFieldName.charAt(0);
			c = Character.toUpperCase(c);
			StringBuffer sb =  new StringBuffer();
			sb.append(c);
			sb.append(this.beanFieldName.substring(1));
			this.beanFieldName = sb.toString();
		}

		//this.beanFieldName = beanFieldName.substring(0, 1).toUpperCase() + beanFieldName.substring(1);

		this.fieldClass = fieldClass;
		this.usJMXEditors = useJMXEditors;
	}

    public AccessorOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand, String beanFieldName, Class<?> fieldClass) {
		this(context, log, sleeCommand, beanFieldName, fieldClass, false);

	}
    public AccessorOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand, String beanFieldName) {
		this(context, log, sleeCommand, beanFieldName, null, false);

	}

    /**
     * User should overide it to provide different name, for instance for boolean \"is\" prefix
     */
	protected void makeGetter() {
		if(fieldClass.equals(boolean.class) || fieldClass.equals(Boolean.class)) {
			super.operationName = "is" + this.beanFieldName;
		} else {
			super.operationName = "get" + this.beanFieldName;
		}
	}

	protected void makeSetter() {
		super.operationName = "set" + this.beanFieldName;
	}

	/**
	 * This method is called to convert optArg from string form, if no conversion is needed it should return passed object.
	 * @param optArg
	 * @return
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws IllegalArgumentException
	 * @throws CommandException
	 */
	protected Object convert(String optArg) throws SecurityException, NoSuchMethodException, IllegalArgumentException,
			InstantiationException, IllegalAccessException, InvocationTargetException, CommandException {
		if (fieldClass.isPrimitive()) {
			// TODO: to optimize, to rework new to valueOf
			if (fieldClass.equals(int.class)) {
				return new Integer(optArg);
			} else if (fieldClass.equals(long.class)) {
				return new Long(optArg);
			} else if (fieldClass.equals(int.class)) {
				return new Integer(optArg);
			} else if (fieldClass.equals(byte.class)) {
				return new Byte(optArg);
			} else if (fieldClass.equals(short.class)) {
				return new Short(optArg);
			} else if (fieldClass.equals(float.class)) {
				return new Float(optArg);
			} else if (fieldClass.equals(double.class)) {
				return new Double(optArg);
			} else if (fieldClass.equals(boolean.class)) {
				return new Boolean(optArg);
			} else if(fieldClass.equals(char.class)) {
				return new Character(optArg.charAt(0));
			} //?

			throw new CommandException("Unpredicted place. Please report.");
		} else if (isClassNumber()) {
			//Handle Long, Integer, .., Boolean
			Constructor<?> con = fieldClass.getConstructor(String.class);
			return con.newInstance(optArg);
		}

		return optArg;
	}

	private boolean isClassNumber()
	{
		@SuppressWarnings("rawtypes")
		Class[] all = fieldClass.getClasses();

		for(Class<?> c : all) {
			if(c.equals(Number.class) || c.equals(Boolean.class)) {
				return true;
			}
		}
		return false;
	}

	@Override
	public void buildOperation(Getopt opts, String[] args) throws CommandException {
		int code;
		String optArg;
		while ((code = opts.getopt()) != -1) {
			if (super.operationName != null) {
				throw new CommandException("Command: \"" + sleeCommand.getName() + "\", expects either \"--set\" or \"--get\"!");
			}
			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 set:
				makeSetter();
				optArg = opts.getOptarg();
				try {
					addArg(convert(optArg), fieldClass, usJMXEditors);
				} catch (Exception e) {
					throw new CommandException("Failed to parse Integer: \"" + optArg + "\"", e);
				}

				break;
			case get:
				makeGetter();
				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 either \"--set\" or \"--get\"!");
		}

	}
}


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

import org.infinispan.remoting.transport.Address;
import org.restcomm.cluster.MobicentsCluster;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * @author martins
 *
 */
public class ReplicatedDataImpl<K extends Serializable, V extends Serializable>
		implements ReplicatedData<K, V> {

	/**
	 *
	 */
	private final MobicentsCluster cluster;

	/**
	 *
	 */
	private final ReplicatedDataCacheData<K, V> cacheData;

	/**
	 *
	 */
	private final DataRemovalListener<K, V> dataRemovalListener;

	/**
	 * @param name
	 * @param raEntity
	 * @param cluster
	 * @param ra
	 * @param activateDataRemovedCallback
	 */
	public ReplicatedDataImpl(String name, String raEntity,
			MobicentsCluster cluster, FaultTolerantResourceAdaptor<K, V> ra,
			boolean activateDataRemovedCallback) {
		cacheData = new ReplicatedDataCacheData<K, V>(name, raEntity,
				cluster);
		cacheData.create();
		this.cluster = cluster;
		if (activateDataRemovedCallback) {
			this.dataRemovalListener = new DataRemovalListener<K, V>(ra, getCacheData());
			cluster.addDataRemovalListener(dataRemovalListener);
		}
		else {
			dataRemovalListener = null;
		}
	}

	/**
	 *
	 * @return the cacheData
	 */
	ReplicatedDataCacheData<K, V> getCacheData() {
		return cacheData;
	}

	/**
	 *
	 * @return the cluster
	 */
	MobicentsCluster getCluster() {
		return cluster;
	}

	/**
	 * Removes all replicated data
	 */
	public void remove() {
		if (dataRemovalListener != null) {
			cluster.removeDataRemovalListener(dataRemovalListener);
		}
		cacheData.remove();
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.resource.cluster.ReplicatedData#getLocalKeyset()
	 */
	public Set<K> getLocalKeyset() {
		Set<K> set = new HashSet<K>();
		ReplicatedDataKeyClusteredCacheData<K, V> handleCacheData = null;
		Address handleCacheDataClusterNode = null;
		for (K handle : cacheData.getAllKeys()) {
			handleCacheData = new ReplicatedDataKeyClusteredCacheData<K, V>(
					cacheData, handle, cluster);
			handleCacheDataClusterNode = handleCacheData
					.getClusterNodeAddress();
			if (handleCacheDataClusterNode == null
					|| handleCacheDataClusterNode.equals(cluster
							.getLocalAddress())) {
				set.add(handle);
			}
		}
		return Collections.unmodifiableSet(set);
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.resource.cluster.ReplicatedData#put(java.io.Serializable, java.io.Serializable)
	 */
	public boolean put(K key, V value) {
		final ReplicatedDataKeyClusteredCacheData<K, V> keyCacheData = new ReplicatedDataKeyClusteredCacheData<K, V>(
				cacheData, key, cluster);
		boolean created = keyCacheData.create();
		if (value != null) {
			keyCacheData.setValue(value);
		}
		return created;
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.resource.cluster.ReplicatedData#get(java.io.Serializable)
	 */
	public V get(K key) {
		final ReplicatedDataKeyClusteredCacheData<K, V> handleCacheData = new ReplicatedDataKeyClusteredCacheData<K, V>(
				cacheData, key, cluster);
		return handleCacheData.exists() ? handleCacheData.getValue() : null;
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.resource.cluster.ReplicatedData#contains(java.io.Serializable)
	 */
	public boolean contains(K key) {
		return new ReplicatedDataKeyClusteredCacheData<K, V>(cacheData, key,
				cluster).exists();
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.resource.cluster.ReplicatedData#remove(java.io.Serializable)
	 */
	public boolean remove(K key) {
		return new ReplicatedDataKeyClusteredCacheData<K, V>(cacheData, key, cluster)
				.remove();
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.resource.cluster.ReplicatedData#getKeyset()
	 */
	public Set<K> getKeyset() {
		return cacheData.getAllKeys();
	}

}


package javax.slee.management;

import javax.slee.facilities.Level;
import javax.slee.facilities.TraceLevel;
import javax.management.Notification;
import javax.management.NotificationFilter;

/**
 * A notification filter that filters {@link TraceNotification}s based on their trace level.
 * Only trace notifications of the specified level or greater are be allowed through this filter.
 *

 * Notifications that are not instances of {@link TraceNotification} are suppressed by this filter.
 */
public class TraceLevelFilter implements NotificationFilter {
    /**
     * Create a TraceLevelFilter.  A filter created using this constructor will
     * only allow SLEE 1.0-compliant trace notifications to pass through where they otherwise
     * satisfy the filtering criteria.
     * @param minLevel this minimum trace level of trace notifications allowed through
     *        this filter.
     * @deprecated Replaced with {@link #TraceLevelFilter(TraceLevel)} as trace and alarm
     *       levels have been split into different classes.
     */
    public TraceLevelFilter(Level minLevel) {
        this.minLevel_10 = minLevel;
        this.minLevel_11 = null;
    }

    /**
     * Create a TraceLevelFilter.  A filter created using this constructor will
     * only allow SLEE 1.1-compliant trace notifications to pass through where they otherwise
     * satisfy the filtering criteria.
     * @param minLevel this minimum trace level of trace notifications allowed through this filter.
     */
    public TraceLevelFilter(TraceLevel minLevel) {
        this.minLevel_10 = null;
        this.minLevel_11 = minLevel;
    }

    /**
     * Determine whether the specified notification should be delivered to notification
     * listeners using this notification filter.
     * @param notification the notification to be sent.
     * @return true if the notification should be delivered to notification
     *        listeners, false otherwise.  This method always returns
     *        false if notification is not an instance of
     *        {@link TraceNotification}.
     */
    public boolean isNotificationEnabled(Notification notification) {
        if (!(notification instanceof TraceNotification)) return false;
        if (minLevel_10 != null) {
            // SLEE 1.0 comparison
            Level traceLevel = ((TraceNotification)notification).getLevel();
            return traceLevel != null && !minLevel_10.isHigherLevel(traceLevel);
        }
        else {
            // SLEE 1.1 comparison
            TraceLevel traceLevel = ((TraceNotification)notification).getTraceLevel();
            return traceLevel != null && !minLevel_11.isHigherLevel(traceLevel);
        }
    }

    private final Level minLevel_10;
    private final TraceLevel minLevel_11;
}


package javax.slee.profile;

import java.io.Serializable;
import javax.slee.Address;
import javax.slee.AddressPlan;

/**
 * The ProfileID class defines an identifier that can be used to
 * reference profiles.  For example a profile specification's CMP interface
 * may contain attributes of the type ProfileID, allowing profile's of
 * that type to reference other profiles.
 */
public class ProfileID implements Serializable, Cloneable {
    /**
     * Create a ProfileID object using a profile table name and profile name.
     * @param profileTableName the name of the profile table.
     * @param profileName the name of the profile within the profile table.
     * @throws NullPointerException if either argument is null.
     * @throws IllegalArgumentException if profileTableName includes the '<tt>/</tt>'
     *        character.  This character is not permitted in profile table names.
     */
    public ProfileID(String profileTableName, String profileName) throws NullPointerException, IllegalArgumentException {
        setProfileID(profileTableName, profileName);
    }

    /**
     * Create a ProfileID object from an address.  The address must have the
     * address plan of {@link javax.slee.AddressPlan#SLEE_PROFILE}.
     * @param address the address of the profile.
     * @throws NullPointerException if address is null.
     * @throws IllegalArgumentException if the address plan of the address is not
     *        AddressPlan.SLEE_PROFILE, or the address string does not
     *        contain a profile identifier with the correct encoding:
     *        <tt><profile-table-name>/<profile-name></tt>.
     */
    public ProfileID(Address address) throws NullPointerException, IllegalArgumentException {
        if (address == null) throw new NullPointerException("address is null");

        if (!address.getAddressPlan().equals(AddressPlan.SLEE_PROFILE))
            throw new IllegalArgumentException("address must have the SLEE_PROFILE address plan");

        String addressString = address.getAddressString();

        int div = addressString.indexOf('/');
        if (div < 0) throw new IllegalArgumentException("address string does not contain a '/' seperator character");

        this.profileTableName = addressString.substring(0, div);
        this.profileName = addressString.substring(div + 1);
        this.address = address;
    }

    /**
     * Get the name of the profile table referenced by this identifier.
     * @return the profile table name.
     */
    public final String getProfileTableName() {
        return profileTableName;
    }

    /**
     * Get the name of the profile referenced by this identifier.
     * @return the profile name.
     */
    public final String getProfileName() {
        return profileName;
    }

    /**
     * Set the profile table and profile referenced by this profile identifier to new
     * values.
     * @param profileTableName the name of the profile table.
     * @param profileName the name of the profile within the profile table.
     * @throws NullPointerException if either argument is null.
     * @throws IllegalArgumentException if profileTableName includes the
     *        '<tt>/</tt>' character.  This character is not permitted in profile table names.
     */
    public final void setProfileID(String profileTableName, String profileName) throws NullPointerException, IllegalArgumentException {
        if (profileTableName == null) throw new NullPointerException("profileTableName is null");
        if (profileName == null) throw new NullPointerException("profileName is null");

        if (profileTableName.indexOf('/') >= 0) throw new IllegalArgumentException("profileTableName cannot contain the '/' character");

        this.profileTableName = profileTableName;
        this.profileName = profileName;
        this.address = null;
    }

    /**
     * Get an Address object containing the address form of the profile
     * identified by this profile identifier.
     * @return an Address object containing the address form of the profile
     *        identified by this profile identifier.
     */
    public Address toAddress() {
        if (address == null) {
            address = new Address(AddressPlan.SLEE_PROFILE, profileTableName + '/' + profileName);
        }
        return address;
    }

    /**
     * Create a copy of this profile identifier.
     * @return a copy of this profile identifier.
     * @see Object#clone()
     * @since SLEE 1.1.
     */
    public Object clone(){
        return new ProfileID(profileTableName, profileName);
    }

    /**
     * Compare this profile identifier for equality with another object.
     * @param obj the object to compare this with.
     * @return true if obj is an instance of this class and the
     *        profile table name and profile name are equal.
     */
    public boolean equals(Object obj) {
        if (obj == this) return true;
        if (!(obj instanceof ProfileID)) return false;

        ProfileID that = (ProfileID)obj;
        return this.profileTableName.equals(that.profileTableName)
            && this.profileName.equals(that.profileName);
    }

    /**
     * Get a hash code value for this profile identifier.  The hash code is the logical
     * OR of the hashcodes of the profile table name and profile name.
     * @return a hash code for this profile identifier.
     */
    public int hashCode() {
        return profileTableName.hashCode() | profileName.hashCode();
    }

    /**
     * Get a string representation for this profile identifier.
     * @return a string representation for this profile identifier.
     */
    public String toString() {
        StringBuffer buf = new StringBuffer();
        buf.append("ProfileID[table=")
            .append(profileTableName)
            .append(",profile=")
            .append(profileName)
            .append("]");
        return buf.toString();
    }

    private String profileTableName;
    private String profileName;

    private transient Address address;
}


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

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

import javax.slee.Address;
import javax.slee.EventTypeID;
import javax.slee.ServiceID;

import org.mobicents.slee.container.activity.ActivityContext;
import org.mobicents.slee.container.activity.LocalActivityContext;
import org.mobicents.slee.container.component.service.ServiceComponent;
import org.mobicents.slee.container.sbbentity.SbbEntityID;

/**
 * @author martins
 *
 */
public class DefaultEventContextData implements EventContextData {

	private final EventTypeID eventTypeId;
	private final ServiceID serviceID;
	private final Object eventObject;
	private final Address address;

	private LocalActivityContext localActivityContext;
	private EventUnreferencedCallback unreferencedCallback;
	private EventProcessingSucceedCallback succeedCallback;
	private EventProcessingFailedCallback failedCallback;
	private ReferencesHandler referencesHandler;

	/**
	 * a queue of {@link EventContext}s barried due to this context become
	 * suspended
	 */
	private LinkedList<EventContext> barriedEvents;

	/**
	 * the set containing all sbb entities that handled the event so far
	 */
	private Set<SbbEntityID> sbbEntitiesThatHandledEvent;

	/**
	 * the ordered list containing all active services that will process this
	 * event as initial
	 */
	private LinkedList<ServiceComponent> activeServicesToProcessEventAsInitial;

	public DefaultEventContextData(EventTypeID eventTypeId, Object event,
			ActivityContext ac, Address address, ServiceID serviceID,
			EventProcessingSucceedCallback succeedCallback,
			EventProcessingFailedCallback failedCallback,
			EventUnreferencedCallback unreferencedCallback,
			ReferencesHandler referencesHandler) {
		this.eventTypeId = eventTypeId;
		this.eventObject = event;
		this.localActivityContext = ac.getLocalActivityContext();
		this.address = address;
		this.serviceID = serviceID;
		this.succeedCallback = succeedCallback;
		this.failedCallback = failedCallback;
		this.unreferencedCallback = unreferencedCallback;
		this.referencesHandler = referencesHandler;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.event.EventContextData#barrierEvent(org.
	 * mobicents.slee.container.event.EventContext)
	 */
	public void barrierEvent(EventContext eventContext) {
		if (barriedEvents == null) {
			barriedEvents = new LinkedList<EventContext>();
		}
		barriedEvents.add(eventContext);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.container.event.EventContextData#
	 * getActiveServicesToProcessEventAsInitial()
	 */
	public LinkedList<ServiceComponent> getActiveServicesToProcessEventAsInitial() {
		if (activeServicesToProcessEventAsInitial == null) {
			activeServicesToProcessEventAsInitial = new LinkedList<ServiceComponent>();
		}
		return activeServicesToProcessEventAsInitial;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.slee.container.event.EventContextData#getAddress()
	 */
	public Address getAddress() {
		return address;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.slee.container.event.EventContextData#getEventObject()
	 */
	public Object getEventObject() {
		return eventObject;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.slee.container.event.EventContextData#getEventTypeId()
	 */
	public EventTypeID getEventTypeId() {
		return eventTypeId;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.event.EventContextData#getFailedCallback()
	 */
	public EventProcessingFailedCallback getFailedCallback() {
		return failedCallback;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.event.EventContextData#getLocalActivityContext
	 * ()
	 */
	public LocalActivityContext getLocalActivityContext() {
		return localActivityContext;
	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.container.event.EventContextData#getReferencesHandler()
	 */
	public ReferencesHandler getReferencesHandler() {
		return referencesHandler;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.container.event.EventContextData#
	 * getSbbEntitiesThatHandledEvent()
	 */
	public Set<SbbEntityID> getSbbEntitiesThatHandledEvent() {
		if (sbbEntitiesThatHandledEvent == null) {
			sbbEntitiesThatHandledEvent = new HashSet<SbbEntityID>();
		}
		return sbbEntitiesThatHandledEvent;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.slee.container.event.EventContextData#getService()
	 */
	public ServiceID getService() {
		return serviceID;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.event.EventContextData#getSucceedCallback()
	 */
	public EventProcessingSucceedCallback getSucceedCallback() {
		return succeedCallback;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.event.EventContextData#getUnreferencedCallback
	 * ()
	 */
	public EventUnreferencedCallback getUnreferencedCallback() {
		return unreferencedCallback;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.event.EventContextData#removeEventsBarried()
	 */
	public EventContext[] removeEventsBarried() {
		// this is safe because adding events and calling this is ever done by
		// same executor/thread
		final EventContext[] result = barriedEvents
				.toArray(new EventContext[barriedEvents.size()]);
		barriedEvents = null;
		return result;
	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.container.event.EventContextData#unsetFailedCallback()
	 */
	public void unsetFailedCallback() {
		this.failedCallback = null;
	}

	@Override
	public void unsetUnreferencedCallback() {
		this.unreferencedCallback = null;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return new StringBuilder("event type id = ").append(
				eventTypeId).append(" , event = ").append(eventObject).append(
				" , local ac = ").append(localActivityContext.getActivityContextHandle()).append(" , address = ").append(
				address).append(" , serviceID = ").append(serviceID).toString();
	}
}


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

/**
 *
 */
package org.mobicents.slee.runtime.eventrouter.mapping;

import org.mobicents.slee.container.activity.ActivityContextHandle;
import org.mobicents.slee.container.eventrouter.EventRouterExecutor;

/**
 * Simple {@link EventRouterExecutor} to {@link ActivityContextHandle} mapping
 * using the hashcode of the latter.
 *
 * @author martins
 *
 */
public class ActivityHashingEventRouterExecutorMapper extends
		AbstractEventRouterExecutorMapper {

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.runtime.eventrouter.mapping.
	 * AbstractEventRouterExecutorMapper
	 * #getExecutor(org.mobicents.slee.runtime.activity.ActivityContextHandle)
	 */
	@Override
	public EventRouterExecutor getExecutor(
			ActivityContextHandle activityContextHandle) {
		return executors[(activityContextHandle.hashCode() & Integer.MAX_VALUE)
				% executors.length];
	}

}


package javax.slee.management;

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

/**
 * This class defines an enumerated type that encapsulates the operational state of the SLEE.
 *

 * A singleton instance of each enumerated value is guaranteed (via an implementation
 * of readResolve() - refer {@link java.io.Serializable java.io.Serializable}),
 * so that equality tests using == are always evaluated correctly.  (This
 * equality test is only guaranteed if this class is loaded in the application's boot class
 * path, rather than dynamically loaded at runtime.)
 */
public final class SleeState implements Serializable {
    /**
     * An integer representation of the {@link #STOPPED} state.
     */
    public static final int SLEE_STOPPED = 0;

    /**
     * An integer representation of the {@link #STARTING} state.
     */
    public static final int SLEE_STARTING = 1;

    /**
     * An integer representation of the {@link #RUNNING} state.
     */
    public static final int SLEE_RUNNING = 2;

    /**
     * An integer representation of the {@link #STOPPING} state.
     */
    public static final int SLEE_STOPPING = 3;

    /**
     * A string representation of the {@link #STOPPED} state.
     */
    public static final String STOPPED_STRING = "Stopped";

    /**
     * A string representation of the {@link #STARTING} state.
     */
    public static final String STARTING_STRING = "Starting";

    /**
     * A string representation of the {@link #RUNNING} state.
     */
    public static final String RUNNING_STRING = "Running";

    /**
     * A string representation of the {@link #STOPPING} state.
     */
    public static final String STOPPING_STRING = "Stopping";

    /**
     * The STOPPED state is the initial state for the SLEE on startup.
     * When in this state, the the SLEE and resource adaptors do not generate events
     * and SLEE's event routing subsystem is idle.
     */
    public static final SleeState STOPPED = new SleeState(SLEE_STOPPED);

    /**
     * The STARTING state is a transitional state between {@link #STOPPED}
     * and {@link #RUNNING}. When in this state, the SLEE is activating relevant
     * resource adaptors and performing any other tasks necessary to start event
     * processing.  The event router is not yet started in this state.
     */
    public static final SleeState STARTING = new SleeState(SLEE_STARTING);

    /**
     * In the RUNNING state the SLEE and resource adaptors are generating events
     * and the SLEE's event routing subsystem is actively creating SBBs and delivering
     * events to them.
     */
    public static final SleeState RUNNING = new SleeState(SLEE_RUNNING);

    /**
     * The STOPPING state is a transitional state between {@link #STARTING}
     * or {@link #RUNNING} and {@link #STOPPED}.  When in this state any remaining
     * activities are allowed to complete without new activities being created.
     */
    public static final SleeState STOPPING = new SleeState(SLEE_STOPPING);

    /**
     * Get a SleeState object from an integer value.
     * @param state the state as an integer.
     * @return a SleeState object corresponding to state.
     * @throws IllegalArgumentException if state is not a valid SLEE
     *        state value.
     */
    public static SleeState fromInt(int state) throws IllegalArgumentException {
        switch (state) {
            case SLEE_STOPPED: return STOPPED;
            case SLEE_STARTING: return STARTING;
            case SLEE_RUNNING: return RUNNING;
            case SLEE_STOPPING: return STOPPING;
            default: throw new IllegalArgumentException("Invalid state: " + state);
        }
    }

    /**
     * Get a SleeState object from a string value.
     * @param state the state as a string, for example as returned by the {@link #toString()}
     *        method (case insensitive).
     * @return a SleeState object corresponding to state.
     * @throws NullPointerException if state is null.
     * @throws IllegalArgumentException if state is not a valid SLEE
     *        state string.
     * @since SLEE 1.1
     */
    public static SleeState fromString(String state) throws NullPointerException, IllegalArgumentException {
        if (state == null) throw new NullPointerException("state is null");
        if (state.equalsIgnoreCase(STOPPED_STRING)) return STOPPED;
        if (state.equalsIgnoreCase(STARTING_STRING)) return STARTING;
        if (state.equalsIgnoreCase(RUNNING_STRING)) return RUNNING;
        if (state.equalsIgnoreCase(STOPPING_STRING)) return STOPPING;
        throw new IllegalArgumentException("Invalid state: " + state);
    }

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

    /**
     * Determine if this SleeState object represents the STOPPED state of the SLEE.
     *

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

     *     if (state.isStopped()) ...
     *

     * is interchangeable with the code:
     *

     *    if (state == SleeState.STOPPED) ...
     *

     * @return true if this object represents the STOPPED state of the SLEE,
     *       false otherwise.
     */
    public boolean isStopped() {
        return state == SLEE_STOPPED;
    }

    /**
     * Determine if this SleeState object represents the STARTING state of the SLEE.
     *

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

     *     if (state.isStarting()) ...
     *

     * is interchangeable with the code:
     *

     *    if (state == SleeState.STARTING) ...
     *

     * @return true if this object represents the STARTING state of the SLEE,
     *       false otherwise.
     */
    public boolean isStarting() {
        return state == SLEE_STARTING;
    }

    /**
     * Determine if this SleeState object represents the RUNNING state of the SLEE.
     *

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

     *     if (state.isRunning()) ...
     *

     * is interchangeable with the code:
     *

     *    if (state == SleeState.RUNNING) ...
     *

     * @return true if this object represents the RUNNING state of the SLEE,
     *       false otherwise.
     */
    public boolean isRunning() {
        return state == SLEE_RUNNING;
    }

    /**
     * Determine if this SleeState object represents the STOPPING state of the SLEE.
     *

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

     *     if (state.isStopping()) ...
     *

     * is interchangeable with the code:
     *

     *    if (state == SleeState.STOPPING) ...
     *

     * @return true if this object represents the STOPPING state of the SLEE,
     *       false otherwise.
     */
    public boolean isStopping() {
        return state == SLEE_STOPPING;
    }

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

        return (obj instanceof SleeState) && ((SleeState)obj).state == state;
    }

    /**
     * Get a hash code value for this SLEE state.
     * @return a hash code value.
     */
    public int hashCode() {
        return state;
    }

    /**
     * Get the textual representation of the SLEE state object.
     * @return the textual representation of the SLEE state object.
     */
    public String toString() {
        switch (state) {
            case SLEE_STOPPED: return STOPPED_STRING;
            case SLEE_STARTING: return STARTING_STRING;
            case SLEE_RUNNING: return RUNNING_STRING;
            case SLEE_STOPPING: return STOPPING_STRING;
            default: return "SleeState in Unknown and Invalid State";
        }
    }

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

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

    private final int state;
}


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

import org.mobicents.slee.container.management.console.client.Logger;
import org.mobicents.slee.container.management.console.client.common.BrowseContainer;
import org.mobicents.slee.container.management.console.client.common.ControlContainer;

import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.FormHandler;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.FormSubmitCompleteEvent;
import com.google.gwt.user.client.ui.FormSubmitEvent;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;

/**
 * @author Stefano Zappaterra
 *
 */
public class DeployableUnitInstallPanel extends FormPanel {

  // protected DeployableUnitsCard deployableUnitsCard;

  private String extractMessage(String result) {

    // Fix:
    // Firefox 2 encapsulates the text inside <pre> tag
    String startPreTag = "<pre>";
    String endPreTag = "</pre>";

    result = result.trim();

    if (result.startsWith(startPreTag) && result.endsWith(endPreTag)) {
      result = result.substring(startPreTag.length(), result.length() - endPreTag.length());
    }

    return result;
  }

  public DeployableUnitInstallPanel(BrowseContainer browseContainer) {
    super();

    setAction("DeployableUnitsInstallService");
    setEncoding(FormPanel.ENCODING_MULTIPART);
    setMethod(FormPanel.METHOD_POST);

    ControlContainer panel = new ControlContainer();
    panel.setWidth("");

    setWidget(panel);

    Label label = new Label("Package file:");

    final FileUpload fileUpload = new FileUpload();
    fileUpload.setName("uploadFormElement");

    final Button submit = new Button("Install", new ClickListener() {
      public void onClick(Widget sender) {
        submit();
      }
    });

    addFormHandler(new FormHandler() {
      public void onSubmitComplete(final FormSubmitCompleteEvent event) {
        String result = event.getResults();

        if (result == null || result.length() == 0) {
          return;
        }

        result = extractMessage(result);

        if (result.indexOf(DeployableUnitsService.SUCCESS_CODE) != -1) {
          Logger.info("Deployable unit installed");
        }
        else {
          Logger.error(result);
        }
      }

      public void onSubmit(FormSubmitEvent event) {
        if (fileUpload.getFilename().trim().length() == 0) {
          Logger.error("Please specify a package file");
          event.setCancelled(true);
        }
      }
    });

    panel.setWidget(0, 0, label);
    panel.setWidget(0, 1, fileUpload);
    panel.setWidget(0, 2, submit);

    browseContainer.add("Install a deployable unit", this);
  }
}


package javax.slee.management;

import java.util.HashMap;
import java.util.Iterator;
import javax.management.Notification;
import javax.management.NotificationFilter;

/**
 * A notification filter that supresses equivalent {@link AlarmNotification}s
 * until a specified number have occurred within a specified time period.  Once
 * the threshold has been reached, the next equivalent alarm notification is allowed
 * through the filter, and the cycle restarts.  The cycle also restarts if the time
 * period from the first notification expires without a notification being sent.
 * This filter can be used to suppress alarms that occur and then clear up spontaneously.
 *

 * Formally: Given a series of duplicate alarm notifications, if
 * threshold + 1 notification are observed within period
 * milliseconds of the first notification, notification number threshold + 1
 * is delivered to notification listeners and counting restarts from notification
 * number threshold + 2.
 *

 * Alarm notification equivalence is tested using the {@link AlarmNotification#equals}
 * method.
 *

 * Notifications that are not instances of {@link AlarmNotification} are suppressed
 * by this filter.
 *

 * Note: This filter implementation does not use threads to clear stale timeouts.
 * Instead, stale timeouts are cleared on each invocation of {@link #isNotificationEnabled
 * isNotificationEnabled}.  Methods in this class are also thread-safe.
 */
public class AlarmThresholdFilter implements NotificationFilter {
    /**
     * Create an AlarmThresholdFilter.
     * @param threshold the number of duplicate notifications that must occur within
     *        the specified time period before the following duplicate notification
     *        is delivered to notification listeners.
     * @param period the period (measured in ms) during which duplicate alarm
     *        notifications within the threshold number will be discarded.
     */
    public AlarmThresholdFilter(int threshold, long period) {
        this.threshold = threshold;
        this.period = period;
    }

    /**
     * Determine whether the specified notification should be delivered to notification
     * listeners using this notification filter.
     * @param notification the notification to be sent.
     * @return true if the notification should be delivered to notification
     *        listeners, false otherwise.  This method always returns
     *        false if notification is not an instance of
     *        {@link AlarmNotification}.
     */
    public boolean isNotificationEnabled(Notification notification) {
        if (!(notification instanceof AlarmNotification)) return false;

        synchronized (knownAlarms) {
            clearStaleTimeouts();

            NotificationInfo info = (NotificationInfo)knownAlarms.get(notification);
            if (info == null) {
                // we've not seen this alarm before, or the period has expired since
                // the first notification
                knownAlarms.put(notification, new NotificationInfo(System.currentTimeMillis()));
                return false;
            }

            if (++info.count == threshold) {
                // passed threshold
                knownAlarms.remove(notification);
                return true;
            }

            return false;
        }
    }

    // private

    private void clearStaleTimeouts() {
        Iterator iterator = knownAlarms.values().iterator();
        long currentTime = System.currentTimeMillis();
        while (iterator.hasNext()) {
            NotificationInfo info = (NotificationInfo)iterator.next();
            // if period has expired remove reference to the notification
            if ((info.firstSeenTime + period) < currentTime) {
                iterator.remove();
            }
        }
    }

    private final class NotificationInfo {
        NotificationInfo(long currentTime) {
            this.firstSeenTime = currentTime;
        }

        final long firstSeenTime;
        int count = 0;
    }

    private final int threshold;
    private final long period;
    private final HashMap knownAlarms = new HashMap();
}