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

package org.mobicents.slee.runtime.facilities;

import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

import javax.slee.InvalidArgumentException;
import javax.slee.facilities.FacilityException;
import javax.slee.facilities.TraceLevel;
import javax.slee.facilities.Tracer;
import javax.slee.management.NotificationSource;
import javax.slee.management.TraceNotification;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.mobicents.slee.container.management.jmx.TraceMBeanImpl;

/**
 *
 * Start time:21:04:04 2009-03-09

 * Project: restcomm-jainslee-server-core

 * Implementation of Tracer object that allows slee comopnents to send
 * notification on some interesting ocasions.
 *
 * @author baranowb - Bartosz Baranowski
 * @author martins
 */
public class TracerImpl implements Tracer {

	public static final TraceLevel DEFAULT_TRACE_LEVEL = TraceLevel.INFO;

	public final static String ROOT_TRACER_NAME = "";

	private TraceLevel level;

	private final Logger logger;

	private final NotificationSourceWrapperImpl notificationSource;

	private final TraceMBeanImpl traceMBean;

	private final String name;

	private final TracerImpl parent;

	private boolean requestedBySource = false;

	private boolean configEnabled = false;
	private boolean infoEnabled = false;
	private boolean fineEnabled = false;
	private boolean finerEnabled = false;
	private boolean finestEnabled = false;
	private boolean warningEnabled = false;
	private boolean severeEnabled = false;

	private final ConcurrentLinkedQueue<TracerImpl> childs = new ConcurrentLinkedQueue<TracerImpl>();

	/**
	 *
	 */
	public TracerImpl(String name, TracerImpl parent, NotificationSourceWrapperImpl notificationSource, TraceMBeanImpl traceMBean) {
		this.name = name;
		this.parent = parent;
		if (parent != null) {
			parent.childs.add(this);
		}
		this.logger = Logger.getLogger(tracerNameToLog4JLoggerName(name, notificationSource.getNotificationSource()));
		this.notificationSource = notificationSource;
		this.traceMBean = traceMBean;
		syncLevelWithLog4j();
	}

	/**
	 * Generates the log4j logger name for the tracer with specified named and notification source.
	 *
	 * @param tracerName
	 * @param notificationSource
	 * @return
	 */
	private String tracerNameToLog4JLoggerName(String tracerName, NotificationSource notificationSource) {
		final StringBuilder sb = new StringBuilder("javax.slee.").append(notificationSource.toString());
		if(!tracerName.equals(ROOT_TRACER_NAME)) {
			sb.append('.').append(tracerName);
		}
		return sb.toString();
	}

	/**
	 * syncs the slee tracer level with the one that related logger has in log4j
	 */
	void syncLevelWithLog4j() {
		// get the level from log4j, only the root one uses effective level
		Level log4jLevel = parent == null ? logger.getEffectiveLevel() : logger.getLevel();
		if (level == null) {
			// set the level
			assignLog4JLevel(log4jLevel);
		}
		else {
			// set the level only if differs, otherwise we may loose levels not present in log4j
			if (tracerToLog4JLevel(level) != log4jLevel) {
				assignLog4JLevel(log4jLevel);
			}
		}
		// the root must always have a level
		if (parent == null && level == null) {
			// defaults to INFO
			logger.setLevel(Level.INFO);
			level = TraceLevel.INFO;
		}
		// reset the flags
		resetCacheFlags(false);
	}

	/**
	 * assigns the equiv log4j level to the tracer
	 * @param log4jLevel
	 */
	private void assignLog4JLevel(Level log4jLevel) {
		if (log4jLevel == null) {
			return;
		}
		if (log4jLevel == Level.DEBUG) {
			level = TraceLevel.FINE;
		}
		else if (log4jLevel == Level.INFO) {
			level = TraceLevel.INFO;
		}
		else if (log4jLevel == Level.WARN) {
			level = TraceLevel.WARNING;
		}
		else if (log4jLevel == Level.ERROR) {
			level = TraceLevel.SEVERE;
		}
		else if (log4jLevel == Level.TRACE) {
			level = TraceLevel.FINEST;
		}
		else if (log4jLevel == Level.OFF) {
			level = TraceLevel.OFF;
		}
	}

	/**
	 * manages the flags which cache if levels are enabled
	 */
	void resetCacheFlags(boolean resetChilds) {
		if (isTraceable(TraceLevel.FINEST)) {
			finestEnabled = true;
			finerEnabled = true;
			fineEnabled = true;
			configEnabled = true;
			infoEnabled = true;
			warningEnabled = true;
			severeEnabled = true;
		}
		else {
			finestEnabled = false;
			if (isTraceable(TraceLevel.FINER)) {
				finerEnabled = true;
				fineEnabled = true;
				configEnabled = true;
				infoEnabled = true;
				warningEnabled = true;
				severeEnabled = true;
			}
			else {
				finerEnabled = false;
				if (isTraceable(TraceLevel.FINE)) {
					fineEnabled = true;
					configEnabled = true;
					infoEnabled = true;
					warningEnabled = true;
					severeEnabled = true;
				}
				else {
					fineEnabled = false;
					if (isTraceable(TraceLevel.CONFIG)) {
						configEnabled = true;
						infoEnabled = true;
						warningEnabled = true;
						severeEnabled = true;
					}
					else {
						if (isTraceable(TraceLevel.INFO)) {
							infoEnabled = true;
							warningEnabled = true;
							severeEnabled = true;
						}
						else {
							infoEnabled = false;
							if (isTraceable(TraceLevel.WARNING)) {
								warningEnabled = true;
								severeEnabled = true;
							}
							else {
								warningEnabled = false;
								if (isTraceable(TraceLevel.SEVERE)) {
									severeEnabled = true;
								}
								else {
									severeEnabled = false;
								}
							}
						}
					}
				}
			}
		}
		if (resetChilds) {
			// implicit change of level demands that we update reset flags on childs without level
			for(TracerImpl child : childs) {
				if (child.level == null) {
					child.resetCacheFlags(true);
				}
			}
		}
	}

	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#config(java.lang.String)
	 */
	public void config(String message) throws NullPointerException,
			FacilityException {
		sendNotification(TraceLevel.CONFIG, message, null);
		logger.info(message);
	}

	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#config(java.lang.String, java.lang.Throwable)
	 */
	public void config(String message, Throwable t)
			throws NullPointerException, FacilityException {
		sendNotification(TraceLevel.CONFIG, message, t);
		logger.info(message,t);
	}

	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#fine(java.lang.String)
	 */
	public void fine(String message) throws NullPointerException,
			FacilityException {
		sendNotification(TraceLevel.FINE, message, null);
		logger.debug(message);

	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#fine(java.lang.String, java.lang.Throwable)
	 */
	public void fine(String message, Throwable t) throws NullPointerException,
			FacilityException {
		sendNotification(TraceLevel.FINE, message, t);
		logger.debug(message,t);
	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#finer(java.lang.String)
	 */
	public void finer(String message) throws NullPointerException,
			FacilityException {
		sendNotification(TraceLevel.FINER, message, null);
		logger.debug(message);

	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#finer(java.lang.String, java.lang.Throwable)
	 */
	public void finer(String message, Throwable t) throws NullPointerException,
			FacilityException {
		sendNotification(TraceLevel.FINER, message, t);
		logger.debug(message,t);
	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#finest(java.lang.String)
	 */
	public void finest(String message) throws NullPointerException,
			FacilityException {
		sendNotification(TraceLevel.FINEST, message, null);
		logger.trace(message);

	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#finest(java.lang.String, java.lang.Throwable)
	 */
	public void finest(String message, Throwable t)
			throws NullPointerException, FacilityException {
		sendNotification(TraceLevel.FINEST, message, t);
		logger.trace(message,t);
	}

	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#getParentTracerName()
	 */
	public String getParentTracerName() {
		return parent == null ? null : parent.getTracerName();
	}

	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#getTraceLevel()
	 */
	public TraceLevel getTraceLevel() throws FacilityException {
		return level != null ? level : parent.getTraceLevel();
	}

	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#getTracerName()
	 */
	public String getTracerName() {
		return name;
	}

	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#info(java.lang.String)
	 */
	public void info(String message) throws NullPointerException,
			FacilityException {
		sendNotification(TraceLevel.INFO, message, null);
		logger.info(message);

	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#info(java.lang.String, java.lang.Throwable)
	 */
	public void info(String message, Throwable t) throws NullPointerException,
			FacilityException {
		sendNotification(TraceLevel.INFO, message, t);
		logger.info(message,t);

	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#isConfigEnabled()
	 */
	public boolean isConfigEnabled() throws FacilityException {
		return configEnabled;
	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#isFineEnabled()
	 */
	public boolean isFineEnabled() throws FacilityException {
		return fineEnabled;
	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#isFinerEnabled()
	 */
	public boolean isFinerEnabled() throws FacilityException {
		return finerEnabled;
	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#isFinestEnabled()
	 */
	public boolean isFinestEnabled() throws FacilityException {
		return finestEnabled;
	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#isInfoEnabled()
	 */
	public boolean isInfoEnabled() throws FacilityException {
		return infoEnabled;
	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#isSevereEnabled()
	 */
	public boolean isSevereEnabled() throws FacilityException {
		return severeEnabled;
	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#isTraceable(javax.slee.facilities.TraceLevel)
	 */
	public boolean isTraceable(TraceLevel traceLevel) throws NullPointerException,
			FacilityException {
		return !getTraceLevel().isHigherLevel(traceLevel);
	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#isWarningEnabled()
	 */
	public boolean isWarningEnabled() throws FacilityException {
		return warningEnabled;
	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#severe(java.lang.String)
	 */
	public void severe(String message) throws NullPointerException,
			FacilityException {
		sendNotification(TraceLevel.SEVERE, message, null);
		logger.error(message);
	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#severe(java.lang.String, java.lang.Throwable)
	 */
	public void severe(String message, Throwable t)
			throws NullPointerException, FacilityException {
		sendNotification(TraceLevel.SEVERE, message, t);
		logger.error(message,t);
	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#trace(javax.slee.facilities.TraceLevel, java.lang.String)
	 */
	public void trace(TraceLevel traceLevel, String message)
			throws NullPointerException, IllegalArgumentException,
			FacilityException {
		sendNotification(traceLevel, message, null);
		logger.log(tracerToLog4JLevel(traceLevel), message);
	}

	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#trace(javax.slee.facilities.TraceLevel, java.lang.String, java.lang.Throwable)
	 */
	public void trace(TraceLevel traceLevel, String message, Throwable t)
			throws NullPointerException, IllegalArgumentException,
			FacilityException {
		sendNotification(traceLevel, message, t);
		logger.log(tracerToLog4JLevel(traceLevel), message,t);

	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#warning(java.lang.String)
	 */
	public void warning(String message) throws NullPointerException,
			FacilityException {
		sendNotification(TraceLevel.WARNING, message, null);
		logger.warn(message);
	}
	/* (non-Javadoc)
	 * @see javax.slee.facilities.Tracer#warning(java.lang.String, java.lang.Throwable)
	 */
	public void warning(String message, Throwable t)
			throws NullPointerException, FacilityException {
		sendNotification(TraceLevel.WARNING, message, t);
		logger.warn(message,t);
	}

	/**
	 * THis is internaly called, by 1.1 tracers
	 *
	 * @param src
	 */
	void sendNotification(javax.slee.facilities.TraceLevel level, String message, Throwable t) {
		if (!isTraceable(level)) {
			return;
		}
		traceMBean.sendNotification(new TraceNotification(notificationSource.getNotificationSource().getTraceNotificationType(), traceMBean, notificationSource.getNotificationSource(), getTracerName(), level, message, t, notificationSource.getNextSequence(), System.currentTimeMillis()));
	}

	/**
	 * This checks if the specified tracer name is ok.
	 *
	 * @param tracerName
	 * @param notificationSource
	 * @throws InvalidArgumentException
	 */
	public static void checkTracerName(String tracerName, NotificationSource notificationSource) throws NullPointerException,InvalidArgumentException {

		if (tracerName.equals("")) {
			// This is root
			return;
		}

		StringTokenizer stringTokenizer = new StringTokenizer(tracerName, ".", true);

		String lastToken = null;

		while (stringTokenizer.hasMoreTokens()) {
			String token = stringTokenizer.nextToken();
			if (lastToken == null) {
				// this is start
				lastToken = token;
			}

			if (lastToken.equals(token) && token.equals(".")) {
				throw new InvalidArgumentException("Passed tracer:" + tracerName + ", name for source: " + notificationSource + ", is illegal");
			}

			lastToken = token;

		}

		if (lastToken.equals(".")) {
			throw new IllegalArgumentException("Passed tracer:" + tracerName + ", name for source: " + notificationSource + ", is illegal");
		}

	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "Tracer{ notificationSource = "+notificationSource.getNotificationSource()+" , name = "+getTracerName()+" , parent = "+getParentTracerName()+" , level = "+getTraceLevel()+" }";
	}

	private Level tracerToLog4JLevel(TraceLevel traceLevel) {
		if (traceLevel.isFine() || traceLevel.isFiner()) {
			return Level.DEBUG;
		}
		if (traceLevel.isInfo() || traceLevel.isConfig()) {
			return Level.INFO;
		}
		if (traceLevel.isFinest()) {
			return Level.TRACE;
		}
		if(traceLevel.isWarning()) {
			return Level.WARN;
		}
		if(traceLevel.isSevere()) {
			return Level.ERROR;
		}
		if(traceLevel.isOff()) {
			return Level.OFF;
		}
		return Level.INFO;
	}

	/**
	 * @param level
	 */
	public void setTraceLevel(TraceLevel level) {
		this.level = level;
		logger.setLevel(tracerToLog4JLevel(level));
		resetCacheFlags(true);
	}

	public void unsetTraceLevel() {
		this.level = null;
		logger.setLevel(null);
		resetCacheFlags(true);
	}

	/**
	 * @return
	 */
	public boolean isExplicitlySetTracerLevel() {
		return level != null;
	}

	/**
	 * Sets
	 * @param requestedBySource the requestedBySource to set
	 */
	public void setRequestedBySource(boolean requestedBySource) {
		this.requestedBySource = requestedBySource;
	}

	/**
	 * Retrieves
	 * @return the requestedBySource
	 */
	public boolean isRequestedBySource() {
		return requestedBySource;
	}
}


package javax.slee.management;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.rmi.MarshalledObject;

/**
 * This class provides serialization and deserialization utility methods used by
 * classes that implement the {@link VendorExtensions} interface.
 */
public class VendorExtensionUtils {
    /**
     * Write the current object and vendor-specific data to the output stream.
     * @param out the object output stream that the current object is being written to.
     * @param vendorData the optional vendor data to include in the serialization stream.
     * @throws IOException if an I/O error occurs while writing to the output stream.
     */
    public static void writeObject(ObjectOutputStream out, Object vendorData) throws IOException {
        // write non-transient fields
        out.defaultWriteObject();
        // check if should we serialize vendor data?
        if (vendorData != null) {
            // serialize the vendor data
            out.writeBoolean(true);
            // write the vendor data in a marshalled object so deserialization can be deferred
            out.writeObject(new MarshalledObject(vendorData));
        }
        else out.writeBoolean(false);
    }

    /**
     * Read the current object in the input stream from the stream, optionally
     * deserializing any vendor-specific data in the stream.
     * @param in the object input stream that the current object is being read from.
     * @param vendorDataDeserializationEnabled boolean flag indicating whether or not
     *        any vendor data in the serialization stream should be deserialized also.
     * @return the vendor-specific data, or null if there isn't any or the
     *        value of the vendorDataDeserializationEnabled parameter was
     *        false.
     * @throws IOException if an I/O error occurs while reading from the input stream.
     * @throws ClassNotFoundException if a class of the serialized objects could not
     *        be found.
     */
    public static Object readObject(ObjectInputStream in, boolean vendorDataDeserializationEnabled) throws IOException, ClassNotFoundException {
        // read non-transient fields
        in.defaultReadObject();
        // read any possible marshalled vendor data from the stream
        MarshalledObject vendorData = in.readBoolean()
            ? (MarshalledObject)in.readObject()
            : null;
        // now figure out what to return
        return (vendorData != null && vendorDataDeserializationEnabled) ? vendorData.get() : null;
    }
}


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

package org.mobicents.slee.container.component.deployment.classloading;

import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.component.classloading.URLClassLoaderDomain;

/**
 * An extension of {@link URLClassLoader} to support multiple parents.
 *
 * @author martins
 *
 */
public class URLClassLoaderDomainImpl extends URLClassLoaderDomain {

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

    /**
     * classes loaded within these packages will have classloading order
     * inverted. That is first try locally, then in parent.
     */
    private Set<String> preferredPackages = new HashSet();

	/**
	 * the set of dependencies for the domain
	 */
	private Set<URLClassLoaderDomainImpl> directDependencies = new HashSet<URLClassLoaderDomainImpl>();

	/**
	 *
	 * @param urls
	 * @param sleeClassLoader
	 */
	public URLClassLoaderDomainImpl(URL[] urls, ClassLoader sleeClassLoader) {
		super(urls, sleeClassLoader);
	}

	/**
	 * Adds a direct dependency to this domain. Direct dependencies are other
	 * domains which the domain depends on.
	 *
	 * @param domain
	 */
	public void addDirectDependency(URLClassLoaderDomainImpl domain) {
		if (logger.isTraceEnabled())
			logger.trace(toString() + " adding domain " + domain
					+ " to direct dependencies");
		directDependencies.add(domain);
	}

	/**
	 * Retrieves the set of direct dependencies for the domain.
	 *
	 * @return
	 */
	public Set<URLClassLoaderDomainImpl> getDirectDependencies() {
		return directDependencies;
	}

	/**
	 * Retrieves a flat list containing all dependencies for the domain, i.e., all direct dependencies and their own dependencies.
	 * @return
	 */
	public List<URLClassLoaderDomainImpl> getAllDependencies() {
		List<URLClassLoaderDomainImpl> result = new ArrayList<URLClassLoaderDomainImpl>();
		this.getAllDependencies(result);
		return result;
	}

	private void getAllDependencies(List<URLClassLoaderDomainImpl> result) {
		for (URLClassLoaderDomainImpl i : directDependencies) {
			if (!result.contains(i)) {
				result.add(i);
				i.getAllDependencies(result);
			}
		}
	}

	private static final ReentrantLock GLOBAL_LOCK = new ReentrantLock();
	private static final long WAIT_FOR_LOCK = 10;
	private static final long MAX_WAIT_FOR_LOCK = 10000;
	private static final long MAX_ATTEMPTS = MAX_WAIT_FOR_LOCK / WAIT_FOR_LOCK;

	private boolean acquireGlobalLock() {
		boolean acquired = false;

		if (GLOBAL_LOCK.isHeldByCurrentThread()) {
			return false;
		} else {
			int attempts = 0;
			try {
				//prevent an infinite loop by limiting the acquire attempts
				while (!acquired && attempts < MAX_ATTEMPTS) {
					acquired = GLOBAL_LOCK.tryLock(WAIT_FOR_LOCK, TimeUnit.MILLISECONDS);
					attempts = attempts + 1;
				}
			} catch (InterruptedException ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Interrupted while acquiring.", ex);
				}
			}
			if (!acquired) {
				//throw a runtime exception so error is reported upstream
				throw new IllegalMonitorStateException("Unable to acquire global lock.");
			}
		}

		return acquired;
	}

	private void releaseGlobalLock() {
		GLOBAL_LOCK.unlock();
	}

    private boolean isPreferredPackage(String className) {
        boolean isPreferred = false;
        for (String prefPack : preferredPackages)
        {
            if (className.startsWith(prefPack)) {
                isPreferred = true;
            }
        }
        return isPreferred;
    }

	@Override
    protected Class<?> loadClass(final String name, final boolean resolve)
            throws ClassNotFoundException {

        Class foundClass = null;
        ClassNotFoundException localException = null;

        if (logger.isTraceEnabled()) {
            logger.trace(toString() + " loadClass: " + name);
        }

        boolean acquiredLock = false;

        try {
            acquiredLock = acquireGlobalLock();

            //fixes https://github.com/RestComm/jain-slee/issues/49
            //classloader order is inverted for preferred packages
            if (isPreferredPackage(name)) {
                try {
                    Class<?> loaded = this.findLoadedClass(name);
                    if (loaded == null) {
                        Class<?> clazz = this.findClass(name);
                        foundClass = clazz;
                    } else {
                        foundClass = loaded;
                    }
                } catch (ClassNotFoundException cExp) {
                    //ignore, try with parent before raising exception
                    //save exception in case parent dont find it
                    localException = cExp;
                    if (logger.isTraceEnabled()) {
                        logger.trace("Class not found" + cExp);
                    }
                }
            }
        } finally {
            //in any case always release lock
            if (acquiredLock) {
                releaseGlobalLock();
            }
        }
        if (foundClass == null) {
            //now try with parent
            // load the class
            if (System.getSecurityManager() != null) {
                try {
                    return AccessController
                            .doPrivileged(new PrivilegedExceptionAction<Class<?>>() {
                                public Class<?> run()
                                        throws ClassNotFoundException {
                                    return URLClassLoaderDomainImpl.super
                                            .loadClass(name, resolve);
                                }
                            });
                } catch (PrivilegedActionException e) {
                    throw (ClassNotFoundException) e.getException();
                }
            } else {
                foundClass = super.loadClass(name, resolve);
            }
        }

        if (foundClass != null) {
            return foundClass;
        } else {
            //ensure we raise proper exception
            if (localException != null) {
                throw localException;
            } else {
                throw new ClassNotFoundException(name);
            }
        }
    }

	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		if (logger.isTraceEnabled())
			logger.trace(toString() + " findClass: " + name);
		// try 1st in dependencies
		Class<?> c = null;
		for (URLClassLoaderDomainImpl dependency : getAllDependencies()) {
			synchronized (dependency) {
				c = dependency.findLoadedClass(name);
				if (c != null) {
					return c;
				}
				try {
					return dependency.findClassLocallyLocked(name);
				} catch (Throwable e) {
					// ignore
				}
			}
		}
		// now locally
		return findClassLocallyLocked(name);
	}

	/**
	 * Finds a class locally, i.e., in the URLs managed by the extended
	 * URLClassLoader.
	 *
	 * @param name
	 * @return
	 * @throws ClassNotFoundException
	 */
	protected Class<?> findClassLocally(String name)
            throws ClassNotFoundException {
        if (logger.isTraceEnabled()) {
            logger.trace(toString() + " findClassLocally: " + name);
        }
        final boolean acquiredLock = acquireGlobalLock();
        try {
            return findClassLocallyLocked(name);
        } finally {
            if (acquiredLock) {
                releaseGlobalLock();
            }
        }
    }

	protected Class<?> findClassLocallyLocked(String name)
			throws ClassNotFoundException {
		if (logger.isTraceEnabled())
			logger.trace(toString() + " findClassLocallyLocked: " + name);
		return super.findClass(name);
	}

	@Override
	public URL findResource(String name) {
		if (logger.isTraceEnabled())
			logger.trace(toString() + " findResource: " + name);

		// try 1st in dependencies
		URL result = null;
		for (URLClassLoaderDomainImpl dependency : getAllDependencies()) {
			result = dependency.findResourceLocally(name);
			if (result != null) {
				return result;
			}
		}
		// now locally
		return findResourceLocally(name);
	}

	/**
	 * Finds a resource locally, i.e., in the URLs managed by the extended
	 * URLClassLoader.
	 *
	 * @param name
	 * @return
	 */
	protected URL findResourceLocally(String name) {
		if (logger.isTraceEnabled())
			logger.trace(toString() + " findResourceLocally: " + name);

		return super.findResource(name);
	}

	@Override
	public Enumeration<URL> findResources(String name) throws IOException {
		if (logger.isTraceEnabled())
			logger.trace(toString() + " findResources: " + name);

		Vector<URL> vector = new Vector<URL>();
		// add resources from dependencies
		Enumeration<URL> enumeration = null;
		for (URLClassLoaderDomainImpl dependency : getAllDependencies()) {
			enumeration = dependency.findResourcesLocally(name);
			while (enumeration.hasMoreElements()) {
				vector.add(enumeration.nextElement());
			}
		}
		// now the local ones
		enumeration = findResourcesLocally(name);
		while (enumeration.hasMoreElements()) {
			vector.add(enumeration.nextElement());
		}
		return vector.elements();
	}

	/**
	 * Finds resources locally, i.e., in the URLs managed by the extended
	 * URLClassLoader.
	 *
	 * @param name
	 * @return
	 * @throws IOException
	 */
	protected Enumeration<URL> findResourcesLocally(String name)
			throws IOException {
		if (logger.isTraceEnabled())
			logger.trace(toString() + " findResourcesLocally: " + name);

		return super.findResources(name);
	}

	@Override
	public String toString() {
		return "URLClassLoaderDomain( urls= " + Arrays.asList(getURLs())
				+ " )\n";
	}

	public void clear() {
		directDependencies.clear();
	}

    public Set<String> getPreferredPackages() {
        return preferredPackages;
    }

    public void setPreferredPackages(Set<String> preferredPackages) {
        this.preferredPackages = preferredPackages;
    }

}


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

/***************************************************
 *                                                 *
 *  Restcomm: The Open Source VoIP Platform      *
 *                                                 *
 *  Distributable under LGPL license.              *
 *  See terms of license at gnu.org.               *
 *                                                 *
 ***************************************************/
/*
 * ProfileProvisioningMBeanImpl.java
 *
 * Created on 12 nov. 2004
 *
 */
package org.mobicents.slee.container.management.jmx;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.slee.CreateException;
import javax.slee.InvalidArgumentException;
import javax.slee.SLEEException;
import javax.slee.TransactionRequiredLocalException;
import javax.slee.management.ManagementException;
import javax.slee.management.SleeState;
import javax.slee.profile.AttributeNotIndexedException;
import javax.slee.profile.AttributeTypeMismatchException;
import javax.slee.profile.ProfileAlreadyExistsException;
import javax.slee.profile.ProfileID;
import javax.slee.profile.ProfileSpecificationID;
import javax.slee.profile.ProfileTableAlreadyExistsException;
import javax.slee.profile.UnrecognizedAttributeException;
import javax.slee.profile.UnrecognizedProfileNameException;
import javax.slee.profile.UnrecognizedProfileSpecificationException;
import javax.slee.profile.UnrecognizedProfileTableNameException;
import javax.slee.profile.UnrecognizedQueryNameException;
import javax.slee.profile.query.QueryExpression;
import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.component.profile.ProfileSpecificationComponent;
import org.mobicents.slee.container.management.ProfileManagementImpl;
import org.mobicents.slee.container.profile.AbstractProfileMBeanImpl;
import org.mobicents.slee.container.profile.ProfileTableImpl;
import org.mobicents.slee.container.profile.entity.ProfileEntity;
import org.mobicents.slee.container.transaction.SleeTransactionManager;
import org.mobicents.slee.container.transaction.TransactionContext;
import org.mobicents.slee.container.transaction.TransactionalAction;

/**
 * MBean class for profile provisioning through jmx
 *
 * @author <a href="mailto:baranowb@gmail.com">baranowb - Bartosz Baranowski
 * @author martins
 */
public class ProfileProvisioningMBeanImpl extends MobicentsServiceMBeanSupport implements ProfileProvisioningMBeanImplMBean {

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

	private ProfileManagementImpl sleeProfileManagement = null;
	private SleeTransactionManager sleeTransactionManagement = null;

	/**
	 *
	 * @throws NotCompliantMBeanException
	 */
	public ProfileProvisioningMBeanImpl(SleeContainer sleeContainer) throws NotCompliantMBeanException {
		super(sleeContainer);
		this.sleeTransactionManagement = getSleeContainer().getTransactionManager();
		this.sleeProfileManagement = (ProfileManagementImpl) getSleeContainer().getSleeProfileTableManager();
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.ProfileProvisioningMBean#createProfile(java.lang.String, java.lang.String)
	 */
	public ObjectName createProfile(java.lang.String profileTableName, java.lang.String profileName) throws java.lang.NullPointerException, UnrecognizedProfileTableNameException,
			InvalidArgumentException, ProfileAlreadyExistsException, ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("createProfile( profileTable = "+profileTableName+" , profile = "+profileName+" )");
		}

		try {
			ProfileTableImpl.validateProfileName(profileName);
			ProfileTableImpl.validateProfileTableName(profileTableName);
		}
		catch (IllegalArgumentException e) {
			throw new InvalidArgumentException(e.getMessage());
		}

		Transaction transaction = null;
		boolean rollback = true;
		try {
			// begin tx
			sleeTransactionManagement.begin();
			transaction = sleeTransactionManagement.getTransaction();
			// This checks if profile table exists - throws SLEEException in
			// case of system level and UnrecognizedProfileTableNameException in
			// case of no such table
			final ProfileTableImpl profileTable = this.sleeProfileManagement.getProfileTable(profileTableName);
			// create profile
			profileTable.createProfile(profileName);
			if (sleeTransactionManagement.getRollbackOnly()) {
				throw new ManagementException("Transaction used in profile creation rolled back");
			}
			else {
				// create mbean and registers it
				final AbstractProfileMBeanImpl profileMBean = createAndRegisterProfileMBean(profileName,profileTable);
				// keep track of the mbean existence
				profileTable.addUncommittedProfileMBean(profileMBean);
				TransactionalAction action = new TransactionalAction() {
					public void execute() {
						profileTable.removeUncommittedProfileMBean(profileMBean);
					}
				};
				final TransactionContext txContext = sleeTransactionManagement.getTransactionContext();
				txContext.getAfterCommitActions().add(action);
				txContext.getAfterRollbackActions().add(action);
				// indicate profile creation
				profileMBean.createProfile();
				rollback = false;
				if (logger.isDebugEnabled()) {
					logger.debug("createProfile( profileTable = "+profileTableName+" , profile = "+profileName+" ) result is "+profileMBean.getObjectName());
				}
				return profileMBean.getObjectName();
			}
		} catch (TransactionRequiredLocalException e) {
			throw new ManagementException(e.getMessage(),e);
		} catch (SLEEException e) {
			throw new ManagementException(e.getMessage(),e);
		} catch (CreateException e) {
			throw new ManagementException(e.getMessage(),e);
		} catch (NotSupportedException e) {
			throw new ManagementException(e.getMessage(),e);
		} catch (SystemException e) {
			throw new ManagementException(e.getMessage(),e);
		} finally {
			if(rollback) {
				try {
					if (sleeTransactionManagement.getTransaction() == null) {
						// the tx was suspended, resume it
						sleeTransactionManagement.resume(transaction);
					}
					sleeTransactionManagement.rollback();
				}
				catch (Throwable e) {
					logger.error(e.getMessage(),e);
				}
			}
		}
	}

	/**
	 * Creates and registers a profile mbean for the specified object.
	 * @param profileObject
	 * @return
	 * @throws ManagementException
	 */
	private AbstractProfileMBeanImpl createAndRegisterProfileMBean(String profileName, ProfileTableImpl profileTable) throws ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("createAndRegisterProfileMBean( profileTable = "+profileTable+" , profileName = "+profileName+" )");
		}

		try {
			ProfileSpecificationComponent component = profileTable.getProfileSpecificationComponent();
			Constructor<?> constructor = component.getProfileMBeanConcreteImplClass().getConstructor(Class.class, String.class, ProfileTableImpl.class);
			final AbstractProfileMBeanImpl profileMBean = (AbstractProfileMBeanImpl) constructor.newInstance(component.getProfileMBeanConcreteInterfaceClass(), profileName, profileTable);
			profileMBean.register();
			// add a rollback action to unregister the mbean
			TransactionalAction rollbackAction = new TransactionalAction() {
				public void execute() {
					try {
						profileMBean.unregister();
					} catch (Throwable e) {
						logger.error(e.getMessage(),e);
					}
				}
			};
			sleeTransactionManagement.getTransactionContext().getAfterRollbackActions().add(rollbackAction);
			return profileMBean;
		} catch (Throwable e) {
			throw new ManagementException(e.getMessage(),e);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.ProfileProvisioningMBean#createProfileTable(javax.slee.profile.ProfileSpecificationID, java.lang.String)
	 */
	public void createProfileTable(ProfileSpecificationID specificationID,
			String profileTableName) throws NullPointerException,
			UnrecognizedProfileSpecificationException,
			InvalidArgumentException, ProfileTableAlreadyExistsException,
			ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("createProfileTable( profileTable = "+profileTableName+" , specificationID = "+specificationID+" )");
		}

		try {
			ProfileTableImpl.validateProfileTableName(profileTableName);
		}
		catch (IllegalArgumentException e) {
			throw new InvalidArgumentException(e.getMessage());
		}

		final SleeContainer sleeContainer = getSleeContainer();

		if (sleeContainer.getSleeState() != SleeState.RUNNING)
			return;

		ProfileSpecificationComponent component = sleeContainer.getComponentRepository().getComponentByID(specificationID);
		if (component == null)
			throw new UnrecognizedProfileSpecificationException();

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

		boolean terminateTx = sleeTransactionManagement.requireTransaction();
		boolean doRollback = true;
		try {
			Thread.currentThread().setContextClassLoader(component.getClassLoader());
			sleeProfileManagement.addProfileTable(profileTableName,component);
			doRollback =false;
		} catch (ProfileTableAlreadyExistsException e) {
			throw e;
		} catch (Throwable e) {
			if (logger.isDebugEnabled()) {
				logger.debug(e.getMessage(),e);
			}
			throw new ManagementException(e.getMessage(),e);
		} finally {
			Thread.currentThread().setContextClassLoader(currentClassLoader);
			try {
				sleeTransactionManagement.requireTransactionEnd(terminateTx,doRollback);
			} catch (Throwable e) {
				throw new ManagementException(e.getMessage(),e);
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.ProfileProvisioningMBean#getDefaultProfile(java.lang.String)
	 */
	public ObjectName getDefaultProfile(String profileTableName) throws NullPointerException, UnrecognizedProfileTableNameException, ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("getDefaultProfile( profileTable = "+profileTableName+" )");
		}

		try {
			return _getProfile(profileTableName,null);
		} catch (UnrecognizedProfileNameException e) {
			// can't happen
			throw new ManagementException(e.getMessage(),e);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.ProfileProvisioningMBean#getProfile(java.lang.String, java.lang.String)
	 */
	public ObjectName getProfile(java.lang.String profileTableName, java.lang.String profileName) throws NullPointerException, UnrecognizedProfileTableNameException, UnrecognizedProfileNameException,
			ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("getProfile( profileTable = "+profileTableName+" , profile = "+profileName+" )");
		}

		ProfileTableImpl.validateProfileName(profileName);
		ObjectName objectName = _getProfile(profileTableName, profileName);
		if (logger.isDebugEnabled()) {
			logger.debug("getProfile( profileTable = "+profileTableName+" , profile = "+profileName+" ) result is "+objectName);
		}
		return objectName;
	}

	/**
	 *
	 * @param profileTableName
	 * @param profileName
	 * @return
	 * @throws NullPointerException
	 * @throws UnrecognizedProfileTableNameException
	 * @throws ManagementException
	 * @throws UnrecognizedProfileNameException
	 * @throws ManagementException
	 */
	private ObjectName _getProfile(java.lang.String profileTableName, java.lang.String profileName) throws NullPointerException, UnrecognizedProfileTableNameException,
			ManagementException, UnrecognizedProfileNameException, ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("_getProfile( profileTable = "+profileTableName+" , profile = "+profileName+" )");
		}

		ProfileTableImpl.validateProfileTableName(profileTableName);

		boolean b = this.sleeTransactionManagement.requireTransaction();
		boolean rb = true;
		ProfileTableImpl profileTable = null;
		try {
			profileTable = this.sleeProfileManagement.getProfileTable(profileTableName);
			if (profileName != null && !profileTable.profileExists(profileName)) {
				throw new UnrecognizedProfileNameException(profileName);
			}
			ObjectName objectName = AbstractProfileMBeanImpl.getObjectName(profileTable.getProfileTableName(), profileName);
			if (!getSleeContainer().getMBeanServer().isRegistered(objectName)) {
				createAndRegisterProfileMBean(profileName, profileTable);
			}
			rb = false;
			return objectName;
		} finally {
			try {
				sleeTransactionManagement.requireTransactionEnd(b,rb);
			} catch (Throwable e) {
				throw new ManagementException(e.getMessage(),e);
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.ProfileProvisioningMBean#getProfileSpecification(java.lang.String)
	 */
	public ProfileSpecificationID getProfileSpecification(String profileTableName) throws NullPointerException, UnrecognizedProfileTableNameException, ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("getProfileSpecification( profileTableName = "
					+ profileTableName +" )");
		}

		if (profileTableName == null)
			throw new NullPointerException("Argument[ProfileTableName] must not be null");

		boolean b = false;
		try {
			b = this.sleeTransactionManagement.requireTransaction();

			ProfileTableImpl profileTable = this.sleeProfileManagement.getProfileTable(profileTableName);
			return profileTable.getProfileSpecificationComponent().getProfileSpecificationID();
		} catch (SLEEException e) {
			throw new ManagementException("Failed to obtain ProfileSpecID name for ProfileTable: " + profileTableName, e);
		} catch (UnrecognizedProfileTableNameException e) {
			throw e;
		} catch (Exception e) {
			throw new ManagementException("Failed to obtain ProfileSpecID name for ProfileTable: " + profileTableName, e);
		} finally {
			// never rollbacks
			try {
				sleeTransactionManagement.requireTransactionEnd(b,false);
			} catch (Throwable e) {
				throw new ManagementException(e.getMessage(),e);
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.ProfileProvisioningMBean#getProfileTableUsageMBean(java.lang.String)
	 */
	public ObjectName getProfileTableUsageMBean(String profileTableName) throws NullPointerException, UnrecognizedProfileTableNameException, InvalidArgumentException, ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("getProfileTableUsageMBean( profileTableName = "
					+ profileTableName +" )");
		}

		if (profileTableName == null)
			throw new NullPointerException("Argument[ProfileTableName] must not be null");

		boolean b = this.sleeTransactionManagement.requireTransaction();
		try {
			ProfileTableUsageMBean usageMBeanImpl = this.sleeProfileManagement.getProfileTable(profileTableName).getProfileTableUsageMBean();
			if (usageMBeanImpl == null) {
				throw new InvalidArgumentException();
			}
			else {
				// ensure it is open
				usageMBeanImpl.open();
				// return its object name
				return usageMBeanImpl.getObjectName();
			}
		} catch (SLEEException e) {
			throw new ManagementException("Failed to obtain ProfileSpecID name for ProfileTable: " + profileTableName, e);
		} catch (UnrecognizedProfileTableNameException e) {
			throw e;
		} catch (InvalidArgumentException e) {
			throw e;
		} catch (Throwable e) {
			throw new ManagementException("Failed to obtain ProfileSpecID name for ProfileTable: " + profileTableName, e);
		} finally {
			// never rollbacks
			try {
				sleeTransactionManagement.requireTransactionEnd(b,false);
			} catch (Throwable e) {
				throw new ManagementException(e.getMessage(),e);
			}
		}

	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.ProfileProvisioningMBean#getProfileTables()
	 */
	public Collection<String> getProfileTables() throws ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("getProfileTables()");
		}

		boolean b = sleeTransactionManagement.requireTransaction();
		try {
			return sleeProfileManagement.getDeclaredProfileTableNames();
		} catch (Exception x) {
			if (x instanceof ManagementException)
				throw (ManagementException) x;
			else
				throw new ManagementException("Failed getProfileTable", x);
		} finally {
			try {
				sleeTransactionManagement.requireTransactionEnd(b,false);
			} catch (Throwable e) {
				throw new ManagementException(e.getMessage(),e);
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.ProfileProvisioningMBean#getProfileTables(javax.slee.profile.ProfileSpecificationID)
	 */
	public Collection<String> getProfileTables(ProfileSpecificationID id) throws java.lang.NullPointerException, UnrecognizedProfileSpecificationException, ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("getProfileTables( id = "+ id + " )");
		}

		if (id == null) {
			throw new NullPointerException("null profile spec id");
		}

		boolean b = sleeTransactionManagement.requireTransaction();
		try {
			return sleeProfileManagement.getDeclaredProfileTableNames(id);
		} catch (UnrecognizedProfileSpecificationException x) {
			throw x;
		} catch (Throwable x) {
			throw new ManagementException("Failed createProfileTable", x);
		} finally {
			try {
				sleeTransactionManagement.requireTransactionEnd(b,false);
			} catch (Throwable e) {
				throw new ManagementException(e.getMessage(),e);
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.ProfileProvisioningMBean#getProfiles(java.lang.String)
	 */
	public Collection<ProfileID> getProfiles(String profileTableName) throws NullPointerException, UnrecognizedProfileTableNameException, ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("getProfiles( profileTableName = "
					+ profileTableName + " )");
		}

		boolean b = sleeTransactionManagement.requireTransaction();
		try {
			return sleeProfileManagement.getProfileTable(profileTableName).getProfiles();
		} catch (NullPointerException e) {
			throw e;
		} catch (UnrecognizedProfileTableNameException e) {
			throw e;
		} catch (Throwable e) {
			throw new ManagementException(e.getMessage(), e);
		} finally {
			try {
				sleeTransactionManagement.requireTransactionEnd(b,false);
			} catch (Throwable e) {
				throw new ManagementException(e.getMessage(),e);
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.ProfileProvisioningMBean#getProfilesByAttribute(java.lang.String, java.lang.String, java.lang.Object)
	 */
	public Collection<ProfileID> getProfilesByAttribute(String profileTableName,
			String attributeName, Object attributeValue)
			throws NullPointerException, UnrecognizedProfileTableNameException,
			UnrecognizedAttributeException, AttributeTypeMismatchException,
			ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("getProfilesByAttribute( profileTableName = "
					+ profileTableName + " , attributeName = " + attributeName
					+ " , attributeValue = " + attributeValue + " )");
		}

		boolean b = sleeTransactionManagement.requireTransaction();
		try {
			ProfileTableImpl profileTable = sleeProfileManagement.getProfileTable(profileTableName);
			if (!profileTable.getProfileSpecificationComponent().isSlee11()) {
				throw new UnsupportedOperationException("JAIN SLEE 1.1 Specs forbiddens the usage of this method on SLEE 1.0 Profile Tables");
			}
			else {
				return profileTable.getProfilesByAttribute(attributeName,attributeValue,true);
			}
		} catch (NullPointerException e) {
			throw e;
		} catch (UnrecognizedProfileTableNameException e) {
			throw e;
		} catch (UnrecognizedAttributeException e) {
			throw e;
		} catch (AttributeTypeMismatchException e) {
			throw e;
		} catch (Throwable e) {
			throw new ManagementException(e.getMessage(), e);
		} finally {
			try {
				sleeTransactionManagement.requireTransactionEnd(b,false);
			} catch (Throwable e) {
				throw new ManagementException(e.getMessage(),e);
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.ProfileProvisioningMBean#getProfilesByDynamicQuery(java.lang.String, javax.slee.profile.query.QueryExpression)
	 */
	public Collection<ProfileID> getProfilesByDynamicQuery(String profileTableName,
			QueryExpression queryExpression) throws NullPointerException,
			UnrecognizedProfileTableNameException,
			UnrecognizedAttributeException, AttributeTypeMismatchException,
			ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("getProfilesByDynamicQuery( profileTableName = "
					+ profileTableName + " , queryExpression = " + queryExpression
					+ " )");
		}

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

		boolean b = sleeTransactionManagement.requireTransaction();

		Collection<ProfileID> profileIDs = new ArrayList<ProfileID>();
		try {
			ProfileTableImpl profileTable = sleeProfileManagement.getProfileTable(profileTableName);
			if (!profileTable.getProfileSpecificationComponent().isSlee11()) {
				throw new UnsupportedOperationException("JAIN SLEE 1.1 Specs forbiddens the usage of this method on SLEE 1.0 Profile Tables");
			}
			for (ProfileEntity profileEntity : profileTable.getProfileSpecificationComponent().getProfileEntityFramework().getProfilesByDynamicQuery(profileTableName,queryExpression)) {
				profileIDs.add(new ProfileID(profileEntity.getTableName(),profileEntity.getProfileName()));
			}
		} catch (NullPointerException e) {
			throw e;
		} catch (UnrecognizedProfileTableNameException e) {
			throw e;
		} catch (UnrecognizedAttributeException e) {
			throw e;
		} catch (AttributeTypeMismatchException e) {
			throw e;
		} catch (Throwable e) {
			throw new ManagementException("Failed to obtain ProfileNames for ProfileTable: " + profileTableName, e);
		}
		finally {
			try {
				sleeTransactionManagement.requireTransactionEnd(b,false);
			} catch (Throwable e) {
				throw new ManagementException(e.getMessage(),e);
			}
		}

		return profileIDs;

	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.ProfileProvisioningMBean#getProfilesByIndexedAttribute(java.lang.String, java.lang.String, java.lang.Object)
	 */
	public Collection<?> getProfilesByIndexedAttribute(String profileTableName,
			String attributeName, Object attributeValue)
			throws NullPointerException, UnrecognizedProfileTableNameException,
			UnrecognizedAttributeException, AttributeNotIndexedException,
			AttributeTypeMismatchException, ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("getProfilesByIndexedAttribute( profileTableName = "
					+ profileTableName + " , attributeName = " + attributeName
					+ " , attributeValue = " + attributeValue + " )");
		}

		boolean b = sleeTransactionManagement.requireTransaction();
		try {
			ProfileTableImpl profileTable = sleeProfileManagement.getProfileTable(profileTableName);
			if (profileTable.getProfileSpecificationComponent().isSlee11()) {
				throw new UnsupportedOperationException("JAIN SLEE 1.1 Specs forbiddens the usage of this method on SLEE 1.1 Profile Tables");
			}
			else {
				return profileTable.getProfilesByAttribute(attributeName,attributeValue,false);
			}
		} catch (NullPointerException e) {
			throw e;
		} catch (UnrecognizedProfileTableNameException e) {
			throw e;
		} catch (UnrecognizedAttributeException e) {
			throw e;
		} catch (AttributeTypeMismatchException e) {
			throw e;
		} catch (AttributeNotIndexedException e) {
			throw e;
		} catch (Throwable e) {
			throw new ManagementException(e.getMessage(), e);
		} finally {
			try {
				sleeTransactionManagement.requireTransactionEnd(b,false);
			} catch (Throwable e) {
				throw new ManagementException(e.getMessage(),e);
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.ProfileProvisioningMBean#getProfilesByStaticQuery(java.lang.String, java.lang.String, java.lang.Object[])
	 */
	public Collection<ProfileID> getProfilesByStaticQuery(String profileTableName, String queryName, Object[] parameters) throws NullPointerException,
		UnrecognizedProfileTableNameException,
		UnrecognizedQueryNameException, InvalidArgumentException,
		AttributeTypeMismatchException, ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("getProfilesByStaticQuery( profileTableName = "
					+ profileTableName + " , queryName = " + queryName
					+ " , parameters = " + Arrays.asList(parameters) + " )");
		}

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

		boolean b = sleeTransactionManagement.requireTransaction();

		Collection<ProfileID> profileIDs = new ArrayList<ProfileID>();
		try {
			ProfileTableImpl profileTable = sleeProfileManagement.getProfileTable(profileTableName);
			if (!profileTable.getProfileSpecificationComponent().isSlee11()) {
				throw new UnsupportedOperationException("JAIN SLEE 1.1 Specs forbiddens the usage of this method on SLEE 1.0 Profile Tables");
			}
			for (ProfileEntity profileEntity : profileTable.getProfileSpecificationComponent().getProfileEntityFramework().getProfilesByStaticQuery( profileTableName, queryName, parameters )) {
				profileIDs.add(new ProfileID(profileEntity.getTableName(),profileEntity.getProfileName()));
			}
		} catch (NullPointerException e) {
			throw e;
		} catch (UnrecognizedProfileTableNameException e) {
			throw e;
		} catch (UnrecognizedQueryNameException e) {
			throw e;
		} catch (InvalidArgumentException e) {
			throw e;
		} catch (AttributeTypeMismatchException e) {
			throw e;
		} catch (Throwable e) {
			throw new ManagementException("Failed to obtain ProfileNames for ProfileTable: " + profileTableName, e);
		}
		finally {
			try {
				sleeTransactionManagement.requireTransactionEnd(b,false);
			} catch (Throwable e) {
				throw new ManagementException(e.getMessage(),e);
			}
		}

		return profileIDs;
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.ProfileProvisioningMBean#removeProfile(java.lang.String, java.lang.String)
	 */
	public void removeProfile(java.lang.String profileTableName, java.lang.String profileName) throws java.lang.NullPointerException, UnrecognizedProfileTableNameException,
			UnrecognizedProfileNameException, ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("removeProfile( profileTableName = "
					+ profileTableName + " , profileName = " + profileName
					+ " )");
		}

		if (profileTableName == null)
			throw new NullPointerException("Argument[ProfileTableName] must nto be null");
		if (profileName == null)
			throw new NullPointerException("Argument[ProfileName] must nto be null");

		boolean b = this.sleeTransactionManagement.requireTransaction();
		boolean rb = true;
		try {
			ProfileTableImpl profileTable = this.sleeProfileManagement.getProfileTable(profileTableName);
			if (!profileTable.profileExists(profileName)) {
				throw new UnrecognizedProfileNameException("There is no such profile: " + profileName + ", in profile table: " + profileTableName);
			}
			profileTable.removeProfile(profileName, true, false);
			if(!sleeTransactionManagement.getRollbackOnly()) {
				rb = false;
			}
			else {
				throw new ManagementException("Transaction used in profile removal rolled back");
			}
		} catch (UnrecognizedProfileTableNameException e) {
			throw e;
		} catch (UnrecognizedProfileNameException e) {
			throw e;
		} catch (Exception e) {
			throw new ManagementException("Failed to remove due to system level failure.", e);
		} finally {
			try {
				sleeTransactionManagement.requireTransactionEnd(b,rb);
			} catch (Throwable e) {
				throw new ManagementException(e.getMessage(),e);
			}
		}

	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.ProfileProvisioningMBean#removeProfileTable(java.lang.String)
	 */
	public void removeProfileTable(String profileTableName) throws NullPointerException, UnrecognizedProfileTableNameException, ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("removeProfileTable( profileTableName = "
					+ profileTableName + " )");
		}

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

		boolean b = this.sleeTransactionManagement.requireTransaction();
		boolean rb = false;
		try {
			this.sleeProfileManagement.removeProfileTable(profileTableName);
		} catch (UnrecognizedProfileTableNameException e) {
			rb = true;
			throw e;
		} catch (Throwable e) {
			rb = true;
			throw new ManagementException("Failed to remove due to system level failure.", e);
		} finally {
			try {
				sleeTransactionManagement.requireTransactionEnd(b,rb);
			} catch (Throwable e) {
				throw new ManagementException(e.getMessage(),e);
			}
		}

	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.ProfileProvisioningMBean#renameProfileTable(java.lang.String, java.lang.String)
	 */
	public void renameProfileTable(java.lang.String oldProfileTableName, java.lang.String newProfileTableName) throws java.lang.NullPointerException, UnrecognizedProfileTableNameException,
			InvalidArgumentException, ProfileTableAlreadyExistsException, ManagementException {

		if (logger.isDebugEnabled()) {
			logger.debug("renameProfileTable( oldProfileTableName = "
					+ oldProfileTableName + " , newProfileTableName = "
					+ newProfileTableName + " )");
		}

		if (oldProfileTableName == null)
			throw new NullPointerException("Argument[OldProfileTableName] must nto be null");
		if (newProfileTableName == null)
			throw new NullPointerException("Argument[NewProfileTableName] must nto be null");

		ProfileTableImpl.validateProfileTableName(newProfileTableName);

		boolean b = this.sleeTransactionManagement.requireTransaction();
		boolean rb = true;
		try {
			this.sleeProfileManagement.renameProfileTable(oldProfileTableName,newProfileTableName);
			rb = false;
		} catch (UnrecognizedProfileTableNameException e) {
			throw e;
		} catch (ProfileTableAlreadyExistsException e) {
			throw e;
		} catch (Throwable e) {
			throw new ManagementException("Failed to remove due to system level failure.", e);
		} finally {
			try {
				sleeTransactionManagement.requireTransactionEnd(b,rb);
			} catch (Throwable e) {
				throw new ManagementException(e.getMessage(),e);
			}
		}
	}

	/**
	 *
	 * start MBean service lifecycle method
	 *
	 */
	protected void startService() throws Exception {
		// this.profileManager =
		// (SleeProfileManager)SleeProfileManager.getInstance();
		logger.info("ProfileProvisioningMBean has been started");
		// register service in JNDI
		// SleeContainer.registerFacilityWithJndi(SleeProfileManager.JNDI_NAME,
		// profileManager);
	}

	/**
	 *
	 * stop MBean service lifecycle method
	 *
	 */
	protected void stopService() throws Exception {

		// unregister the SleeProfileManager service with JNDI
		// SleeContainer.unregisterFacilityWithJndi(SleeProfileManager.JNDI_NAME);

		// this.profileManager = null;
	}

}


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

/**
 *
 */
package org.mobicents.slee.runtime.usage;

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

import javax.slee.management.NotificationSource;
import javax.slee.usage.SampleStatistics;

import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.management.jmx.UsageMBeanImpl;
import org.mobicents.slee.runtime.usage.local.UsageMBeanLocalData;

/**
 * Base class for impl of usage parameters, it offers basic ops for params.
 *
 * @author baranowb
 *
 */
public abstract class AbstractUsageParameterSet {

	private static final String _DEFAULT_SET_NAME_ = "";

	private final UsageMBeanData usageMbeanData;

	private NotificationSource notificationSource;
	private String parameterSetName;
	private UsageMBeanImpl usageMBean;

	public AbstractUsageParameterSet(NotificationSource notificationSource, String parameterSetName, SleeContainer sleeContainer) {

		// checks
		if (notificationSource == null) {
			throw new NullPointerException("Notification Source must not be null.");
		}
		if (sleeContainer == null) {
			throw new NullPointerException("Slee Container must not be null.");
		}

		// set
		this.notificationSource = notificationSource;
		if (parameterSetName == null) {
			this.parameterSetName = _DEFAULT_SET_NAME_;
		} else {
			this.parameterSetName = parameterSetName;
		}

		// now init.
		this.usageMbeanData = new UsageMBeanLocalData(notificationSource,this.parameterSetName);
		this.usageMbeanData.create();

		Collection<String> paramNames = this.getParameterNames();
		for (String parameterName : paramNames) {
			if (this.usageMbeanData.getParameter(parameterName) == null) {
				this.usageMbeanData.setParameter(parameterName, new UsageParameter(this.notificationSource,parameterName));
			}
		}

	}

	protected abstract Collection<String> getParameterNames();

	public UsageMBeanImpl getUsageMBean() {
		return usageMBean;
	}

	public void setUsageMBean(UsageMBeanImpl usageMBean) {
		this.usageMBean = usageMBean;
	}

	public NotificationSource getNotificationSource() {
		return notificationSource;
	}

	public String getParameterSetName() {
		if (this.parameterSetName.equals(_DEFAULT_SET_NAME_))
			return null;
		return parameterSetName;
	}

	public void remove() {
		this.usageMbeanData.remove();
	}

	public void reset() {
		// XXX: we use strings as names(wow what a discovery), so underlying
		// impl must return String collection.
		Collection<String> parameterNames = this.usageMbeanData.getParameterNames();
		for (String parameterName : parameterNames) {
			resetParameter(parameterName);
		}
	}

	private void resetParameter(String parameterName) {
		UsageParameter parameter = this.usageMbeanData.getParameter(parameterName);
		if (parameter != null) {
			parameter.reset();
			this.usageMbeanData.setParameter(parameterName, parameter);

		}

	}

	public void incrementParameter(String parameterName, long incValue) {
		UsageParameter usageParameter = this.usageMbeanData.getParameter(parameterName);
		usageParameter.increment(incValue);
		this.usageMbeanData.setParameter(parameterName, usageParameter);
		this.usageMBean.sendUsageNotification(usageParameter.getValue(), usageParameter.getCount(), getParameterSetName(), parameterName, true);
	}

	public long getParameter(String parameterName, boolean reset) {
		UsageParameter usageParameter = this.usageMbeanData.getParameter(parameterName);

		long tmpValue = usageParameter.getValue();
		if (reset) {
			usageParameter.reset();
			this.usageMbeanData.setParameter(parameterName, usageParameter);
		}
		return tmpValue;
	}

	public void sampleParameter(String parameterName, long sample) {
		UsageParameter usageParameter = this.usageMbeanData.getParameter(parameterName);
		usageParameter.sample(sample);
		this.usageMbeanData.setParameter(parameterName, usageParameter);
		this.usageMBean.sendUsageNotification(sample, usageParameter.getCount(), getParameterSetName(), parameterName, false);
	}

	public SampleStatistics getParameterSampleStatistics(String parameterName, boolean reset) {

		UsageParameter usageParameter = this.usageMbeanData.getParameter(parameterName);

		SampleStatistics ss = new SampleStatistics(usageParameter.getCount(), usageParameter.getMin(), usageParameter.getMax(), usageParameter.getMean());
		if (reset) {
			usageParameter.reset();
			this.usageMbeanData.setParameter(parameterName, usageParameter);
		}
		return ss;

	}

	/**
	 * Convenience method to create new instance of concrete impl class of
	 * {@link AbstractUsageParameterSet}.
	 *
	 * @param concreteClass
	 * @param notificationSource
	 * @param parameterSetName
	 * @param mcCache
	 * @return
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 * @throws IllegalArgumentException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static final AbstractUsageParameterSet newInstance(Class<?> concreteClass, NotificationSource notificationSource, String parameterSetName, SleeContainer sleeContainer)
			throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
		Constructor<?> constructor = concreteClass.getConstructor(NotificationSource.class, String.class, SleeContainer.class);
		return (AbstractUsageParameterSet) constructor.newInstance(notificationSource, parameterSetName, sleeContainer);
	}

}


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

package org.mobicents.slee.resource;

import javax.slee.SLEEException;
import javax.transaction.SystemException;

import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.activity.ActivityContextFactory;
import org.mobicents.slee.container.transaction.SleeTransaction;
import org.mobicents.slee.container.transaction.SleeTransactionManager;

/**
 * Base for executors of slee endpoint operations, which must be executed out of
 * any tx context.
 *
 * @author martins
 *
 */
public abstract class SleeEndpointOperationNotTransactedExecutor {

	/**
	 * the container's tx manager
	 */
	final SleeTransactionManager txManager;

	/**
	 * the endpoint bound to the executor
	 */
	final SleeEndpointImpl sleeEndpoint;

	/**
	 * the container's ac factory
	 */
	final ActivityContextFactory acFactory;
	/**
	 *
	 * @param sleeContainer
	 * @param sleeEndpoint
	 */
	SleeEndpointOperationNotTransactedExecutor(SleeContainer sleeContainer,SleeEndpointImpl sleeEndpoint) {
		this.txManager = sleeContainer.getTransactionManager();
		this.acFactory = sleeContainer.getActivityContextFactory();
		this.sleeEndpoint = sleeEndpoint;
	}

	/**
	 * Suspends the current tx (if exists).
	 * @return the tx which was suspended, null if there is no active tx
	 * @throws SLEEException if there is a system error in tx manager
	 */
	SleeTransaction suspendTransaction() throws SLEEException {
		try {
			final SleeTransaction tx = txManager.getTransaction();
			if (tx != null) {
				txManager.suspend();
			}
			return tx;
		} catch (SystemException e) {
			throw new SLEEException(e.getMessage(),e);
		}
	}

	/**
	 * Resumes the specified tx. If it is null nothing is done.
	 * @param transaction
	 * @throws SLEEException if there is a system error in tx manager
	 */
	void resumeTransaction(SleeTransaction transaction) throws SLEEException {
		if (transaction != null) {
			try {
				txManager.resume(transaction);
			} catch (Throwable e) {
				throw new SLEEException(e.getMessage(),e);
			}
		}
	}
}


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

package org.mobicents.slee.container.component.deployment.classloading;

import java.net.URL;

import javax.slee.ComponentID;

import org.mobicents.slee.container.component.classloading.ClassLoaderFactory;
import org.mobicents.slee.container.component.classloading.URLClassLoaderDomain;

/**
 * @author martins
 *
 */
public class ClassLoaderFactoryImpl implements ClassLoaderFactory {

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.core.component.classloading.ClassLoaderFactory#
	 * newClassLoaderDomain(java.net.URL[], java.lang.ClassLoader)
	 */
	public URLClassLoaderDomainImpl newClassLoaderDomain(URL[] urls,
			ClassLoader sleeClassLoader) {
		return new URLClassLoaderDomainImpl(urls, sleeClassLoader);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.core.component.classloading.ClassLoaderFactory#
	 * newComponentClassLoader(javax.slee.ComponentID,
	 * org.mobicents.slee.core.component.classloading.URLClassLoaderDomain)
	 */
	public ComponentClassLoaderImpl newComponentClassLoader(
			ComponentID componentID, URLClassLoaderDomain parent) {
		return new ComponentClassLoaderImpl(componentID, (URLClassLoaderDomainImpl) parent);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.core.component.classloading.ClassLoaderFactory#
	 * newReplicationClassLoader(java.lang.ClassLoader)
	 */
	public ReplicationClassLoaderImpl newReplicationClassLoader(
			ClassLoader sleeClassLoader) {
		return new ReplicationClassLoaderImpl(sleeClassLoader);
	}

}


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

package org.mobicents.slee.container.component;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.slee.ComponentID;
import javax.slee.SbbID;
import javax.slee.ServiceID;
import javax.slee.management.ComponentDescriptor;
import javax.slee.management.DependencyException;
import javax.slee.management.DeploymentException;
import javax.slee.management.ServiceState;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.component.ComponentRepository;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.ServiceDescriptorImpl;
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.management.jmx.ServiceUsageMBean;

/**
 * Start time:16:00:31 2009-01-25

 * Project: restcomm-jainslee-server-core

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

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

	/**
	 * the service descriptor
	 */
	private final ServiceDescriptorImpl descriptor;

	/**
	 * the JAIN SLEE specs descriptor
	 */
	private javax.slee.management.ServiceDescriptor specsDescriptor = null;

	/**
	 * the {@link SbbComponent} the service defines as root
	 */
	private SbbComponent rootSbbComponent = null;

	/**
	 * the usage mbean for this service
	 */
	private ServiceUsageMBean serviceUsageMBean;

	/**
	 * the service alarm notification sources, mapped by sbb id.
	 *
	 * note: Tracer and Alarm have their own MNotificationSource, sequence don't
	 * match, and alarm sequence numbers must be consistent.
	 */
	private ConcurrentHashMap<SbbID, Object> alarmNotificationSources =
		new ConcurrentHashMap<SbbID, Object>();

	/**
	 * the time in milliseconds this component was created
	 */
	private final long creationTime = System.currentTimeMillis();

	private ServiceState serviceState = ServiceState.INACTIVE;

	private boolean activityEnded = false;

	/**
	 *
	 * @param descriptor
	 */
	public ServiceComponentImpl(ServiceDescriptorImpl descriptor) {
		this.descriptor = descriptor;
	}

	/**
	 * Retrieves the service alarm notification sources, mapped by sbb id.
	 * @return
	 */
	public ConcurrentHashMap<SbbID, Object> getAlarmNotificationSources() {
		return alarmNotificationSources;
	}

	/**
	 * Retrieves the service descriptor
	 *
	 * @return
	 */
	public ServiceDescriptorImpl getDescriptor() {
		return descriptor;
	}

	/**
	 * Retrieves the id of the service
	 *
	 * @return
	 */
	public ServiceID getServiceID() {
		return descriptor.getServiceID();
	}

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

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

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

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

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

	/**
	 * Retrieves the JAIN SLEE specs descriptor
	 *
	 * @return
	 */
	public javax.slee.management.ServiceDescriptor getSpecsDescriptor() {
		if (specsDescriptor == null) {
			specsDescriptor = new javax.slee.management.ServiceDescriptor(getServiceID(),
					getDeployableUnit().getDeployableUnitID(),
					getDeploymentUnitSource(), descriptor.getRootSbbID(),
					descriptor.getAddressProfileTable(),
					descriptor.getResourceInfoProfileTable());
		}
		return specsDescriptor;
	}

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

	/**
	 * Retrieves the time in milliseconds this component was created
	 * @return
	 */
	public long getCreationTime() {
		return creationTime;
	}

	/**
	 * Retrieves the set of sbbs used by this service
	 *
	 * @param componentRepository
	 * @return
	 */
	public Set<SbbID> getSbbIDs(ComponentRepository componentRepository) {
		Set<SbbID> result = new HashSet<SbbID>();
		buildSbbTree(descriptor.getRootSbbID(), result,
				componentRepository);
		return result;
	}

	private void buildSbbTree(SbbID sbbID, Set<SbbID> result,
			ComponentRepository componentRepository) {
		result.add(sbbID);
		SbbComponent sbbComponent = componentRepository.getComponentByID(sbbID);
		for (ComponentID componentID : sbbComponent.getDependenciesSet()) {
			if (componentID instanceof SbbID) {
				SbbID anotherSbbID = (SbbID) componentID;
				if (!result.contains(anotherSbbID)) {
					buildSbbTree(anotherSbbID, result, componentRepository);
				}
			}
		}
	}

	/**
	 * Retrieves the set of ra entity links referenced by the sbbs related with the service.
	 * @param componentRepository
	 * @return
	 */
	public Set<String> getResourceAdaptorEntityLinks(ComponentRepository componentRepository) {
		Set<String> result = new HashSet<String>();
		for (SbbID sbbID : getSbbIDs(componentRepository)) {
			SbbComponent sbbComponent = componentRepository.getComponentByID(sbbID);
			for (ResourceAdaptorTypeBindingDescriptor raTypeBinding : sbbComponent.getDescriptor().getResourceAdaptorTypeBindings()) {
				for (ResourceAdaptorEntityBindingDescriptor raEntityBinding : raTypeBinding.getResourceAdaptorEntityBinding()) {
					result.add(raEntityBinding.getResourceAdaptorEntityLink());
				}
			}
		}
		return result;
	}

	/**
	 * Retrieves the {@link SbbComponent} the service defines as root
	 *
	 * @return
	 */
	public SbbComponent getRootSbbComponent() {
		return rootSbbComponent;
	}

	/**
	 * Sets the {@link SbbComponent} the service defines as root
	 *
	 * @param rootSbbComponent
	 */
	public void setRootSbbComponent(SbbComponent rootSbbComponent) {
		this.rootSbbComponent = rootSbbComponent;
	}

	/**
	 * Retrieves the usage mbean for this service
	 *
	 * @return
	 */
	public ServiceUsageMBean getServiceUsageMBean() {
		return serviceUsageMBean;
	}

	/**
	 * Sets the usage mbean for this service
	 *
	 * @param serviceUsageMBean
	 */
	public void setServiceUsageMBean(ServiceUsageMBean serviceUsageMBean) {
		this.serviceUsageMBean = serviceUsageMBean;
	}
	@Override
	public void processSecurityPermissions() throws DeploymentException {
		//Do nothing

	}

	@Override
	public void undeployed() {
		super.undeployed();
		specsDescriptor = null;
		rootSbbComponent = null;
		serviceUsageMBean = null;
		if (alarmNotificationSources != null) {
			alarmNotificationSources.clear();
			alarmNotificationSources = null;
		}
	}

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

	@Override
	public ServiceState getServiceState() {
		return serviceState;
	}

	@Override
	public void setServiceState(ServiceState state) {
		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("Changing "+getServiceID()+" state to "+state);
		}
		this.serviceState = state;
	}

	private ServiceID oldVersion;

	@Override
	public ServiceID getOldVersion() {
		return oldVersion;
	}

	@Override
	public void setOldVersion(ServiceID oldVersion) {
		this.oldVersion = oldVersion;
	}

	public boolean isActivityEnded() {
		return activityEnded;
	}

	public void setActivityEnded(boolean activityEnded) {
		this.activityEnded = activityEnded;
	}
}


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

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Hashtable;

import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;

/**
 * The class is used as a Default Entity Resolver when parsing slee XML files
 * such as deployment descriptors for example.
 * @author Emil Ivov
 * @author Tim Fox - refactored to use ClassLoader of slee
 */
public class DefaultSleeEntityResolver implements EntityResolver{

    private Hashtable<String,URL> resources = null;

    private static final DefaultSleeEntityResolver instance = new DefaultSleeEntityResolver();

    public static DefaultSleeEntityResolver getInstance() {
    	return instance;
    }

    private DefaultSleeEntityResolver() {
        resources = new Hashtable<String,URL>();
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Deployable Unit 1.0//EN", "dtd/slee-deployable-unit_1_0.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE SBB 1.0//EN", "dtd/slee-sbb-jar_1_0.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Service 1.0//EN", "dtd/slee-service-xml_1_0.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Resource Adaptor Type 1.0//EN", "dtd/slee-resource-adaptor-type-jar_1_0.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Resource Adaptor 1.0//EN", "dtd/slee-resource-adaptor-jar_1_0.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Profile Specification 1.0//EN", "dtd/slee-profile-spec-jar_1_0.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Event 1.0//EN", "dtd/slee-event-jar_1_0.dtd");
        //We add this, cause JAXB supports XMLNode as source, we need to parse to determine which Context we want to use, 1.0 or 1.1
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Deployable Unit 1.1//EN", "dtd/slee-deployable-unit_1_1.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE SBB 1.1//EN", "dtd/slee-sbb-jar_1_1.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Service 1.1//EN", "dtd/slee-service-xml_1_1.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Resource Adaptor Type 1.1//EN", "dtd/slee-resource-adaptor-type-jar_1_1.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Resource Adaptor 1.1//EN", "dtd/slee-resource-adaptor-jar_1_1.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Profile Specification 1.1//EN", "dtd/slee-profile-spec-jar_1_1.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Event 1.1//EN", "dtd/slee-event-jar_1_1.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Library 1.1//EN","dtd/slee-library-jar_1_1.dtd");
        // For SLEE 1.1 Extensions
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Ext Library 1.1//EN", "dtd/slee-library-jar_1_1-ext.dtd");

    }

    /**
     * Adds a URL to the specified resource (as returned by the system classloader).
     * to the resource table of the resolver.
     * @param publicID the public id of the resource
     * @param resourceName the path (starting from a location in the class path)
     * and name of the dtd that should be used by the resolver for documents
     * with the specified public id.
     */
    private void registerResource(String publicID, String resourceName)
    {
        URL url = this.getClass().getClassLoader().getResource(resourceName);
        if (url != null) {
            resources.put(publicID, url);
        }
        else {
            //All the slee dtds should be packaged locally in sar of slee itself
            throw new IllegalStateException("Cannot find resource:" + resourceName);
        }
    }

    /**
     * Creates an InputSource with a SystemID corresponding to a local dtd file.
     * @param publicId The public identifier of the external entity
     *        being referenced, or null if none was supplied.
     * @param systemId The system identifier of the external entity
     *        being referenced (This is a dummy parameter and is overridden by
     *        the resource names earlier specified by the
     *        registrerResource) method to correspond to the publicID.
     * @return An InputSource object describing the new input source,
     *         or null to request that the parser open a regular
     *         URI connection to the system identifier.
     * @exception org.xml.sax.SAXException Any SAX exception, possibly
     *            wrapping another exception.
     * @exception java.io.IOException A Java-specific IO exception,
     *            possibly the result of creating a new InputStream
     *            or Reader for the InputSource.
     */
    public InputSource resolveEntity(String publicId, String systemId)
        throws IOException
    {
    	if (publicId != null) {
			final URL resourceURL = resources.get(publicId);
			if (resourceURL != null) {
				InputStream resourceStream = null;
				resourceStream = resourceURL.openStream();
				InputSource is = new InputSource(resourceStream);
				is.setPublicId(publicId);
				is.setSystemId(resourceURL.toExternalForm());
				return is;
			}
		}
		return null;
	}

}