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

import java.util.concurrent.CountDownLatch;

import javax.slee.ActivityContextInterface;
import javax.slee.Address;
import javax.slee.TransactionRequiredLocalException;
import javax.slee.TransactionRolledbackLocalException;
import javax.slee.facilities.FacilityException;
import javax.slee.facilities.TimerID;
import javax.slee.facilities.TimerOptions;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.AbstractSleeContainerModule;
import org.mobicents.slee.container.activity.ActivityContext;
import org.mobicents.slee.container.facilities.TimerFacility;
import org.mobicents.slee.container.management.jmx.TimerFacilityConfiguration;
import org.mobicents.slee.container.transaction.SleeTransactionManager;
import org.mobicents.slee.container.transaction.TransactionContext;
import org.mobicents.slee.container.transaction.TransactionalAction;
import org.mobicents.slee.util.concurrent.SleeThreadFactory;
import org.restcomm.timers.FaultTolerantScheduler;

/**
 * Implementation of the SLEE timer facility. timer is the timer object
 * currently being examined. timer.scheduleTime is time that the Timer Event is
 * scheduled to fire. timer.timeout is timeout for this timer (from
 * TimerOptions). timer.numRepetitions is the total repetitions for this timer,
 * 0 if infinite, 1 if non-periodic. timer.remainingRepetiton is the remaining
 * repetition count, initially Long.MAX_VALUE for infinite periodic timers,
 * timer.numRepetitions otherwise. timer.period is the timer period
 * (Long.MAX_VALUE if non-periodic). timer.missed is the counter of undelivered
 * late events.
 *
 * @author Tim
 * @author M. Ranganathan
 * @author Ivelin Ivanov
 * @author martins
 *
 */
public class TimerFacilityImpl extends AbstractSleeContainerModule implements TimerFacility {

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

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

	private static final int DEFAULT_TIMEOUT = 1000;

	// this is supposed to be the timer resolution in ms of the hosting
	// OS/hardware
	private int timerResolution = 10;

	private FaultTolerantScheduler scheduler;

	private final TimerFacilityConfiguration configuration;

	/**
	 *
	 */
	public TimerFacilityImpl(TimerFacilityConfiguration configuration) {
		this.configuration = configuration;
	}

	@Override
	public void sleeInitialization() {
	}

	@Override
	public void sleeStarting() {
		if (scheduler != null) {
			scheduler.shutdownNow();
		}
		scheduler = new FaultTolerantScheduler("timer-facility",configuration.getTimerThreads(),sleeContainer.getCluster(),(byte)10, sleeContainer.getTransactionManager().getRealTransactionManager(),new TimerFacilityTimerTaskFactory(),configuration.getPurgePeriod(), SLEE_THREAD_FACTORY);
	}

	/**
	 * Retrieves
	 * @return the scheduler
	 */
	public FaultTolerantScheduler getScheduler() {
		return scheduler;
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.facilities.TimerFacility#setTimer(javax.slee.ActivityContextInterface, javax.slee.Address, long, javax.slee.facilities.TimerOptions)
	 */
	public TimerID setTimer(ActivityContextInterface aci, Address address,
			long startTime, TimerOptions timerOptions)
			throws NullPointerException, IllegalArgumentException,
			FacilityException {

		return setTimer(aci, address, startTime, Long.MAX_VALUE, 1,
				timerOptions);
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.facilities.TimerFacility#setTimer(javax.slee.ActivityContextInterface, javax.slee.Address, long, long, int, javax.slee.facilities.TimerOptions)
	 */
	public TimerID setTimer(ActivityContextInterface aci, Address address,
			long startTime, long period, int numRepetitions,
			TimerOptions timerOptions) throws NullPointerException,
			IllegalArgumentException, TransactionRolledbackLocalException,
			FacilityException {

		if (aci == null)
			throw new NullPointerException("Null ActivityContextInterface");
		if (startTime < 0)
			throw new IllegalArgumentException("startTime < 0");
		if (period <= 0)
			throw new IllegalArgumentException("period <= 0");
		if (timerOptions == null)
			throw new NullPointerException("Null TimerOptions");
		if (timerOptions.getTimeout() > period)
			throw new IllegalArgumentException("timeout > period");
		if (timerOptions.getTimeout() < this.getResolution())
			timerOptions.setTimeout(Math.min(period, this.getResolution()));

		if (period == Long.MAX_VALUE && numRepetitions == 1) {
			// non periodic value, the framework expects it to be negative instead
			period = -1;
		}

		// when numRepetitions == 0 the timer repeats infinitely or until
		// canceled
		if (numRepetitions < 0)
			throw new IllegalArgumentException("numRepetitions < 0");

		SleeTransactionManager txMgr = sleeContainer.getTransactionManager();
		boolean startedTx = txMgr.requireTransaction();

		TimerIDImpl timerID = new TimerIDImpl(sleeContainer.getUuidGenerator().createUUID());

		if (logger.isDebugEnabled()) {
			logger.debug("setTimer: timerID = "+timerID+" , startTime = " + startTime + " period = "
					+ period + " numRepetitions = " + numRepetitions
					+ " timeroptions =" + timerOptions);
		}

		// Attach to activity context
		org.mobicents.slee.container.activity.ActivityContextInterface aciImpl = (org.mobicents.slee.container.activity.ActivityContextInterface) aci;
		aciImpl.getActivityContext().attachTimer(timerID);

		// schedule timer task
		TimerFacilityTimerTaskData taskData = new TimerFacilityTimerTaskData(timerID, aciImpl.getActivityContext().getActivityContextHandle(), address, startTime, period, numRepetitions, timerOptions);
    	final TimerFacilityTimerTask task = new TimerFacilityTimerTask(taskData);
    	if(configuration.getTaskExecutionWaitsForTxCommitConfirmation()) {
    		final CountDownLatch countDownLatch = new CountDownLatch(1);
    		task.setCountDownLatch(countDownLatch);
    		TransactionalAction action = new TransactionalAction() {
    			@Override
    			public void execute() {
    				countDownLatch.countDown();
    			}
    		};
    		TransactionContext txContext = txMgr.getTransactionContext();
    		txContext.getAfterCommitActions().add(action);
    		txContext.getAfterRollbackActions().add(action);
    	}
		scheduler.schedule(task);

		// If we started a tx for this operation, we commit it now
		if (startedTx) {
			try {
				txMgr.commit();
			} catch (Exception e) {
				throw new TransactionRolledbackLocalException(
						"Failed to commit transaction");
			}
		}

		return timerID;
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.facilities.TimerFacility#cancelTimer(javax.slee.facilities.TimerID)
	 */
	public void cancelTimer(TimerID timerID) throws NullPointerException,
			TransactionRolledbackLocalException, FacilityException {

		if (logger.isDebugEnabled()) {
			logger.debug("cancelTimer: timerID = "+timerID);
		}

		if (timerID == null)
			throw new NullPointerException("Null TimerID");

		SleeTransactionManager txMgr = sleeContainer.getTransactionManager();

		boolean terminateTx = txMgr.requireTransaction();
		boolean doRollback = true;
		try {
			cancelTimer(timerID,true);
			doRollback = false;
		} finally {
			try {
				txMgr.requireTransactionEnd(terminateTx, doRollback);
			} catch (Throwable e) {
				throw new TransactionRolledbackLocalException(e.getMessage(),e);
			}
		}
	}

	public void cancelTimer(TimerID timerID, boolean detachAC) {
		// cancel task in scheduler
		final TimerFacilityTimerTask task = (TimerFacilityTimerTask) scheduler.cancel(timerID);
		if (detachAC && task != null) {
			// detach this timer from the ac
			ActivityContext ac = sleeContainer.getActivityContextFactory()
					.getActivityContext(task.getTimerFacilityTimerTaskData().getActivityContextHandle());
			if (ac != null) {
				ac.detachTimer(timerID);
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.facilities.TimerFacility#getResolution()
	 */
	public long getResolution() throws FacilityException {
		return this.timerResolution;
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.facilities.TimerFacility#getDefaultTimeout()
	 */
	public long getDefaultTimeout() throws FacilityException {
		return DEFAULT_TIMEOUT;
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.facilities.TimerFacility#getActivityContextInterface(javax.slee.facilities.TimerID)
	 */
	public ActivityContextInterface getActivityContextInterface(TimerID timerID)
			throws NullPointerException, TransactionRequiredLocalException,
			FacilityException {
		if (timerID == null) {
			throw new NullPointerException("null timerID");
		}

		sleeContainer.getTransactionManager().mandateTransaction();

		TimerFacilityTimerTaskData taskData = (TimerFacilityTimerTaskData) scheduler.getTimerTaskData(timerID);
		if (taskData != null) {
			try {
				return sleeContainer.getActivityContextFactory().getActivityContext(taskData.getActivityContextHandle()).getActivityContextInterface();
			} catch (Exception e) {
				throw new FacilityException(e.getMessage(),e);
			}
		}
		else {
			return null;
		}
	}

	@Override
	public String toString() {
		return 	"Timer Facility: " +
				"\n+-- " + scheduler.toDetailedString();
	}
}


package javax.slee.management;

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

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

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

    /**
     * Create an AlarmLevelFilter.  A filter created using this constructor will
     * only allow SLEE 1.1-compliant alarm notifications to pass through where they otherwise
     * satisfy the filtering criteria.
     * @param minLevel this minimum alarm level of alarm notifications allowed through this filter.
     */
    public AlarmLevelFilter(AlarmLevel 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 AlarmNotification}.
     */
    public boolean isNotificationEnabled(Notification notification) {
        if (!(notification instanceof AlarmNotification)) return false;

        if (minLevel_10 != null) {
            // SLEE 1.0 comparison
            Level alarmLevel = ((AlarmNotification)notification).getLevel();
            return alarmLevel != null && !minLevel_10.isHigherLevel(alarmLevel);
        }
        else {
            // SLEE 1.1 comparison
            AlarmLevel alarmLevel = ((AlarmNotification)notification).getAlarmLevel();
            return alarmLevel != null && !minLevel_11.isHigherLevel(alarmLevel);
        }
    }

    private final Level minLevel_10;
    private final AlarmLevel minLevel_11;
}


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

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

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

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

import org.mobicents.slee.container.component.deployment.jaxb.descriptors.common.MSecurityPermissions;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.sbb.MSbb;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.sbb.MSbbJar;
import org.mobicents.slee.container.component.sbb.SbbDescriptorFactory;

/**
 *
 * Factory to build {@link SbbDescriptorImpl} objects.
 *
 * @author  Alexandre Mendonca
 * @author  Bartosz Baranowski
 * @author  Eduardo Martins
 */
public class SbbDescriptorFactoryImpl extends AbstractDescriptorFactory implements SbbDescriptorFactory {

  /**
   * Builds a list of {@link SbbDescriptorImpl} objects, from an {@link InputStream} containing the sbb jar xml.
   * @param inputStream
   * @return
   * @throws DeploymentException
   */
  public List<SbbDescriptorImpl> parse(InputStream inputStream) throws DeploymentException
  {
    Object jaxbPojo = buildJAXBPojo(inputStream);

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

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

    MSecurityPermissions mSbbJarSecurityPermissions = mSbbJar.getSecurityPermissions();
    for (MSbb mSbb : mSbbJar.getSbb())
    {
      result.add(new SbbDescriptorImpl(mSbb, mSbbJarSecurityPermissions, isSlee11));
    }

    return result;
  }
}


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

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

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

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem;

/**
 * This class shows TreeStructure of loggers, allows browsing them in through BrowseCOntainer class.
 *
 * @author baranowb
 *
 */
public class LogStructureTreePanel extends Composite implements CommonControl {

  // We are displayed in this component, also log links will make this component display us.
  private BrowseContainer browseContainer;
  private final Tree logTree = new Tree();

  public LogStructureTreePanel(BrowseContainer browseContainer) {
    super();
    this.browseContainer = browseContainer;
    browseContainer.add("Logger Configuration", this.logTree);
    ScrollPanel scroll = new ScrollPanel();
    // scroll.setHeight("500px");
    // scroll.setWidth("630px");
    scroll.add(browseContainer);
    scroll.setHeight("100%");
    scroll.setWidth("100%");
    initWidget(scroll);

  }

  public void onHide() {
    // TODO Auto-generated method stub

  }

  public void onInit() {
    refreshData();

  }

  public void onShow() {

  }

  public void refreshData() {
    // final Tree t1 = logTree;
    // ArrayList names = new ArrayList();
    // names.add("org");
    // names.add("org.mobicents.slee");
    // names.add("org.apache");
    // names.add("org.mobicents");
    // names.add("org.mobicents.slee.container");
    // names.add("org.mobicents.slee.container.management.jmx.MBEAN");
    // names.add("org.mobicents.slee.container.management.jmx.ABEAN");
    // names.add("org.mobicents.slee.container.management.xmx.MBEAN");
    // names.add("org.mobicents.slee.container.management.xmx.ABEAN");
    // names.add("org.mobicents.slee.container.fun.jmx.MBEAN");
    // names.add("org.mobicents.slee.container.fun.jmx.ABEAN");
    // names.add("org.mobicents.slee.container.fun.xmx.MBEAN");
    // names.add("org.mobicents.slee.container.fun.xmx.ABEAN");
    // names.add("org.mobicents.mbean.container");
    // names.add("org.mobicents.mbean.container.management");
    // names.add("org.mobicents.mbean.container.management.jmx.MBEAN");
    // names.add("org.mobicents.mbean.container.management.jmx.ABEAN");
    // names.add("com");
    // names.add("com.mobicents.slee");
    // names.add("com.apache");

    AsyncCallback refreshCallback = new AsyncCallback() {

      public void onFailure(Throwable caught) {
        Logger.error("Failed to create tree of loggers!!![" + caught + "]");

      }

      public void onSuccess(Object result) {

        List names = (List) result;

        names.remove("");
        Iterator it = (names).iterator();
        FQDNNode root = new FQDNNode(false, "root", "root");
        while (it.hasNext()) {

          String s = (String) it.next();

          root.addNode(s.split("\\."), s, 0);
        }

        logTree.clear();

        logTree.addItem(doTree(root));

      }

    };

    ServerConnection.logServiceAsync.getLoggerNames(refreshCallback);

  }

  // TMP DEV METHODS

  private TreeItem doTree(FQDNNode localRoot) {

    TreeItem localLeaf = new TreeItem();

    LogTreeNode logTreeNode = new LogTreeNode(browseContainer, localRoot.getShortName(), localRoot.getFqdName(), localRoot.isWasLeaf(), this);

    localLeaf.setWidget(logTreeNode);

    if (localRoot.getChildren().size() > 0) {

      Tree t = new Tree();

      ArrayList names = new ArrayList(localRoot.getChildrenNames());
      Collections.sort(names);
      Iterator it = names.iterator();
      while (it.hasNext()) {
        t.addItem(doTree(localRoot.getChild((String) it.next())));
      }
      localLeaf.addItem(t);
    }

    return localLeaf;

  }

}


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

package org.mobicents.slee.runtime.sbbentity;

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

import javax.slee.ServiceID;

import org.mobicents.slee.container.sbbentity.SbbEntityID;

/**
 *
 * @author martins
 *
 */
public class RootSbbEntityID implements SbbEntityID {

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

	private ServiceID serviceID;
	private String convergenceName;

	private String toString = null;

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

	}

	/**
	 *
	 * @param serviceID
	 * @param convergenceName
	 */
	public RootSbbEntityID(ServiceID serviceID, String convergenceName) {
		this.serviceID = serviceID;
		this.convergenceName = convergenceName;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.sbbentity.SbbEntityID#getParentSBBEntityID()
	 */
	@Override
	public SbbEntityID getParentSBBEntityID() {
		return null;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.sbbentity.SbbEntityID#getParentChildRelation
	 * ()
	 */
	@Override
	public String getParentChildRelation() {
		return null;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.slee.container.sbbentity.SbbEntityID#getServiceID()
	 */
	@Override
	public ServiceID getServiceID() {
		return serviceID;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.sbbentity.SbbEntityID#getServiceConvergenceName
	 * ()
	 */
	@Override
	public String getServiceConvergenceName() {
		return convergenceName;
	}

	@Override
	public String getName() {
		return convergenceName;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.slee.container.sbbentity.SbbEntityID#isRootSbbEntity()
	 */
	@Override
	public boolean isRootSbbEntity() {
		return true;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.container.sbbentity.SbbEntityID#getRootSBBEntityID()
	 */
	@Override
	public SbbEntityID getRootSBBEntityID() {
		return this;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		int result = convergenceName.hashCode();
		result = result * 31 + serviceID.hashCode();
		return result;
	}

	/*
	 * (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 (getClass() != obj.getClass())
			return false;
		final RootSbbEntityID other = (RootSbbEntityID) obj;
		if (!convergenceName.equals(other.convergenceName))
			return false;
		if (!serviceID.equals(other.serviceID))
			return false;
		return true;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		if (toString == null) {
			toString = new StringBuilder("/").append(serviceID.toString())
					.append('/').append(convergenceName).toString();
		}
		return toString;
	}

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

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

}


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

import org.apache.log4j.Logger;
import org.jboss.as.naming.context.NamespaceContextSelector;
import org.mobicents.slee.container.AbstractSleeContainerModule;
import org.mobicents.slee.container.component.ComponentRepository;
import org.mobicents.slee.container.component.classloading.ReplicationClassLoader;
import org.mobicents.slee.container.component.common.EnvEntryDescriptor;
import org.mobicents.slee.container.component.ratype.ResourceAdaptorTypeComponent;
import org.mobicents.slee.container.component.sbb.EjbRefDescriptor;
import org.mobicents.slee.container.component.sbb.ResourceAdaptorEntityBindingDescriptor;
import org.mobicents.slee.container.component.sbb.ResourceAdaptorTypeBindingDescriptor;
import org.mobicents.slee.container.component.sbb.SbbComponent;
import org.mobicents.slee.container.component.service.ServiceComponent;
import org.mobicents.slee.container.deployment.SbbClassCodeGenerator;
import org.mobicents.slee.container.jndi.JndiManagement;
import org.mobicents.slee.container.resource.ResourceAdaptorEntity;
import org.mobicents.slee.container.transaction.SleeTransactionManager;
import org.mobicents.slee.container.transaction.TransactionalAction;
import org.mobicents.slee.runtime.facilities.SbbAlarmFacilityImpl;
import org.mobicents.slee.runtime.sbb.SbbObjectPoolImpl;
import org.mobicents.slee.runtime.sbb.SbbObjectPoolManagementImpl;

import javax.naming.*;
import javax.rmi.PortableRemoteObject;
import javax.slee.SbbID;
import javax.slee.ServiceID;
import javax.slee.facilities.AlarmFacility;
import javax.slee.facilities.Level;
import javax.slee.management.DeploymentException;
import javax.transaction.SystemException;
import java.lang.reflect.Method;

//import javax.naming.InitialContext;

/**
 * Manages sbbs in container
 *
 * @author martins
 *
 */
@SuppressWarnings("deprecation")
public class SbbManagementImpl extends AbstractSleeContainerModule implements SbbManagement {

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

	private SbbObjectPoolManagementImpl sbbPoolManagement;

	@Override
	public void sleeInitialization() {
		sbbPoolManagement = new SbbObjectPoolManagementImpl(sleeContainer);
		sbbPoolManagement.register();
	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.container.management.SbbManagement#serviceInstall(org.mobicents.slee.core.component.service.ServiceComponent)
	 */
	public void serviceInstall(ServiceComponent serviceComponent) {
		// create object pools
		for (SbbID sbbID : serviceComponent.getSbbIDs(sleeContainer.getComponentRepository())) {
			// create the pool for the given SbbID
			sbbPoolManagement.createObjectPool(serviceComponent.getServiceID(), sleeContainer.getComponentRepository().getComponentByID(sbbID),
					sleeContainer.getTransactionManager());
		}
	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.container.management.SbbManagement#serviceUninstall(org.mobicents.slee.core.component.service.ServiceComponent)
	 */
	public void serviceUninstall(ServiceComponent serviceComponent) {
		// remove sbb object pools
		for (SbbID sbbID : serviceComponent.getSbbIDs(sleeContainer.getComponentRepository())) {
			// remove the pool for the given SbbID
			sbbPoolManagement.removeObjectPool(serviceComponent.getServiceID(), sleeContainer.getComponentRepository().getComponentByID(sbbID),
					sleeContainer.getTransactionManager());
		}
	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.container.management.SbbManagement#getObjectPool(javax.slee.ServiceID, javax.slee.SbbID)
	 */
	public SbbObjectPoolImpl getObjectPool(ServiceID serviceID, SbbID sbbID) {
		return sbbPoolManagement.getObjectPool(serviceID, sbbID);
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.SbbManagement#installSbb(org.mobicents.slee.core.component.sbb.SbbComponent)
	 */
	public void installSbb(final SbbComponent sbbComponent)
			throws Exception {

		if (logger.isDebugEnabled()) {
			logger.debug("Installing " + sbbComponent);
		}

		final SleeTransactionManager sleeTransactionManager = sleeContainer
				.getTransactionManager();
		sleeTransactionManager.mandateTransaction();

		// change classloader
		ClassLoader oldClassLoader = Thread.currentThread()
				.getContextClassLoader();
		try {
			Thread.currentThread().setContextClassLoader(
					sbbComponent.getClassLoader());
			// Set up the comp/env naming context for the Sbb.
			JndiManagement jndiManagement = sleeContainer.getJndiManagement();
			jndiManagement.componentInstall(sbbComponent);
			jndiManagement.pushJndiContext(sbbComponent);
			try {
				setupSbbEnvironment(sbbComponent);
			} finally {
				jndiManagement.popJndiContext();
			}
			// generate class code for the sbb
			new SbbClassCodeGenerator().process(sbbComponent);

		//FIXME: this will erase stack trace.
		//} catch (Exception ex) {
		//	throw ex;
		} finally {
			Thread.currentThread().setContextClassLoader(oldClassLoader);
		}

		// Set 1.0 Trace to off
		sleeContainer.getTraceManagement().getTraceFacility().setTraceLevelOnTransaction(
				sbbComponent.getSbbID(), Level.OFF);
		sleeContainer.getAlarmManagement().registerComponent(
				sbbComponent.getSbbID());
		// if we are in cluster mode we need to add the sbb class loader domain to the replication class loader
		if (!sleeContainer.getCluster().getMobicentsCache().isLocalMode()) {
			final ReplicationClassLoader replicationClassLoader = sleeContainer.getReplicationClassLoader();
			replicationClassLoader.addDomain(sbbComponent.getClassLoaderDomain());
			TransactionalAction action = new TransactionalAction() {
				public void execute() {
					replicationClassLoader.removeDomain(sbbComponent.getClassLoaderDomain());
				}
			};
			sleeTransactionManager.getTransactionContext().getAfterRollbackActions().add(action);
		}

	}

	private void setupSbbEnvironment(SbbComponent sbbComponent) throws Exception {

		//Context ctx = (Context) new InitialContext().lookup("java:comp");
		Context ctx = NamespaceContextSelector.getCurrentSelector().getContext("comp");

		if (logger.isTraceEnabled()) {
			logger.trace("Setting up SBB env. Initial context is " + ctx);
		}

		Context envCtx = null;
		try {
			envCtx = ctx.createSubcontext("env");
		} catch (NameAlreadyBoundException ex) {
			envCtx = (Context) ctx.lookup("env");
		}

		Context sleeCtx = null;

		try {
			sleeCtx = envCtx.createSubcontext("slee");
		} catch (NameAlreadyBoundException ex) {
			sleeCtx = (Context) envCtx.lookup("slee");
		}

		// Do all the context binding stuff just once during init and
		// just do the linking here.

		Context newCtx;

		/*
		String containerName = "java:slee/container/Container";
		try {
			newCtx = sleeCtx.createSubcontext("container");
		} catch (NameAlreadyBoundException ex) {

		} finally {
			newCtx = (Context) sleeCtx.lookup("container");
		}

		try {
			newCtx.bind("Container", new LinkRef(containerName));
		} catch (NameAlreadyBoundException ex) {

		}*/

		try {
			newCtx = sleeCtx.createSubcontext("nullactivity");
		} catch (NameAlreadyBoundException ex) {
			newCtx = (Context) sleeCtx.lookup("nullactivity");
		}
		try {
			newCtx.bind("activitycontextinterfacefactory", sleeContainer.getNullActivityContextInterfaceFactory());
		} catch (NameAlreadyBoundException ex) {
		}
		try {
			newCtx.bind("factory", sleeContainer.getNullActivityFactory());
		} catch (NameAlreadyBoundException ex) {
		}

		//String serviceActivityContextInterfaceFactory = "java:slee/serviceactivity/activitycontextinterfacefactory";
		//String serviceActivityFactory = "java:slee/serviceactivity/factory";
		try {
			newCtx = sleeCtx.createSubcontext("serviceactivity");
		} catch (NameAlreadyBoundException ex) {
			newCtx = (Context) sleeCtx.lookup("serviceactivity");
		}
		try {
			newCtx.bind("activitycontextinterfacefactory",
					sleeContainer.getServiceManagement().getServiceActivityContextInterfaceFactory());
		} catch (NameAlreadyBoundException ex) {
		}
		try {
			newCtx.bind("factory", sleeContainer.getServiceManagement().getServiceActivityFactory());
		} catch (NameAlreadyBoundException ex) {
		}

		try {
			newCtx = sleeCtx.createSubcontext("facilities");
		} catch (NameAlreadyBoundException ex) {
			newCtx = (Context) sleeCtx.lookup("facilities");
		}
		try {
			newCtx.bind("timer", sleeContainer.getTimerFacility());
		} catch (NameAlreadyBoundException ex) {
		}

		try {
			newCtx.bind("activitycontextnaming",
					sleeContainer.getActivityContextNamingFacility());
		} catch (NameAlreadyBoundException ex) {
		}

		try {
			newCtx.bind("trace",
					sleeContainer.getTraceManagement().getTraceFacility());
		} catch (NameAlreadyBoundException ex) {
		}

		try {
			newCtx.bind("profile",
					sleeContainer.getSleeProfileTableManager().getProfileFacility());
		} catch (NameAlreadyBoundException ex) {
		}

		try {
			newCtx.bind("profiletableactivitycontextinterfacefactory",
					sleeContainer.getSleeProfileTableManager().getProfileTableActivityContextInterfaceFactory());
		} catch (NameAlreadyBoundException ex) {
		}

		try {
			//This has to be checked, to be sure sbb have it under correct jndi binding
			// previously "alarm" was pointing to the alarmmbeanimpl
			AlarmFacility sbbAlarmFacility = new SbbAlarmFacilityImpl(sbbComponent.getSbbID(),sleeContainer.getAlarmManagement());
			newCtx.bind("alarm", sbbAlarmFacility);
			sbbComponent.setAlarmFacility(sbbAlarmFacility);
		} catch (NameAlreadyBoundException ex) {
		}

		// profiles currently not supported
		/*
		try {
			newCtx.bind("profile", sleeContainer.getSleeProfileTableManager().getProfileFacility());
		} catch (NameAlreadyBoundException ex) {
		}

		try {
			newCtx.bind("profiletableactivitycontextinterfacefactory",
					sleeContainer.getSleeProfileTableManager().getProfileTableActivityContextInterfaceFactory());
		} catch (NameAlreadyBoundException ex) {

		}*/

		// For each resource that the Sbb references, bind the implementing
		// object name to its comp/env

		if (logger.isTraceEnabled()) {
			logger.trace("Number of Resource Bindings:"
					+ sbbComponent.getDescriptor().getResourceAdaptorTypeBindings());
		}
		ComponentRepository componentRepository = sleeContainer.getComponentRepository();
		for (ResourceAdaptorTypeBindingDescriptor raTypeBinding : sbbComponent.getDescriptor().getResourceAdaptorTypeBindings()) {

			ResourceAdaptorTypeComponent raTypeComponent = componentRepository.getComponentByID(raTypeBinding.getResourceAdaptorTypeRef());

			for (ResourceAdaptorEntityBindingDescriptor raEntityBinding : raTypeBinding.getResourceAdaptorEntityBinding()) {

				String raObjectName = raEntityBinding.getResourceAdaptorObjectName();
				String linkName = raEntityBinding.getResourceAdaptorEntityLink();
				/*
				 * The Deployment descriptor specifies Zero or more
				 * resource-adaptor-entity-binding elements. Each
				 * resource-adaptor-entity-binding element binds an object that
				 * implements the resource adaptor interface of the resource
				 * adaptor type into the JNDI comp onent environment of the SBB
				 * (see Section 6.13.3). Each resource- adaptorentity- binding
				 * element contains the following sub-elements: A description
				 * element. This is an optional informational element. A
				 * resource-adaptor-object?name element. This element specifies
				 * the location within the JNDI component environment to which
				 * the object that implements the resource adaptor interface
				 * will be bound. A resource-adaptor-entity-link element. This
				 * is an optional element. It identifies the resource adaptor
				 * entity that provides the object that should be bound into the
				 * JNDI component environment of the SBB. The identified
				 * resource adaptor entity must be an instance of a resource
				 * adaptor whose resource adaptor type is specified by the
				 * resourceadaptor- type-ref sub-element of the enclosing
				 * resource-adaptortype- binding element.
				 */
				ResourceManagement resourceManagement = sleeContainer.getResourceManagement();
				ResourceAdaptorEntity raEntity = resourceManagement
						.getResourceAdaptorEntity(resourceManagement
								.getResourceAdaptorEntityName(linkName));

				if (raEntity == null)
					throw new Exception(
							"Could not find Resource adaptor Entity for Link Name: ["
									+ linkName + "] of RA Type ["
									+ raTypeComponent + "]");

				NameParser parser = ctx.getNameParser("");
				Name name = parser.parse("java:comp/env/"+raObjectName);
				int tokenCount = name.size();

				// ctx is Context for "java:comp"
				Context subContext = ctx;

				// skip 0 = "java:comp"
				for (int i = 0; i < tokenCount - 1; i++) {
					String nextTok = name.get(i);
					try {
						subContext = (Context) subContext.createSubcontext(nextTok);
					} catch (NameAlreadyBoundException nfe) {
						subContext = (Context) subContext.lookup(nextTok);
					}
				}
				// Bind the resource adaptor instance to where the Sbb expects
				// to find it.
				if (logger.isDebugEnabled()) {
					logger
							.debug("Binding RA entity named "+raEntity.getName()+" sbb interface for "+raTypeBinding.getResourceAdaptorTypeRef()+", to JNDI context "+name);
				}
				try {
					Object raSbbInterface = raEntity.getResourceAdaptorInterface(raTypeBinding.getResourceAdaptorTypeRef());
					if (raSbbInterface != null) {
						subContext.bind(name.get(tokenCount-1),ResourceAdaptorSbbInterfaceObjectFactory.getReference(raSbbInterface, raTypeBinding.getResourceAdaptorTypeRef(), linkName));
					}
					else {
						throw new DeploymentException("Unable to retrieve the RA interface for RA entity "+raEntity.getName()+" and RAType " +raTypeBinding.getResourceAdaptorTypeRef());
					}
				} catch (NameAlreadyBoundException e) {
					logger.warn(
							"Unable to bind a JNDI reference to sbb interface of "+raTypeBinding.getResourceAdaptorTypeRef(), e);
				}
			}

			String localFactoryName = raTypeBinding.getActivityContextInterfaceFactoryName();
			if (localFactoryName != null) {
				NameParser parser = ctx.getNameParser("");
				Name local = parser.parse(localFactoryName);
				int nameSize = local.size();
				Context tempCtx = envCtx;

				for (int a = 0; a < nameSize - 1; a++) {
					String temp = local.get(a);
					try {
						tempCtx.lookup(temp);
					} catch (NameNotFoundException ne) {
						tempCtx.createSubcontext(temp);

					} finally {
						tempCtx = (Context) tempCtx.lookup(temp);
					}
				}
				if (logger.isDebugEnabled()) {
					logger
							.debug(
						"Binding a JNDI reference to aci factory interface of "+raTypeBinding.getResourceAdaptorTypeRef());
				}
				String factoryRefName = local.get(nameSize - 1);
				try {
					tempCtx
							.bind(factoryRefName,raTypeComponent.getActivityContextInterfaceFactory());
				} catch (NameAlreadyBoundException e) {
					logger.warn(
							"Unable to bind a JNDI reference to aci factory interface of "+raTypeBinding.getResourceAdaptorTypeRef(), e);
				}
			}

		}

		/*
		 * Bind the ejb-refs
		 */
		try {
			envCtx.createSubcontext("ejb");
		} catch (NameAlreadyBoundException ex) {
			//envCtx = (Context)envCtx.lookup("ejb");
			//6.13.4.1.1 - The SLEE specification recommends, but does not require, that all references to other EJBs be organized
			//in the ejb subcontext of the SBB's environment
			//so it can be any :/
			envCtx.lookup("ejb");
		}

		for (EjbRefDescriptor ejbRef : sbbComponent.getDescriptor().getEjbRefs()) {

			String jndiName = ejbRef.getEjbRefName();

			/*
			 * Validate the ejb reference has the correct type and classes as
			 * specified in deployment descriptor
			 */

			String home = ejbRef.getHome();
			String remote = ejbRef.getRemote();
			//EJBs are bound to global name space.
			//Object obj = new InitialContext().lookup("java:comp/env/" + ejbRef.getEjbRefName());
			Object obj = new InitialContext().lookup( jndiName);

			Object homeObject = null;
			try {

				Class homeClass = Thread.currentThread().getContextClassLoader().loadClass(home);

				homeObject = PortableRemoteObject.narrow(obj, homeClass);

				if (!homeClass.isInstance(homeObject)) {
					throw new DeploymentException("Looked up ejb home is not an instanceof " + home);
				}
			} catch (ClassNotFoundException e) {
				throw new DeploymentException("Failed to load class " + home,e);
			} catch (ClassCastException e) {
				throw new DeploymentException("Failed to lookup ejb reference using jndi name " + jndiName,e);
			}

			try {
				Method m = homeObject.getClass().getMethod("create", null);
				Object ejbObject = m.invoke(homeObject, null);

				Class ejbClass = Thread.currentThread().getContextClassLoader().loadClass(remote);
				if (!ejbClass.isInstance(ejbObject)) {
					throw new DeploymentException("Looked up ejb object is not an instanceof " + remote);
				}
			} catch (ClassNotFoundException e) {
				throw new DeploymentException("Failed to load class " + remote,e);
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Binding ejb: " + ejbRef.getEjbRefName()
					+ " with link to " + jndiName);
			}

			try {
				String name = ejbRef.getEjbRefName();
				NameParser parser = ctx.getNameParser("");
				Name local = parser.parse(name);
				int nameSize = local.size();
				Context tempCtx = createSubContext(envCtx,local);
				tempCtx.bind(local.get(nameSize-1), new LinkRef(jndiName));

			} catch (NameAlreadyBoundException ex) {
				//should not happen, JIC.
			}

			/*
			 * A note on the <ejb-link> link. The semantics of ejb-link when
			 * used to reference a remote ejb are not defined in the SLEE spec.
			 * In J2EE it is defined to mean a reference to an ejb deployed in
			 * the same J2EE application whose <ejb-name> is the same as the
			 * link (optionally the ejb-jar) file is also specifed. In SLEE
			 * there is no J2EE application and ejbs cannot be deployed in the
			 * SLEE container, therefore we do nothing with <ejb-link> since I
			 * am not sure what should be done with it anyway! - Tim
			 */

		}

		/* Set the environment entries */
		for (EnvEntryDescriptor mEnvEntry : sbbComponent.getDescriptor().getEnvEntries()) {
			Class<?> type = null;

			if (logger.isTraceEnabled()) {
				logger.trace("Got an environment entry:" + mEnvEntry);
			}

			try {
				type = Thread.currentThread().getContextClassLoader()
						.loadClass(mEnvEntry.getEnvEntryType());
			} catch (Exception e) {
				throw new DeploymentException(mEnvEntry.getEnvEntryType()
						+ " is not a valid type for an environment entry");
			}
			Object entry = null;
			String s = mEnvEntry.getEnvEntryValue();

			try {
				if (type == String.class) {
					entry = new String(s);
				} else if (type == Character.class) {
					if (s.length() != 1) {
						throw new DeploymentException(
								s
										+ " is not a valid value for an environment entry of type Character");
					}
					entry = new Character(s.charAt(0));
				} else if (type == Integer.class) {
					entry = new Integer(s);
				} else if (type == Boolean.class) {
					entry = new Boolean(s);
				} else if (type == Double.class) {
					entry = new Double(s);
				} else if (type == Byte.class) {
					entry = new Byte(s);
				} else if (type == Short.class) {
					entry = new Short(s);
				} else if (type == Long.class) {
					entry = new Long(s);
				} else if (type == Float.class) {
					entry = new Float(s);
				}
			} catch (NumberFormatException e) {
				throw new DeploymentException("Environment entry value " + s
						+ " is not a valid value for type " + type);
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Binding environment entry with name:"
						+ mEnvEntry.getEnvEntryName() + " type  " + entry.getClass()
						+ " with value:" + entry + ". Current classloader = "
						+ Thread.currentThread().getContextClassLoader());
			}
			try {
				envCtx.bind(mEnvEntry.getEnvEntryName(), entry);
			} catch (NameAlreadyBoundException ex) {
				logger.error("Name already bound ! ", ex);
			}
		}
	}
	private static Context createSubContext(Context ctx,Name local) throws Exception
	{

		int nameSize = local.size();
		Context tempCtx = ctx;

		for (int a = 0; a < nameSize - 1; a++) {
			String temp = local.get(a);
			try {
				tempCtx = (Context) tempCtx.lookup(temp);
			} catch (NameNotFoundException ne) {
				tempCtx = tempCtx.createSubcontext(temp);
			}
		}
		return tempCtx;
	}
	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.SbbManagement#uninstallSbb(org.mobicents.slee.core.component.sbb.SbbComponent)
	 */
	public void uninstallSbb(final SbbComponent sbbComponent)
			throws SystemException, Exception, NamingException {

		final SleeTransactionManager sleeTransactionManager = sleeContainer
				.getTransactionManager();
		sleeTransactionManager.mandateTransaction();

		if (logger.isDebugEnabled())
			logger.debug("Uninstalling "+sbbComponent);

		// remove sbb from trace and alarm facilities
		sleeContainer.getTraceManagement().getTraceFacility().unSetTraceLevel(
				sbbComponent.getSbbID());
		sleeContainer.getAlarmManagement().unRegisterComponent(
				sbbComponent.getSbbID());

		if (logger.isDebugEnabled()) {
			logger.debug("Removed SBB " + sbbComponent.getSbbID()
					+ " from trace and alarm facilities");
		}

		sleeContainer.getJndiManagement().componentUninstall(sbbComponent);

		// if we are in cluster mode we need to remove the sbb class loader domain from the replication class loader
		if (!sleeContainer.getCluster().getMobicentsCache().isLocalMode()) {
			final ReplicationClassLoader replicationClassLoader = sleeContainer.getReplicationClassLoader();
			TransactionalAction action2 = new TransactionalAction() {
				public void execute() {
					replicationClassLoader.removeDomain(sbbComponent.getClassLoaderDomain());
				}
			};
			sleeTransactionManager.getTransactionContext().getAfterCommitActions().add(action2);
		}

	}

}


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

package org.mobicents.slee.runtime.sbbentity;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.AbstractSleeContainerModule;
import org.mobicents.slee.container.sbbentity.SbbEntity;
import org.mobicents.slee.container.sbbentity.SbbEntityFactory;
import org.mobicents.slee.container.sbbentity.SbbEntityID;
import org.mobicents.slee.container.transaction.TransactionContext;
import org.mobicents.slee.container.transaction.TransactionalAction;

import javax.slee.CreateException;
import javax.slee.SLEEException;
import javax.slee.ServiceID;
import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 *
 * SbbEntityFactory -- implements a map from SBB Entity Id to SBB Entity
 * instances. This is the sole place where Sbb Entities are created and
 * destroyed. We keep a map of SBB Entity ID to SBB Entity here and return Sbb
 * Entities that are stored in this map.
 *
 * @author F.Moggia
 * @author M. Ranganathan
 * @author Tim Fox ( streamlining )
 * @author eduardomartins
 */
public class SbbEntityFactoryImpl extends AbstractSleeContainerModule implements SbbEntityFactory {

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

	private static final boolean doTraceLogs = logger.isTraceEnabled();

	protected SbbEntityLockFacility lockFacility;

	private final SbbEntityIDComparator sbbEntityIDComparator = new SbbEntityIDComparator(this);

	@Override
	public void sleeInitialization() {
		// SergeyLee: test
		this.lockFacility = new SbbEntityLockFacility(sleeContainer);
	}

	@Override
	public void sleeStarting() {
		// init cache data
		new SbbEntityFactoryCacheData(sleeContainer.getCluster()).create();
	}

	@Override
	public SbbEntity createNonRootSbbEntity(SbbEntityID parentSbbEntityID,String parentChildRelation, String childName) throws CreateException {

		// it is assumed that parent root sbb entity is loaded, thus no lock needed

		// create sbb entity
		final NonRootSbbEntityID sbbeId = new NonRootSbbEntityID(parentSbbEntityID, parentChildRelation, childName);
		final SbbEntityCacheData cacheData = new SbbEntityCacheData(sbbeId,sleeContainer.getCluster().getMobicentsCache());
		if (cacheData.exists()) {
			throw new CreateException("sbb entity with name "+childName+" already exists");
		}
		cacheData.create();

		final SbbEntityImpl sbbEntity = new SbbEntityImpl(sbbeId, cacheData, true, this);

		// store it in the tx, we need to do it due to sbb local object and
		// current storing in sbb entity per tx
		storeSbbEntityInTx(sbbEntity, sleeContainer.getTransactionManager().getTransactionContext());

		return sbbEntity;

	}

	@Override
	public SbbEntity createRootSbbEntity(ServiceID serviceID,
			String convergenceName) {

		final RootSbbEntityID sbbeId = new RootSbbEntityID(serviceID, convergenceName);

		final TransactionContext txContext = sleeContainer.getTransactionManager().getTransactionContext();

		// get lock
		final ReentrantLock lock = lockFacility.get(sbbeId);
		lockOrFail(lock,sbbeId);
		// we hold the lock now

		// create sbb entity
		final SbbEntityCacheData cacheData = new SbbEntityCacheData(sbbeId,sleeContainer.getCluster().getMobicentsCache());
		SbbEntityImpl sbbEntity = null;
		if (cacheData.create()) {
			sbbEntity = new SbbEntityImpl(sbbeId, cacheData, true, this);
			// add tx actions wrt lock
			final TransactionalAction rollbackTxAction = new TransactionalAction() {
				@Override
				public void execute() {
					lockFacility.remove(sbbeId);
					lock.unlock();
				}
			};
			final TransactionalAction commitTxAction = new TransactionalAction() {
				@Override
				public void execute() {
					lock.unlock();
				}
			};
			txContext.getAfterRollbackActions().add(rollbackTxAction);
			txContext.getAfterCommitActions().add(commitTxAction);

		}
		else {
			sbbEntity = new SbbEntityImpl(sbbeId, cacheData, false, this);
			// add tx actions wrt lock
			final TransactionalAction txAction = new TransactionalAction() {
				@Override
				public void execute() {
					lock.unlock();
				}
			};
			txContext.getAfterRollbackActions().add(txAction);
			txContext.getAfterCommitActions().add(txAction);
		}

		// store it in the tx, we need to do it due to sbb local object and
		// current storing in sbb entity per tx
		storeSbbEntityInTx(sbbEntity, txContext);

		return sbbEntity;
	}

	@Override
	public Set<SbbEntityID> getRootSbbEntityIDs(ServiceID serviceID) {
		final SbbEntityFactoryCacheData cacheData = new SbbEntityFactoryCacheData(sleeContainer.getCluster());
		if (cacheData.exists()) {
			logger.debug("SbbEntityFactoryCacheData: "+cacheData);
			return cacheData.getRootSbbEntityIDs(serviceID);
		}
		else {
			return Collections.emptySet();
		}
	}

	public void WAremove() {
		final SbbEntityFactoryCacheData cacheData = new SbbEntityFactoryCacheData(sleeContainer.getCluster());
		cacheData.WAremove();
	}

	@Override
	public SbbEntity getSbbEntity(SbbEntityID sbbeId, boolean lockSbbEntity) {

		if (sbbeId == null)
			throw new NullPointerException("Null Sbbeid");

		/*
		 * NB!! We must not use a map to cache sbb entities. There can be
		 * multiple active transactions each of which accesses the same sbb
		 * entity at any one time in the SLEE. Therefore, by using a map to
		 * store the sbb entities one tx can see the transactional state of the
		 * other tx before it has committed. I.e. we would have no transaction
		 * isolation. Instead, if we want to cache the sbb entity for the
		 * lifetime of the tx for performance reasons, we need to store in a
		 * *per transaction* cache
		 */

		final TransactionContext txContext = sleeContainer.getTransactionManager().getTransactionContext();

		// Look for it in the per transaction cache
		SbbEntityImpl sbbEntity = getSbbEntityFromTx(sbbeId, txContext);

		if (sbbEntity == null) {

			if (doTraceLogs)
				logger.trace("Loading sbb entity " + sbbeId + " from cache");

			// lock before retrieving from cache?
			ReentrantLock lock = null;
			SbbEntityID lockedSbbEntityID = null;
			if (lockSbbEntity) {
				lockedSbbEntityID = sbbeId.getRootSBBEntityID();
				lock = lockFacility.get(lockedSbbEntityID);
				lockOrFail(lock,lockedSbbEntityID);
			}

			// get sbb entity data from cache
			final SbbEntityCacheData cacheData = new SbbEntityCacheData(sbbeId,sleeContainer.getCluster().getMobicentsCache());
			if (!cacheData.exists()) {
				if(lock != null) {
					lockFacility.remove(lockedSbbEntityID);
					lock.unlock();
				}
				return null;
			}

			// build sbb entity instance
			sbbEntity = new SbbEntityImpl(sbbeId,cacheData,false,this);

			if(lock != null) {
				// add tx actions wrt lock
				final ReentrantLock fLock = lock;
				final TransactionalAction txAction = new TransactionalAction() {
					@Override
					public void execute() {
						fLock.unlock();
					}
				};
				txContext.getAfterRollbackActions().add(txAction);
				txContext.getAfterCommitActions().add(txAction);
			}

			// store it in the tx, we need to do it due to sbb local object and
			// current storing in sbb entity per tx
			storeSbbEntityInTx(sbbEntity, txContext);
		}
		return sbbEntity;

	}

	@Override
	public void removeSbbEntity(SbbEntity sbbEntity,
			boolean useCurrentClassLoader) {

		if (useCurrentClassLoader) {
			removeSbbEntityWithCurrentClassLoader(sbbEntity);
		}
		else {
			ClassLoader oldClassLoader = Thread.currentThread()
			.getContextClassLoader();
			try {
				Thread.currentThread().setContextClassLoader(
						sbbEntity.getSbbComponent().getClassLoader());
				removeSbbEntityWithCurrentClassLoader(sbbEntity);
			} finally {
				// restore old class loader
				Thread.currentThread().setContextClassLoader(oldClassLoader);
			}
		}
	}

	/**
	 * Removes the specified sbb entity but without changing to sbb's class
	 * loader first.
	 *
	 * @param sbbEntity
	 *            the sbb entity to remove
	 */
	private void removeSbbEntityWithCurrentClassLoader(
			final SbbEntity sbbEntity) {
		// remove entity
		sbbEntity.remove();
		// remove from tx data
		final TransactionContext txContext = sleeContainer.getTransactionManager().getTransactionContext();
		final SbbEntityID sbbEntityID = sbbEntity.getSbbEntityId();
		txContext.getData().remove(sbbEntityID);
		// if sbb entity is root add a tx action to ensure lock is removed
		if (sbbEntityID.isRootSbbEntity()) {
			TransactionalAction txAction = new TransactionalAction() {
				@Override
				public void execute() {
					lockFacility.remove(sbbEntityID);
				}
			};
			txContext.getAfterCommitActions().add(txAction);
		}
	}

	// --- helpers

	/**
	 *
	 * @param sbbEntity
	 * @param txContext
	 */
	@SuppressWarnings("unchecked")
	private static void storeSbbEntityInTx(SbbEntityImpl sbbEntity,
			TransactionContext txContext) {
		if (txContext != null)
			txContext.getData().put(
					sbbEntity.getSbbEntityId(), sbbEntity);
	}

	/**
	 *
	 * @param sbbeId
	 * @param txContext
	 * @return
	 */
	private static SbbEntityImpl getSbbEntityFromTx(SbbEntityID sbbeId,
			TransactionContext txContext) {
		return txContext != null ? (SbbEntityImpl) txContext.getData().get(
					sbbeId) : null;
	}

	/**
	 *
	 * @param lock
	 * @param sbbeId
	 * @throws SLEEException
	 */
	private static void lockOrFail(ReentrantLock lock, SbbEntityID sbbeId) throws SLEEException {
		if (doTraceLogs) {
			logger.trace(Thread.currentThread()+" trying to acquire lock "+lock+" for sbb entity with id "+sbbeId);
		}
		boolean locked;
		try {
			locked = lock.tryLock(10, TimeUnit.SECONDS);
		}
		catch (Throwable e) {
			throw new SLEEException(e.getMessage(),e);
		}
		if (!locked) {
			throw new SLEEException("timeout while acquiring lock "+lock+" for sbb entity with id "+sbbeId);
		}
		if (doTraceLogs) {
			logger.trace(Thread.currentThread()+" acquired lock "+lock+" for sbb entity with id "+sbbeId);
		}
	}

	@Override
	public Set<SbbEntityID> getSbbEntityIDs() {
		final SbbEntityFactoryCacheData cacheData = new SbbEntityFactoryCacheData(sleeContainer.getCluster());
		if (cacheData.exists()) {
			return cacheData.getSbbEntities();
		}
		else {
			return Collections.emptySet();
		}
	}

	@Override
	public Set<SbbEntityID> sortByPriority(Set<SbbEntityID> ids) {
		final Set<SbbEntityID> orderSbbSet = new TreeSet<SbbEntityID>(sbbEntityIDComparator);
		orderSbbSet.addAll(ids);
		return orderSbbSet;
	}
}


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

package org.mobicents.slee.container.management.jmx;

import java.io.File;
import java.net.MalformedURLException;
import java.security.Policy;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.management.NotCompliantMBeanException;
import javax.slee.ComponentID;
import javax.slee.EventTypeID;
import javax.slee.InvalidStateException;
import javax.slee.SLEEException;
import javax.slee.SbbID;
import javax.slee.ServiceID;
import javax.slee.UnrecognizedComponentException;
import javax.slee.UnrecognizedServiceException;
import javax.slee.management.AlreadyDeployedException;
import javax.slee.management.ComponentDescriptor;
import javax.slee.management.DependencyException;
import javax.slee.management.DeployableUnitDescriptor;
import javax.slee.management.DeployableUnitID;
import javax.slee.management.DeploymentException;
import javax.slee.management.LibraryID;
import javax.slee.management.ManagementException;
import javax.slee.management.UnrecognizedDeployableUnitException;
import javax.slee.profile.ProfileSpecificationID;
import javax.slee.resource.ResourceAdaptorID;
import javax.slee.resource.ResourceAdaptorTypeID;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.component.common.EnvEntryDescriptor;
import org.mobicents.slee.container.component.ComponentRepository;
import org.mobicents.slee.container.component.SleeComponent;
import org.mobicents.slee.container.component.du.DeployableUnit;
import org.mobicents.slee.container.component.du.DeployableUnitBuilder;
import org.mobicents.slee.container.component.du.DeployableUnitManagement;
import org.mobicents.slee.container.component.event.EventTypeComponent;
import org.mobicents.slee.container.component.library.LibraryComponent;
import org.mobicents.slee.container.component.profile.ProfileSpecificationComponent;
import org.mobicents.slee.container.component.ra.ResourceAdaptorComponent;
import org.mobicents.slee.container.component.ratype.ResourceAdaptorTypeComponent;
import org.mobicents.slee.container.component.sbb.SbbComponent;
import org.mobicents.slee.container.component.security.PermissionHolder;
import org.mobicents.slee.container.component.security.PolicyFile;
import org.mobicents.slee.container.component.service.ServiceComponent;
import org.mobicents.slee.container.deployment.jboss.SleeContainerDeployerImpl;
import org.mobicents.slee.container.management.ResourceManagement;
import org.mobicents.slee.container.management.ServiceManagement;
import org.mobicents.slee.container.transaction.SleeTransactionManager;

/**
 *
 * TODO rework all the deployment mess, there should be a single internal deployer and this mbean should just delegate operations to it.
 * Implementation of the deployment MBean.
 *
 * @author M. Ranganathan
 * @author DERUELLE Jean - bug fix throw UnrecognizedDeployableUnitException on
 *         method getDescriptor(DeplyableUnit) if no descriptor has been found
 * @author Eduardo Martins
 */
public class DeploymentMBeanImpl extends MobicentsServiceMBeanSupport implements
		DeploymentMBeanImplMBean {

	private File tempDUJarsDeploymentRoot;

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

	private final SleeContainerDeployerImpl deployer;

	public DeploymentMBeanImpl(SleeContainerDeployerImpl deployer) {
		super(deployer.getSleeContainer());
		this.tempDUJarsDeploymentRoot = createTempDUJarsDeploymentRoot();
		this.deployer = deployer;
		deployer.setDeploymentMBean(this);
	}

	/**
	 *
	 * Sets the root directory that will be used for unpacking DU jars.
	 *
	 * @TODO: make sure to remove this directory on undeploy
	 *
	 */
	private File createTempDUJarsDeploymentRoot() {

		File tempDeploymentRootDir = new File(getSleeContainer().getDeployPath());
		if (!tempDeploymentRootDir.exists()) {
			boolean dirCreated = tempDeploymentRootDir.mkdirs();
			if (!dirCreated)
				throw new SLEEException(
						"failed to create temp deployment dir: "
								+ tempDeploymentRootDir);
		}
		return tempDeploymentRootDir;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#install(java.lang.String)
	 */
	public DeployableUnitID install(String url) throws NullPointerException,
			MalformedURLException, AlreadyDeployedException,
			DeploymentException, ManagementException {

		try {
			final SleeContainer sleeContainer = getSleeContainer();
			final DeployableUnitBuilder deployableUnitBuilder = sleeContainer.getDeployableUnitManagement().getDeployableUnitBuilder();
			final SleeTransactionManager sleeTransactionManager = sleeContainer
					.getTransactionManager();
			final ComponentRepository componentRepositoryImpl = sleeContainer
					.getComponentRepository();
			final DeployableUnitManagement deployableUnitManagement = sleeContainer
					.getDeployableUnitManagement();

			synchronized (sleeContainer.getManagementMonitor()) {

				DeployableUnitID deployableUnitID = new DeployableUnitID(url);

				logger.info("Installing " +deployableUnitID);

				if (deployableUnitManagement
						.getDeployableUnit(deployableUnitID) != null) {
					throw new AlreadyDeployedException(
							"there is already a DU deployed for url " + url);
				}

				DeployableUnit deployableUnit = null;

				Thread currentThread = Thread.currentThread();
				ClassLoader currentClassLoader = currentThread
						.getContextClassLoader();

				Set<SleeComponent> componentsInstalled = new HashSet<SleeComponent>();
				boolean rollback = true;
				try {
					// start transaction
					sleeTransactionManager.begin();
					// build du
					deployableUnit = deployableUnitBuilder.build(url,
							tempDUJarsDeploymentRoot, componentRepositoryImpl);
					// install each component built
					for (LibraryComponent component : deployableUnit
							.getLibraryComponents().values()) {
						componentRepositoryImpl.putComponent(component);
						updateSecurityPermissions(component, false);
						logger.info("Installed " + component);
					}
					for (EventTypeComponent component : deployableUnit
							.getEventTypeComponents().values()) {
						componentRepositoryImpl.putComponent(component);
						logger.info("Installed " + component);
					}
					for (ResourceAdaptorTypeComponent component : deployableUnit
							.getResourceAdaptorTypeComponents().values()) {
						componentRepositoryImpl.putComponent(component);
						currentThread.setContextClassLoader(component
								.getClassLoader());
						sleeContainer.getResourceManagement()
								.installResourceAdaptorType(component);
						componentsInstalled.add(component);
						logger.info("Installed " + component);
					}
					// before executing the logic to install an profile spec, ra
					// or sbb insert the components in the repo, a component can
					// require that another is already in repo
					for (ProfileSpecificationComponent component : deployableUnit
							.getProfileSpecificationComponents().values()) {
						componentRepositoryImpl.putComponent(component);
					}
					for (ResourceAdaptorComponent component : deployableUnit
							.getResourceAdaptorComponents().values()) {
						componentRepositoryImpl.putComponent(component);
					}
					for (SbbComponent component : deployableUnit
							.getSbbComponents().values()) {
						componentRepositoryImpl.putComponent(component);
					}
					// run the install logic to install an profile spec, ra or
					// sbb
					for (ProfileSpecificationComponent component : deployableUnit
							.getProfileSpecificationComponents().values()) {
						currentThread.setContextClassLoader(component
								.getClassLoader());
						sleeContainer.getSleeProfileTableManager()
								.installProfileSpecification(component);
						componentsInstalled.add(component);
						updateSecurityPermissions(component, false);
						logger.info("Installed " + component);
					}
					for (ResourceAdaptorComponent component : deployableUnit
							.getResourceAdaptorComponents().values()) {
						currentThread.setContextClassLoader(component
								.getClassLoader());
						sleeContainer.getResourceManagement()
								.installResourceAdaptor(component);
						componentsInstalled.add(component);
						updateSecurityPermissions(component, false);
						logger.info("Installed " + component);
					}
					for (SbbComponent component : deployableUnit
							.getSbbComponents().values()) {
						currentThread.setContextClassLoader(component
								.getClassLoader());
						sleeContainer.getSbbManagement().installSbb(component);
						componentsInstalled.add(component);
						updateSecurityPermissions(component, false);
						logger.info("Installed " + component);
					}
					// finally install the services
					currentThread.setContextClassLoader(currentClassLoader);
					for (ServiceComponent component : deployableUnit
							.getServiceComponents().values()) {
						componentRepositoryImpl.putComponent(component);
						sleeContainer.getServiceManagement().installService(
								component);
						componentsInstalled.add(component);
						logger.info("Installed " + component+". Root sbb is "+component.getRootSbbComponent());
					}

					deployableUnitManagement.addDeployableUnit(deployableUnit);
					logger.info("Installed " +deployableUnitID);
					updateSecurityPermissions(null, true);
					rollback = false;

					return deployableUnitID;
				} finally {
					currentThread.setContextClassLoader(currentClassLoader);
					try {
						if (rollback) {
							if (deployableUnit != null) {
								// remove all components added to repo
								// put all components in the repo again
								for (LibraryComponent component : deployableUnit
										.getLibraryComponents().values()) {
									removeSecurityPermissions(component, false);
									componentRepositoryImpl.removeComponent(component.getLibraryID());
									logger.info("Uninstalled " + component
											+ " due to tx rollback");
								}
								for (EventTypeComponent component : deployableUnit
										.getEventTypeComponents().values()) {
									componentRepositoryImpl.removeComponent(component.getEventTypeID());
									logger.info("Uninstalled " + component
											+ " due to tx rollback");
								}
								for (ResourceAdaptorTypeComponent component : deployableUnit
										.getResourceAdaptorTypeComponents()
										.values()) {
									removeSecurityPermissions(component, false);
									if(componentsInstalled.contains(component)) {
										sleeContainer.getResourceManagement().uninstallResourceAdaptorType(component);
									}
									componentRepositoryImpl.removeComponent(component.getResourceAdaptorTypeID());
									logger.info("Uninstalled " + component
											+ " due to tx rollback");
								}
								for (ProfileSpecificationComponent component : deployableUnit
										.getProfileSpecificationComponents()
										.values()) {
									if(componentsInstalled.contains(component)) {
										sleeContainer.getSleeProfileTableManager().uninstallProfileSpecification(component);
									}
									componentRepositoryImpl.removeComponent(component.getProfileSpecificationID());
									logger.info("Uninstalled " + component
											+ " due to tx rollback");
								}
								for (ResourceAdaptorComponent component : deployableUnit
										.getResourceAdaptorComponents().values()) {
									removeSecurityPermissions(component, false);
									if(componentsInstalled.contains(component)) {
										sleeContainer.getResourceManagement().uninstallResourceAdaptor(component);
									}
									componentRepositoryImpl.removeComponent(component.getResourceAdaptorID());
									logger.info("Uninstalled " + component
											+ " due to tx rollback");
								}
								for (SbbComponent component : deployableUnit
										.getSbbComponents().values()) {
									removeSecurityPermissions(component, false);
									if(componentsInstalled.contains(component)) {
										sleeContainer.getSbbManagement().uninstallSbb(component);
									}
									componentRepositoryImpl.removeComponent(component.getSbbID());
									logger.info("Uninstalled " + component
											+ " due to tx rollback");
								}
								for (ServiceComponent component : deployableUnit
										.getServiceComponents().values()) {
									if(componentsInstalled.contains(component)) {
										sleeContainer.getServiceManagement().uninstallService(component);
									}
									componentRepositoryImpl.removeComponent(component.getServiceID());
									logger.info("Uninstalled " + component
											+ " due to tx rollback");
								}
								removeSecurityPermissions(null, true);
								// undeploy the unit
								deployableUnit.undeploy();
							}
							sleeTransactionManager.rollback();
						} else {
							sleeTransactionManager.commit();
						}
					} catch (Exception ex) {
						throw new ManagementException(
								"Exception while completing transaction", ex);
					}
				}
			}
		} catch (AlreadyDeployedException e) {
			throw e;
		} catch (DeploymentException e) {
			// This will remove stack trace;
			// throw e;
			throw new DeploymentException(
					"Failure encountered during deploy process.", e);
		} catch (Throwable e) {
			if (logger.isDebugEnabled()) {
				logger.debug(e.getMessage(),e);
			}
			throw new ManagementException(e.getMessage(), e);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#uninstall(javax.slee.management.DeployableUnitID)
	 */
	public void uninstall(DeployableUnitID deployableUnitID)
			throws NullPointerException, UnrecognizedDeployableUnitException,
			DependencyException, InvalidStateException, ManagementException {

		logger.info("Uninstalling " +deployableUnitID);

		final SleeContainer sleeContainer = getSleeContainer();
		final SleeTransactionManager sleeTransactionManager = sleeContainer
				.getTransactionManager();
		final ServiceManagement serviceManagement = sleeContainer
				.getServiceManagement();
		final ResourceManagement resourceManagement = sleeContainer
				.getResourceManagement();
		final DeployableUnitManagement deployableUnitManagement = sleeContainer
				.getDeployableUnitManagement();
		final ComponentRepository componentRepositoryImpl = sleeContainer
				.getComponentRepository();

		// we sync on the container's monitor object
		synchronized (sleeContainer.getManagementMonitor()) {

			if (this.isInstalled(deployableUnitID)) {

				Thread currentThread = Thread.currentThread();
				ClassLoader currentClassLoader = currentThread
						.getContextClassLoader();

				DeployableUnit deployableUnit = null;
				boolean rollback = true;
				try {
					// start transaction
					sleeTransactionManager.begin();
					// get du
					deployableUnit = deployableUnitManagement
							.getDeployableUnit(deployableUnitID);

					// Check if its safe to remove the deployable unit.
					for (SleeComponent sleeComponent : deployableUnit
							.getDeployableUnitComponents()) {
						for (SleeComponent referringComponent : sleeContainer
								.getComponentRepository()
								.getReferringComponents(sleeComponent)) {
							if (!referringComponent.getDeployableUnit()
									.getDeployableUnitID().equals(
											deployableUnitID)) {
								throw new DependencyException("Component "
										+ referringComponent
										+ " refers DU component "
										+ sleeComponent);
							}
						}
					}

					for (ServiceComponent component : deployableUnit
							.getServiceComponents().values()) {
						serviceManagement.uninstallService(component);
						componentRepositoryImpl.removeComponent(component
								.getServiceID());
						logger.info("Uninstalled " + component);
					}

					for (SbbComponent component : deployableUnit
							.getSbbComponents().values()) {
						currentThread.setContextClassLoader(component
								.getClassLoader());
						removeSecurityPermissions(component, false);
						sleeContainer.getSbbManagement()
								.uninstallSbb(component);
						componentRepositoryImpl.removeComponent(component
								.getSbbID());
						logger.info("Uninstalled " + component);
					}

					for (ResourceAdaptorComponent component : deployableUnit
							.getResourceAdaptorComponents().values()) {
						removeSecurityPermissions(component, false);
						resourceManagement.uninstallResourceAdaptor(component);
						componentRepositoryImpl.removeComponent(component
								.getResourceAdaptorID());
						logger.info("Uninstalled " + component);
					}

					for (ProfileSpecificationComponent component : deployableUnit
							.getProfileSpecificationComponents().values()) {
						currentThread.setContextClassLoader(component
								.getClassLoader());
						removeSecurityPermissions(component, false);
						sleeContainer.getSleeProfileTableManager()
								.uninstallProfileSpecification(component);
						componentRepositoryImpl.removeComponent(component
								.getProfileSpecificationID());
						logger.info("Uninstalled " + component);
					}

					for (ResourceAdaptorTypeComponent component : deployableUnit
							.getResourceAdaptorTypeComponents().values()) {
						resourceManagement
								.uninstallResourceAdaptorType(component);
						componentRepositoryImpl.removeComponent(component
								.getResourceAdaptorTypeID());
						logger.info("Uninstalled " + component);
					}

					for (EventTypeID componentID : deployableUnit
							.getEventTypeComponents().keySet()) {
						componentRepositoryImpl.removeComponent(componentID);
						logger.info("Uninstalled " + componentID);
					}

					for (LibraryID componentID : deployableUnit
							.getLibraryComponents().keySet()) {
						removeSecurityPermissions(componentRepositoryImpl.getComponentByID(componentID), false);
						componentRepositoryImpl.removeComponent(componentID);
						logger.info("Uninstalled " + componentID);
					}
					removeSecurityPermissions(null,true);
					// remove du
					deployableUnitManagement
							.removeDeployableUnit(deployableUnitID);

					rollback = false;

					logger.info("Uninstalled " +deployableUnitID);

				} catch (InvalidStateException ex) {
					logger.error(ex.getMessage(), ex);
					throw ex;
				} catch (DependencyException ex) {
					logger.error(ex.getMessage(), ex);
					throw ex;
				} catch (Throwable ex) {
					if (logger.isDebugEnabled())
						logger.debug(ex.getMessage(),ex);
					throw new ManagementException(
							"Exception removing deployable Unit ", ex);
				} finally {

					currentThread.setContextClassLoader(currentClassLoader);

					try {
						if (rollback) {
							if (deployableUnit != null) {
								// put all components in the repo again
								for (LibraryComponent component : deployableUnit
										.getLibraryComponents().values()) {
									if (componentRepositoryImpl.putComponent(component)) {
										updateSecurityPermissions(component, false);
										logger.info("Reinstalled " + component
												+ " due to tx rollback");
									}
								}
								for (EventTypeComponent component : deployableUnit
										.getEventTypeComponents().values()) {
									if (componentRepositoryImpl.putComponent(component)) {
									logger.info("Reinstalled " + component
											+ " due to tx rollback");
									}
								}
								for (ResourceAdaptorTypeComponent component : deployableUnit
										.getResourceAdaptorTypeComponents()
										.values()) {
									if (componentRepositoryImpl.putComponent(component)) {
									logger.info("Reinstalled " + component
											+ " due to tx rollback");
									}
								}
								for (ProfileSpecificationComponent component : deployableUnit
										.getProfileSpecificationComponents()
										.values()) {
									if (componentRepositoryImpl.putComponent(component)) {
										updateSecurityPermissions(component, false);
									logger.info("Reinstalled " + component
											+ " due to tx rollback");
									}
								}
								for (ResourceAdaptorComponent component : deployableUnit
										.getResourceAdaptorComponents().values()) {
									if (componentRepositoryImpl.putComponent(component)) {
										updateSecurityPermissions(component, false);
									logger.info("Reinstalled " + component
											+ " due to tx rollback");
									}
								}
								for (SbbComponent component : deployableUnit
										.getSbbComponents().values()) {
									if (componentRepositoryImpl.putComponent(component)) {
										updateSecurityPermissions(component, false);
									logger.info("Reinstalled " + component
											+ " due to tx rollback");
									}
								}
								for (ServiceComponent component : deployableUnit
										.getServiceComponents().values()) {
									if (componentRepositoryImpl.putComponent(component)) {
									logger.info("Reinstalled " + component
											+ " due to tx rollback");
									}
								}
								updateSecurityPermissions(null, true);
								deployableUnitManagement
								.addDeployableUnit(deployableUnit);
							}
							sleeTransactionManager.rollback();
						} else {
							sleeTransactionManager.commit();

							// FIXME: For JBoss 7.2.0.Final:
							// we have a problem with org.hibernate.service.UnknownServiceException:
							// Unknown service requested [org.hibernate.event.service.spi.EventListenerRegistry]
							// see https://hibernate.atlassian.net/browse/HHH-8586
							for (ProfileSpecificationComponent component : deployableUnit
									.getProfileSpecificationComponents().values()) {
								currentThread.setContextClassLoader(component
										.getClassLoader());
								removeSecurityPermissions(component, false);
								sleeContainer.getSleeProfileTableManager()
										.closeEntityManagerFactory(component);
								logger.info("Finalized " + component);
							}

							// Clean up all the class files.
							deployableUnit.undeploy();
						}
					} catch (Throwable ex) {
						throw new ManagementException(
								"Exception while completing transaction", ex);
					}

				}
			} else {
				throw new UnrecognizedDeployableUnitException(
						"deployable unit " + deployableUnitID);
			}
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#getDeployableUnit(java.lang.String)
	 */
	public DeployableUnitID getDeployableUnit(String deploymentUrl)
			throws NullPointerException, UnrecognizedDeployableUnitException,
			ManagementException {

		DeployableUnitID deployableUnitID = new DeployableUnitID(deploymentUrl);

		boolean duExists = true;
		try {
			if (getSleeContainer().getDeployableUnitManagement()
					.getDeployableUnit(deployableUnitID) == null) {
				duExists = false;
			}
		} catch (Throwable e) {
			throw new ManagementException(e.getMessage(), e);
		}
		if (duExists) {
			return deployableUnitID;
		} else {
			throw new UnrecognizedDeployableUnitException(deploymentUrl);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#getDeployableUnits()
	 */
	public DeployableUnitID[] getDeployableUnits() throws ManagementException {
		try {
			return getSleeContainer().getDeployableUnitManagement()
					.getDeployableUnits();
		} catch (Throwable e) {
			throw new ManagementException("failed to get deployable units", e);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#getSbbs()
	 */
	public SbbID[] getSbbs() throws ManagementException {
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("getSbbs()");
			}
			return getSleeContainer().getComponentRepository()
					.getSbbIDs().toArray(new SbbID[0]);
		} catch (Throwable ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#getEventTypes()
	 */
	public EventTypeID[] getEventTypes() throws ManagementException {
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("getEventTypes()");
			}
			return getSleeContainer().getComponentRepository()
					.getEventComponentIDs().toArray(new EventTypeID[0]);
		} catch (Throwable ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#getProfileSpecifications()
	 */
	public ProfileSpecificationID[] getProfileSpecifications()
			throws ManagementException {
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("getProfileSpecifications()");
			}
			return getSleeContainer().getComponentRepository()
					.getProfileSpecificationIDs().toArray(
							new ProfileSpecificationID[0]);
		} catch (Throwable ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#getServices()
	 */
	public ServiceID[] getServices() throws ManagementException {
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("getServices()");
			}
			return getSleeContainer().getComponentRepository()
					.getServiceIDs().toArray(new ServiceID[0]);
		} catch (Throwable ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#getResourceAdaptorTypes()
	 */
	public ResourceAdaptorTypeID[] getResourceAdaptorTypes()
			throws ManagementException {
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("getResourceAdaptorTypes()");
			}
			return getSleeContainer().getComponentRepository()
					.getResourceAdaptorTypeIDs().toArray(
							new ResourceAdaptorTypeID[0]);
		} catch (Throwable ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#getResourceAdaptors()
	 */
	public ResourceAdaptorID[] getResourceAdaptors() throws ManagementException {
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("getResourceAdaptors()");
			}
			return getSleeContainer().getComponentRepository()
					.getResourceAdaptorIDs().toArray(new ResourceAdaptorID[0]);
		} catch (Throwable ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#getReferringComponents(javax.slee.ComponentID)
	 */
	public ComponentID[] getReferringComponents(ComponentID componentId)
			throws NullPointerException, UnrecognizedComponentException,
			ManagementException {

		try {
			return getSleeContainer().getComponentRepository()
					.getReferringComponents(componentId);
		} catch (NullPointerException ex) {
			throw ex;
		} catch (UnrecognizedComponentException ex) {
			throw ex;
		} catch (Throwable ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#getDescriptor(javax.slee.management.DeployableUnitID)
	 */
	public DeployableUnitDescriptor getDescriptor(
			DeployableUnitID deployableUnitID) throws NullPointerException,
			UnrecognizedDeployableUnitException, ManagementException {

		if (deployableUnitID == null)
			throw new NullPointerException(
					"deployableUnitID should not be null");

		DeployableUnitDescriptor dud = null;
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("getDescriptor " + deployableUnitID);
			}
			DeployableUnit du = getSleeContainer()
					.getDeployableUnitManagement().getDeployableUnit(
							deployableUnitID);
			if (du != null) {
				dud = du.getSpecsDeployableUnitDescriptor();
			}
		} catch (Throwable ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}

		if (dud == null) {
			throw new UnrecognizedDeployableUnitException(
					"unrecognized deployable unit " + deployableUnitID);
		} else {
			return dud;
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#getDescriptors(javax.slee.management.DeployableUnitID[])
	 */
	public DeployableUnitDescriptor[] getDescriptors(DeployableUnitID[] duIds)
			throws NullPointerException, ManagementException {
		if (duIds == null)
			throw new NullPointerException("Null arg!");

		final DeployableUnitManagement deployableUnitManagement = getSleeContainer().getDeployableUnitManagement();
		try {
			Set<DeployableUnitDescriptor> result = new HashSet<DeployableUnitDescriptor>();
			for (DeployableUnitID deployableUnitID : deployableUnitManagement
					.getDeployableUnits()) {
				DeployableUnit deployableUnit = deployableUnitManagement
						.getDeployableUnit(deployableUnitID);
				result.add(deployableUnit.getSpecsDeployableUnitDescriptor());
			}
			return result.toArray(new DeployableUnitDescriptor[0]);
		} catch (Throwable ex) {
			throw new ManagementException("Error in tx manager ", ex);
		}

	}
	public String[] getEnvEntries(ComponentID componentID)
			throws NullPointerException, UnrecognizedComponentException,
			ManagementException {
		if (componentID == null)
			throw new NullPointerException("null component ID");
		if (logger.isDebugEnabled()) {
			logger.debug("getEnvEntries: componentID " + componentID);
		}
		try {
			ComponentRepository componentRepositoryImpl = getSleeContainer().getComponentRepository();
			SleeComponent component = null;
			if (componentID instanceof SbbID) {
				component = componentRepositoryImpl
						.getComponentByID((SbbID) componentID);
				List<EnvEntryDescriptor> envEntries = ((SbbComponent)component).getEnvEntries();
				String[] envEntriesString = new String[envEntries.size()];
				for (int i = 0; i < envEntries.size(); i++) {
					envEntriesString[i] = envEntries.get(i).toString();
				}
				return envEntriesString;
			}
			else
				return null;
		} catch (Throwable ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}
	}
	 static public String[] toStringArray(EnvEntryDescriptor[] envEntries) {
	     if (envEntries == null)
	       return null;

	     String[] stringArray = new String[envEntries.length];

	     for (int i = 0; i < envEntries.length; i++)
	       stringArray[i] = envEntries[i].toString();

	     return stringArray;
	   }
	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#getDescriptor(javax.slee.ComponentID)
	 */
	public ComponentDescriptor getDescriptor(ComponentID componentID)
			throws NullPointerException, UnrecognizedComponentException,
			ManagementException {
		if (componentID == null)
			throw new NullPointerException("null component ID");

		if (logger.isDebugEnabled()) {
			logger.debug("getDescriptor: componentID " + componentID);
		}

		try {
			ComponentRepository componentRepositoryImpl = getSleeContainer().getComponentRepository();
			SleeComponent component = null;
			if (componentID instanceof EventTypeID) {
				component = componentRepositoryImpl
						.getComponentByID((EventTypeID) componentID);
			} else if (componentID instanceof LibraryID) {
				component = componentRepositoryImpl
						.getComponentByID((LibraryID) componentID);
			} else if (componentID instanceof ProfileSpecificationID) {
				component = componentRepositoryImpl
						.getComponentByID((ProfileSpecificationID) componentID);
			} else if (componentID instanceof ResourceAdaptorID) {
				component = componentRepositoryImpl
						.getComponentByID((ResourceAdaptorID) componentID);
			} else if (componentID instanceof ResourceAdaptorTypeID) {
				component = componentRepositoryImpl
						.getComponentByID((ResourceAdaptorTypeID) componentID);
			} else if (componentID instanceof SbbID) {
				component = componentRepositoryImpl
						.getComponentByID((SbbID) componentID);
			} else if (componentID instanceof ServiceID) {
				component = componentRepositoryImpl
						.getComponentByID((ServiceID) componentID);
			}
			if (component != null)
				return component.getComponentDescriptor();
			else
				return null;
		} catch (Throwable ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}

	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#getDescriptors(javax.slee.ComponentID[])
	 */
	public ComponentDescriptor[] getDescriptors(ComponentID[] componentIds)
			throws NullPointerException, ManagementException {

		if (componentIds == null)
			throw new NullPointerException("null component ids");
		try {
			ComponentDescriptor[] descriptors = new ComponentDescriptor[componentIds.length];
			for (int i = 0; i < descriptors.length; i++) {
				descriptors[i] = getDescriptor(componentIds[i]);
			}
			return descriptors;
		} catch (ManagementException ex) {
			throw ex;
		} catch (Throwable ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#isInstalled(javax.slee.management.DeployableUnitID)
	 */
	public boolean isInstalled(DeployableUnitID deployableUnitID)
			throws NullPointerException, ManagementException {
		if (deployableUnitID == null)
			throw new NullPointerException("null deployableUnitID");
		try {
			return getSleeContainer().getDeployableUnitManagement()
					.getDeployableUnit(deployableUnitID) != null;
		} catch (Throwable ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.management.DeploymentMBean#isInstalled(javax.slee.ComponentID)
	 */
	public boolean isInstalled(ComponentID componentID)
			throws NullPointerException, ManagementException {
		if (componentID == null)
			throw new NullPointerException("null componentID");
		try {
			return getSleeContainer().getComponentRepository()
					.isInstalled(componentID);
		} catch (Throwable ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}
	}

	public LibraryID[] getLibraries() throws ManagementException {
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("getLibraries()");
			}
			return getSleeContainer().getComponentRepository()
					.getLibraryIDs().toArray(new LibraryID[0]);
		} catch (Throwable ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}
	}

	public SbbID[] getSbbs(ServiceID serviceID) throws NullPointerException,
			UnrecognizedServiceException, ManagementException {

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

		Set<SbbID> result = null;
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("getSbbs(serviceID)");
			}
			ComponentRepository componentRepository = getSleeContainer().getComponentRepository();
			ServiceComponent serviceComponent = componentRepository
					.getComponentByID(serviceID);
			if (serviceComponent != null) {
				result = serviceComponent.getSbbIDs(componentRepository);
			}
		} catch (Throwable ex) {
			throw new ManagementException(ex.getMessage(), ex);
		}

		if (result != null) {
			return result.toArray(new SbbID[0]);
		} else {
			throw new UnrecognizedServiceException(serviceID.toString());
		}
	}

	private void updateSecurityPermissions(SleeComponent component, boolean refresh)
	{
		if(System.getSecurityManager()==null)
		{
			return;
		}
		Policy p = Policy.getPolicy();
		if (!(p instanceof PolicyFile)) {
			if (logger.isDebugEnabled()) {
				logger.debug("Could not find Policy implmentation specific to mobicents. Found: " + p.getClass());
			}
			return;
		}

		PolicyFile policyFile = (PolicyFile) p;
		if(component!=null)
		{

			for(PermissionHolder ph : component.getPermissions())
			{

				policyFile.addPermissionHolder(ph, false);
			}
		}

		if(refresh)
			policyFile.refresh();
	}

	private void removeSecurityPermissions(SleeComponent component, boolean refresh)
	{

		if(System.getSecurityManager()==null)
		{
			return;
		}

		Policy p = Policy.getPolicy();
		if(!(p instanceof PolicyFile))
		{
		if (logger.isDebugEnabled()) {
				logger.debug("Could not find Policy implmentation specific to mobicents. Found: " + p.getClass());
			}
			return;
		}

		PolicyFile policyFile = (PolicyFile) p;
		if(component!=null)
		{
			for(PermissionHolder ph : component.getPermissions())
			{
				policyFile.removePermissionHolder(ph, false);
			}
		}

		if(refresh)
			policyFile.refresh();
	}
}