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

/**
 * Start time:13:40:09 2009-04-13

 * Project: restcomm-jainslee-server-core

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

import java.io.File;
import java.io.FileInputStream;
import java.io.FilePermission;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.security.AccessController;
import java.security.CodeSource;
import java.security.KeyStore;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.security.UnresolvedPermission;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.PropertyPermission;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.component.security.PermissionHolder;

import sun.security.provider.PolicyParser;
import sun.security.provider.PolicyParser.GrantEntry;
import sun.security.provider.PolicyParser.PermissionEntry;
import sun.security.util.SecurityConstants;

/**
 * Start time:13:40:09 2009-04-13

 * Project: restcomm-jainslee-server-core

 *
 * @author baranowb - Bartosz Baranowski
 *
 */
public class PolicyFileImpl extends org.mobicents.slee.container.component.security.PolicyFile {
	// FIXME: should this be private class?
	private static final Logger logger = Logger.getLogger(PolicyFileImpl.class);

	// FIXME: make PermissionHolder default container??
	private AtomicReference<GlobalPolicyHolder> currentPolicy = new AtomicReference<GlobalPolicyHolder>(new GlobalPolicyHolder());

	//public static boolean show = false;
	private final Set<PermissionHolderImpl> sleeComponentsPermissions = new HashSet<PermissionHolderImpl>();

	// Some statics
	private static String _DEFAULT_POLICY;
	private static String _DEFAULT_USER_POLICY;
	private final static String _POLICY_URL_PART = "policy.url.";
	private static final String _POLICY_PROPERTY = "java.security.policy";

	// no args
	private static final Class[] _PARAMS_0 = {};
	// name
	private static final Class[] _PARAMS_1 = { String.class };
	// name,action
	private static final Class[] _PARAMS_2 = { String.class, String.class };

	private final static String _PROTOCOL_FILE = "file";
	private final static String _PROTOCOL_FILE_PREFIX = "file://";
	static {

		AccessController.doPrivileged(new PrivilegedAction() {

			public Object run() {
				Properties systemProperties = System.getProperties();
				_DEFAULT_POLICY = (_PROTOCOL_FILE_PREFIX + systemProperties.getProperty("java.home") + File.separator + "lib" + File.separator + "security" + File.separator + "java.policy").replace(
						"\\", File.separator).replace(" ", "\\ ");

				_DEFAULT_USER_POLICY = (_PROTOCOL_FILE_PREFIX + systemProperties.getProperty("user.home") + File.separator + ".java.policy").replace("\\", File.separator).replace(" ", "\\ ");
				return null;
			}

		});

	}

	@Override
	public PermissionCollection getPermissions(CodeSource codesource) {

		Permissions p = new Permissions();
		// We must always return muttable coolection
		// FIXME: shoyuld this be done ni priviledged section?
		// codesource = AccessController.doPrivileged(new
		// PerformURLConversionAction2( true,codesource,this));
		codesource = performUrlConversion(codesource, true);
		p = (Permissions) this.getPermissions(p, codesource);
		//if(show)
		//	doPermDump(p, "RETURN: " + codesource);
		return p;

	}

	@Override
	public PermissionCollection getPermissions(ProtectionDomain domain) {
		Permissions permissions = new Permissions();

		if (domain == null)
			return permissions;

		getPermissions(permissions, domain);
		PermissionCollection pc = domain.getPermissions();
		if (pc != null) {
			Enumeration domainPermissions = pc.elements();
			while (domainPermissions.hasMoreElements()) {
				permissions.add((Permission) domainPermissions.nextElement());
			}
		}
		//if(show)
		//	doPermDump(permissions, "RETURN2: " + domain.getCodeSource());
		return permissions;
	}

	private void doPermDump(PermissionCollection pc, String string) {

		Enumeration<Permission> en = pc.elements();
		while (en.hasMoreElements()) {
			Permission p = en.nextElement();
			logger.info(string + "===>P:" + p.getClass() + " N:" + p.getName() + " A:" + p.getActions());
		}

	}

	private PermissionCollection getPermissions(Permissions permissions, CodeSource codesource) {

		// Add some actions here?
		return this.getPermissions(permissions, codesource, null);
	}

	// generic, for all calls
	private Permissions getPermissions(Permissions permissions, final CodeSource cs, Principal[] principals) {

		List<PolicyHolderEntry> entries = this.currentPolicy.get().policyHolderEntries;

		for (PolicyHolderEntry phe : entries) {

			// general
			selectPermissions(permissions, cs, principals, phe);

			// FIXME: certs?

		}

		return permissions;
	}

	private void getPermissions(Permissions permissions, ProtectionDomain domain) {
		CodeSource cs = domain.getCodeSource();
		if (cs == null)
			return;
		// FIXME: should we
		// cs = AccessController.doPrivileged(new PerformURLConversionAction2(
		// true,cs,this));
		cs = performUrlConversion(cs, true);

		// FIXME: add more actions?

		getPermissions(permissions, cs, domain.getPrincipals());

	}

	private void selectPermissions(Permissions permissions, final CodeSource cs, Principal[] principals, final PolicyHolderEntry phe) {

		// FIXME: this always gets into if... even if debug is not on...
		// if (logger.isDebugEnabled() ) {
		//
		//if (show)
		//	logger.info("Select permissions. \nFor: " + cs + ", Entry\n CS: " + phe.getCodeSource() + "\n" + phe.getCodeSource().implies(cs));
		// }

		Boolean implies = phe.getCodeSource().implies(cs);
		// Boolean implies = (Boolean) AccessController.doPrivileged(new
		// ImpliesAction(cs,phe));
		// System.err.println("I["+implies+"]  For: " + cs + ", Entry CS: " +
		// phe.getCodeSource());
		boolean addPermissions = false;
		if (!implies.booleanValue()) {

			return;
		} else {

			final Principal[] pdp = principals;
			List entryPs = phe.getPrincipals();
			List domainPs = new LinkedList();
			// if (pdp != null && pdp.length != 0) {
			// PolicyParser.PrincipalEntry pe = null;
			// for (int j = 0; j < pdp.length; j++) {
			// pe = new PolicyParser.PrincipalEntry(pdp[j].getClass().getName(),
			// pdp[j].getName());
			// domainPs.add(pe);
			// }
			// }

			if (entryPs == null || entryPs.isEmpty()) {

				addPermissions = true;
			} else if (!domainPs.isEmpty()) {

				// FIXME: what goes here?
			}

			// implies succeeded - grant the permissions
			if (!addPermissions) {

			} else {

				List<Permission> permissionsList = phe.getPermissions();
				//if(show)
				//	System.err.println("PERMS: "+permissionsList.size());
				for (int j = 0; j < permissionsList.size(); j++) {

					Permission p = permissionsList.get(j);
				//	if(show)
				//		System.err.println("PERMSx: "+p);
					permissions.add(p);

				}
			}
		}

	}

	@Override
	public boolean implies(ProtectionDomain domain, Permission permission) {

		Map<ProtectionDomain, PermissionCollection> pdMap = this.currentPolicy.get().getProtectionDomain2PermissionCollection();

		PermissionCollection pc = pdMap.get(domain);

		if (pc != null) {
			return pc.implies(permission);
		}

		pc = getPermissions(domain);
		if (pc == null) {
			return false;
		}

		// cache mapping of protection domain to its PermissionCollection
		pdMap.put(domain, pc);
		return pc.implies(permission);

	}

	@Override
	public void refresh() {

		final GlobalPolicyHolder newGlobalPolicyHolder = new GlobalPolicyHolder();
		final Properties p = System.getProperties();
		// First we load all default policies.
		try {
			AccessController.doPrivileged(new PrivilegedExceptionAction() {

				public Object run() throws Exception {

					String extraURL = p.getProperty(_POLICY_PROPERTY);
					if (extraURL != null) {
						// if we have this we dont load default policies.
						loadPolicy(extraURL, newGlobalPolicyHolder);
						newGlobalPolicyHolder.loadedFiles.add(extraURL);

					} else {
						// URL policyURL = new URL(_DEFAULT_POLICY);
						String policyURL = _DEFAULT_POLICY;
						if (!loadPolicy(policyURL, newGlobalPolicyHolder)) {

							if (logger.isDebugEnabled()) {
								logger.debug("Failed to load policy file: " + policyURL);
							}
						} else {
							newGlobalPolicyHolder.loadedFiles.add(policyURL);
						}

						// policyURL = new URL(_DEFAULT_USER_POLICY);
						policyURL = _DEFAULT_USER_POLICY;
						if (!loadPolicy(policyURL, newGlobalPolicyHolder)) {
							if (logger.isDebugEnabled()) {
								logger.debug("Failed to load policy file: " + policyURL);
							}
						} else {
							newGlobalPolicyHolder.loadedFiles.add(policyURL);
						}

					}

					return null;
				}

			});
			AccessController.doPrivileged(new PrivilegedExceptionAction() {

				public Object run() throws Exception {
					// load some other parts :)
					for (int counter = 1;; counter++) {
						String urlValue = p.getProperty(_POLICY_URL_PART + counter);
						if (urlValue == null)
							break;
						// policyURL = new URL(urlValue);
						String policyURL = urlValue;
						if (!loadPolicy(policyURL, newGlobalPolicyHolder)) {
							if (logger.isDebugEnabled()) {
								logger.debug("Failed to load policy file: " + policyURL);
							}
						}

					}
					return null;
				}

			});
			// System.err.println("SLEE POLICIES: "+sleeComponentsPermissions.size());

			// now lets push slee policies :)
			for (PermissionHolderImpl ph : sleeComponentsPermissions) {

				for (PolicyHolderEntry phe : ph.getPolicyHolderEntry()) {
					// System.err.println("ADDING PHE: "+phe);
					newGlobalPolicyHolder.policyHolderEntries.add(phe);
				}
			}

			// for(Object o: sleeComponentsPermissions)
			// {
			// System.err.println("SLEE POLICIES: "+o);
			// }
		} catch (Exception e) {
			// if we fail, lets dump info, and load defualt policy

			logger.error("Failed to load policies due to some reason. See error message. Loadign default policy.");
			e.printStackTrace();
			loadDefaultPolicy(newGlobalPolicyHolder);
		}
		if (newGlobalPolicyHolder.isAnyPolicyLoaded())
			loadDefaultPolicy(newGlobalPolicyHolder);
		this.currentPolicy.set(newGlobalPolicyHolder);
	}

	private void loadDefaultPolicy(final GlobalPolicyHolder newGlobalPolicyHolder) {
		AccessController.doPrivileged(new PrivilegedAction<Void>() {
			public Void run() {
				URL u = null;
				Certificate[] c = null;
				PolicyHolderEntry pe = new PolicyHolderEntry(new CodeSource(u, c));
				pe.add(SecurityConstants.LOCAL_LISTEN_PERMISSION);
				pe.add(new PropertyPermission("java.version", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("java.vendor", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("java.vendor.url", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("java.class.version", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("os.name", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("os.version", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("os.arch", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("file.separator", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("path.separator", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("line.separator", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("java.specification.version", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("java.specification.vendor", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("java.specification.name", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("java.vm.specification.version", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("java.vm.specification.vendor", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("java.vm.specification.name", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("java.vm.version", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("java.vm.vendor", SecurityConstants.PROPERTY_READ_ACTION));
				pe.add(new PropertyPermission("java.vm.name", SecurityConstants.PROPERTY_READ_ACTION));

				// No need to sync because noone has access to newInfo yet
				newGlobalPolicyHolder.policyHolderEntries.add(pe);

				return null;
			}
		});

	}

	// private boolean loadPolicy(URL policyURL, GlobalPolicyHolder
	// newGlobalPolicyHolder) {
	private boolean loadPolicy(String policyURLString, GlobalPolicyHolder newGlobalPolicyHolder) {

		// System.err.println("Load policy: " + policyURLString);
		try {
			URI policyURI = null;
			if (policyURLString.startsWith(_PROTOCOL_FILE)) {
				File policyFile = new File(policyURLString.replaceFirst(_PROTOCOL_FILE_PREFIX, ""));
				if (!policyFile.exists() || !policyFile.isFile() || !policyFile.canRead()) {
					if (logger.isDebugEnabled()) {
						logger.debug("Could not load file: " + policyURLString + ", exists[" + policyFile.exists() + "] isFile[" + policyFile.isFile() + "] canRead[" + policyFile.canRead() + "] ");

					}
					// Hmm...
					return false;

				} else {
					policyURI = policyFile.toURI().normalize();
				}
			} else {
				policyURI = new URI(policyURLString);
			}

			PolicyParser pp = new PolicyParser(true);
			InputStream is = getStream(policyURI);
			InputStreamReader reader = new InputStreamReader(is);
			pp.read(reader);
			reader.close();

			// KeyStore ks = ..... FIXME:
			KeyStore ks = null;

			Enumeration<PolicyParser.GrantEntry> grantEntries = pp.grantElements();
			while (grantEntries.hasMoreElements()) {

				parseGrantEntry(grantEntries.nextElement(), ks, newGlobalPolicyHolder);
			}

		} catch (Exception e) {

			if (logger.isDebugEnabled()) {
				logger.debug("Failed to read policy file due to some error.");
				e.printStackTrace();
			}
			return false;
		}

		return true;
	}

	private void parseGrantEntry(GrantEntry nextElement, KeyStore ks, GlobalPolicyHolder newGlobalPolicyHolder) {

		try {
			CodeSource cs = getCodeSource(nextElement, ks);
			// should not be null but:
			if (cs == null)
				return;

			PolicyHolderEntry phe = new PolicyHolderEntry(cs, nextElement.principals);

			Enumeration<PolicyParser.PermissionEntry> permissionEntries = nextElement.permissionElements();
			while (permissionEntries.hasMoreElements()) {

				// FIXME: sun has something like - exapnd permission???
				// FIXME: sun has permission self ?
				PolicyParser.PermissionEntry pEntry = permissionEntries.nextElement();

				try {
					Permission permission = getPermission(pEntry);

					phe.add(permission);
				} catch (ClassNotFoundException cnfe) {
					// FIXME:
					Certificate certs[] = null;

					// only add if we had no signer or we had a
					// a signer and found the keys for it.
					if (certs != null || pEntry.signedBy == null) {
						Permission permission = new UnresolvedPermission(pEntry.permission, pEntry.name, pEntry.action, certs);
						phe.add(permission);

					}
				} catch (Exception e) {

					// if (logger.isDebugEnabled()) {
					logger.error("Failed to add permission to entry.");
					e.printStackTrace();
					// }

				}
			}

			newGlobalPolicyHolder.policyHolderEntries.add(phe);
		} catch (Exception e) {

			// if (logger.isDebugEnabled()) {
			logger.error("Failed to parse grant entry.");
			e.printStackTrace();
			// }

		}

	}

	private void parseGrantEntry(GrantEntry nextElement, KeyStore ks, PermissionHolderImpl permissionHolder) {

		try {
			// System.err.println("PARSING GRANT ENTRY: "+permissionHolder);
			CodeSource cs = getCodeSource(nextElement, ks);

			// should not be null but:
			if (cs == null)
				return;
			PolicyHolderEntry phe = new PolicyHolderEntry(cs, nextElement.principals);

			Enumeration<PolicyParser.PermissionEntry> permissionEntries = nextElement.permissionElements();
			permissionHolder.addPolicyHolderEntry(phe);
			while (permissionEntries.hasMoreElements()) {

				// FIXME: sun has something like - exapnd permission???
				// FIXME: sun has permission self ?
				PolicyParser.PermissionEntry pEntry = permissionEntries.nextElement();

				try {
					Permission permission = getPermission(pEntry);
					phe.add(permission);
				} catch (ClassNotFoundException cnfe) {
					cnfe.printStackTrace();
					// FIXME:
					Certificate certs[] = null;

					// only add if we had no signer or we had a
					// a signer and found the keys for it.
					if (certs != null || pEntry.signedBy == null) {
						Permission permission = new UnresolvedPermission(pEntry.permission, pEntry.name, pEntry.action, certs);
						phe.add(permission);

					}

				} catch (Exception e) {

					if (logger.isDebugEnabled()) {
						logger.error("Failed to add permission to entry.");
						e.printStackTrace();
					}

				}
			}

		} catch (Exception e) {

			if (logger.isDebugEnabled()) {
				logger.error("Failed to parse grant entry.");
				e.printStackTrace();
			}

		}
	}

	private Permission getPermission(PermissionEntry entry) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException,
			IllegalAccessException, InvocationTargetException {

		Class permissionClass = Class.forName(entry.permission);
		// FIXME: should we look for other permissions
		Permission p = null;
		if (entry.name != null && entry.action != null) {
			Constructor c = permissionClass.getConstructor(_PARAMS_2);
			p = (Permission) c.newInstance(new Object[] { entry.name, entry.action });
			// System.err.println("PC: "+permissionClass.getCanonicalName()+" - "+entry.name+" -- "+entry.action);

		} else if (entry.name != null && entry.action == null) {
			Constructor c = permissionClass.getConstructor(_PARAMS_1);
			p = (Permission) c.newInstance(new Object[] { entry.name });
			// System.err.println("PC: "+permissionClass.getCanonicalName()+" - "+entry.name);
		} else {
			Constructor c = permissionClass.getConstructor(_PARAMS_0);
			p = (Permission) c.newInstance(new Object[] {});
			// System.err.println("PC: "+permissionClass.getCanonicalName());
		}

		return p;
	}

	// private InputStream getStream(URL url) throws IOException {
	private InputStream getStream(URI uri) throws IOException {

		try {
			if (uri.toURL().getProtocol().equals(_PROTOCOL_FILE)) {
				String path = uri.toURL().getFile().replace('\\', File.separatorChar);

				return new FileInputStream(path);
			} else {
				return uri.toURL().openStream();
			}
		} catch (java.lang.IllegalArgumentException e) {
			// this happens if url is relative, meaning a file?

			return new FileInputStream(new File(uri));
		}

	}

	private CodeSource getCodeSource(GrantEntry nextElement, KeyStore ks) throws MalformedURLException {

		Certificate[] certs = null;
		if (nextElement.signedBy != null) {
			// FIXME:
			// certs = ...;
			if (certs == null) {
				// we don't have a key for this alias,
				// just return

				// }
				// return null;
			}
		}

		URL location;
		CodeSource cs = null;
		if (nextElement.codeBase != null)
		{

			location = new URL(nextElement.codeBase);
			cs = new CodeSource(location, certs);
			cs=performUrlConversion(cs, false);
		}
		else
		{
			location = null;
			cs = new CodeSource(location, certs);
		}

		// FIXME: sun has something cvalled : canonical ....
		return cs;
	}

	// Some add/remove methods
	public boolean addPermissionHolder(PermissionHolder holder) {

		return this.addPermissionHolder(holder, true);
	}

	public boolean addPermissionHolder(PermissionHolder holder, boolean refresh) {

		PermissionHolderImpl holderImpl = (PermissionHolderImpl) holder;

		if (this.sleeComponentsPermissions.contains(holderImpl)) {
			// System.err.println("ALREADY PRESENT.");
			return false;
		} else {
			this.sleeComponentsPermissions.add(holderImpl);
			// Parse

			// KeyStore ks = ..... FIXME:
			KeyStore ks = null;

			Enumeration<PolicyParser.GrantEntry> grantEntries = holderImpl.getPolicyParser().grantElements();
			while (grantEntries.hasMoreElements()) {

				parseGrantEntry(grantEntries.nextElement(), ks, holderImpl);
			}

			if (refresh)
				this.refresh();
			return true;
		}
	}

	// FIXME: should those method be hidden?

	public boolean removePermissionHolder(PermissionHolder holder) {

		return this.removePermissionHolder(holder, true);
	}

	public boolean removePermissionHolder(PermissionHolder holder, boolean refresh) {

		if (this.sleeComponentsPermissions.contains(holder)) {
			return false;
		} else {
			this.sleeComponentsPermissions.remove(holder);
			if (refresh)
				this.refresh();
			return true;
		}
	}

	/**
	 * This class holds globaly active policies. Start time:13:42:44 2009-04-13

	 * Project: restcomm-jainslee-server-core

	 *
	 * @author baranowb - Bartosz Baranowski
	 *
	 * @author  Alexandre Mendonca
	 */
	private static class GlobalPolicyHolder {
		private final List<PolicyHolderEntry> policyHolderEntries = new ArrayList<PolicyHolderEntry>();
		private final Map<ProtectionDomain, PermissionCollection> protectionDomain2PermissionCollection = new HashMap<ProtectionDomain, PermissionCollection>();
		private final Set<String> loadedFiles = new HashSet<String>();

		public boolean isAnyPolicyLoaded() {
			return !policyHolderEntries.isEmpty();
		}

		public Map<ProtectionDomain, PermissionCollection> getProtectionDomain2PermissionCollection() {
			return protectionDomain2PermissionCollection;
		}

	}

	private static class ImpliesAction implements PrivilegedExceptionAction {
		private CodeSource cs;
		private PolicyHolderEntry phe;

		public ImpliesAction(CodeSource cs, PolicyHolderEntry phe) {
			super();
			this.cs = cs;
			this.phe = phe;
		}

		public Object run() throws Exception {
			// TODO Auto-generated method stuba
			return new Boolean(phe.getCodeSource().implies(cs));
		}

	}

	/**
	 * This function MUST convert code source passed. Meaning it must normalize
	 * URL. For instance security framework may pass url that conceptualy
	 * matches pat specified policy files but comparison wont match. See url
	 * belowe.
	 *

	 *
1 -
	 * jar:file:/D:/java/servers/jboss-5.0.0.GA/server/default/deploy
	 * /restcomm.sar/lib/jar.jar!/

	 *
2 -
	 * file:/D:/java/servers/jboss-5.0.0.GA/server/default/deploy/-

	 *

	 * URL 1 is passed from security framework as source of loaded classes.
	 * However it is not matched by second one (and is should)
	 *
	 * @param cs
	 * @return
	 */
	CodeSource performUrlConversion(CodeSource cs, boolean extractSignerCerts) {

		String path = null;
		CodeSource parsedCodeSource = null;

		URL locationURL = cs.getLocation();
		if (locationURL != null) {
			// can happen for default.
			Permission urlAccessPermission = null;
			try {
				urlAccessPermission = locationURL.openConnection().getPermission();
			} catch (IOException e) {

			}

			if (urlAccessPermission != null && urlAccessPermission instanceof FilePermission) {
				path = ((FilePermission) urlAccessPermission).getName();
			} else if ((urlAccessPermission == null) && (locationURL.getProtocol().equals("file"))) {
				path = locationURL.getFile().replace("/", File.separator);
				// FIXME: do more?
			} else {
				// FIXME: ??
			}
		}

		if (path == null) {
			if (extractSignerCerts) {
				parsedCodeSource = new CodeSource(cs.getLocation(), getSignerCertificates(cs));
			}
		} else {

			try {
				// Sun says it fails
				if (path.endsWith("*")) {
					// remove trailing '*' because it causes
					// canonicaization
					// to fail on win32
					path = path.substring(0, path.length() - 1);
					boolean removeTrailingFileSep = false;
					if (path.endsWith(File.separator))
						removeTrailingFileSep = true;
					if (path.equals("")) {
						path = System.getProperty("user.dir");
					}
					File f = new File(path);
					path = f.getCanonicalPath();
					StringBuffer sb = new StringBuffer(path);
					// reappend '*' to canonicalized filename (note that
					// canonicalization may have removed trailing file
					// separator, so we have to check for that, too)
					if (!path.endsWith(File.separator) && removeTrailingFileSep)
						sb.append(File.separator);
					sb.append('*');
					path = sb.toString();
				} else if (path.endsWith(File.separator)) {
					// this is xxxx/x.jar!/ case.....
					path = path.substring(0, path.length() - 1);
					if (path.endsWith("!")) {
						path = path.substring(0, path.length() - 1);
					}
				} else {
					path = new File(path).getCanonicalPath();
				}
				// FIXME: possible convert URL? what is check this in
				// rfc
				locationURL=fileToEncodedURL(new File(path));
				//locationURL = new URL("file", "", path);

				if (extractSignerCerts) {
					parsedCodeSource = new CodeSource(locationURL, getSignerCertificates(cs));
				} else {
					parsedCodeSource = new CodeSource(locationURL, cs.getCertificates());
				}
			} catch (IOException ioe) {
				// leave codesource as it is, unless we have to extract
				// its
				// signer certificates
				if (extractSignerCerts) {
					parsedCodeSource = new CodeSource(cs.getLocation(), getSignerCertificates(cs));
				}
			}

		}

		return parsedCodeSource;
		// CodeSource o = AccessController.doPrivileged(new
		// PerformURLConversionAction(extractSignerCerts,cs));

		// return o;
	}

	public static URL fileToEncodedURL(File file) throws MalformedURLException {
		String path = file.getAbsolutePath();
		//pff, CS has hardcoded "/" checks
		path = path.replace("\\", "/");
		//path = ParseUtil.encodePath(path);
		if (!path.startsWith("/")) {
			path = "/" + path;
		}
//		if (!path.endsWith("/") && file.isDirectory()) {
//			path = path + "/";
//		}
		return new URL("file", "", path);
	}

	private Certificate[] getSignerCertificates(CodeSource cs) {
		// FIXME: fill this once we have certs
		return null;
	}

	// Some methods to expose info about what is goign on.

	public String getCodeSources() {

		List<String> css = new ArrayList<String>();
		for (PolicyHolderEntry phe : this.currentPolicy.get().policyHolderEntries) {
			css.add(phe.getCodeSource().getLocation() == null ? "default" : phe.getCodeSource().getLocation().toString());
		}

		return Arrays.toString(css.toArray());
	}

	public String getPolicyFilesURL() {
		return Arrays.toString(this.currentPolicy.get().loadedFiles.toArray());
	}

}


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

package org.mobicents.slee.resource.cluster;

import org.infinispan.tree.Fqn;
import org.restcomm.cache.FqnWrapper;

import java.io.Serializable;

public class DataRemovalListener<K extends Serializable, V extends Serializable> implements org.restcomm.cluster.DataRemovalListener {

	private final FaultTolerantResourceAdaptor<K, V> ra;
	private final ReplicatedDataCacheData<K, V> baseCacheData;

	/**
	 * @param ra
	 * @param baseCacheData
	 */
	public DataRemovalListener(FaultTolerantResourceAdaptor<K, V> ra,
			ReplicatedDataCacheData<K, V> baseCacheData) {
		this.ra = ra;
		this.baseCacheData = baseCacheData;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.restcomm.cluster.ClientLocalListener#getBaseFqn()
	 */
	@SuppressWarnings("unchecked")
	public FqnWrapper getBaseFqn() {
		return new FqnWrapper(baseCacheData.getNodeFqn());
	}

	/*
	 * (non-Javadoc)
	 * @see org.restcomm.cluster.DataRemovalListener#dataRemoved(org.infinispan.tree.Fqn)
	 */
	@SuppressWarnings("unchecked")
	public void dataRemoved(FqnWrapper fqnWrapper) {
		final Fqn fqn = fqnWrapper.getFqn();
		ra.dataRemoved((K)fqn.getLastElement());
	}

}


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

/*
 * SbbObjectPoolFactory.java
 *
 * Created on June 28, 2004, 2:45 PM
 *
 * The source code contained in this file is in in the public domain.
 * It can be used in any project or product without prior permission,
 * license or royalty payments. There is no claim of correctness and
 * NO WARRANTY OF ANY KIND provided with this code.
 */

package org.mobicents.slee.runtime.sbb;

import java.security.AccessController;
import java.security.PrivilegedAction;

import javax.slee.ServiceID;

import org.apache.commons.pool.PoolableObjectFactory;
import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainerUtils;
import org.mobicents.slee.container.component.sbb.SbbComponent;
import org.mobicents.slee.container.sbb.SbbObject;
import org.mobicents.slee.container.sbb.SbbObjectState;

/**
 * Implements the methods invoked by the object pool to create the SbbEntity
 * Object
 *
 * @author F.Moggia
 * @author Eduardo Martins
 */
public class SbbObjectPoolFactory implements PoolableObjectFactory {

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

	private boolean doTraceLogs = logger.isTraceEnabled();

	private final SbbComponent sbbComponent;
	private final ServiceID serviceID;

    /** Creates a new instance of SbbObjectPoolFactory */
    public SbbObjectPoolFactory(ServiceID serviceID, SbbComponent sbbComponent) {
    	this.serviceID = serviceID;
        this.sbbComponent = sbbComponent;
    }

    public void activateObject(Object obj) throws java.lang.Exception {
        /*
         * NOTE. We must not call sbbActivate in here This is because this
         * method would get called when borrowing an sbbObject in order to do a
         * sbbCreate - in which case it is illegal to call sbbActivat before
         * sbbCreate - Tim
         */

    	if (doTraceLogs) {
        	logger.trace("activateObject() for "+sbbComponent);
        }

    }

    public void destroyObject(Object sbb) throws java.lang.Exception {

    	if (doTraceLogs) {
        	logger.trace("destroyObject() for "+sbbComponent);
        }

        SbbObject sbbObject = (SbbObject) sbb;
        final ClassLoader oldClassLoader = SleeContainerUtils
                .getCurrentThreadClassLoader();

        try {
        	//unsetSbbContext must be called with the context classloader
            //of the entities sbbDescriptor as with other sbb invocatiions.
            Thread.currentThread().setContextClassLoader(sbbComponent.getClassLoader());
            if (sbbObject.getState() != SbbObjectState.DOES_NOT_EXIST) {
                sbbObject.unsetSbbContext();
            }
        } finally {
            if (System.getSecurityManager()!=null)
                AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    public Object run() {
                        Thread.currentThread().setContextClassLoader(
                                oldClassLoader);
                        return null;
                    }
                });
            else
                Thread.currentThread().setContextClassLoader(oldClassLoader);

        }

        sbbObject.setState(SbbObjectState.DOES_NOT_EXIST);

    }

    /**
     * Create a new instance of this object and set the SbbContext This places
     * it into the object pool.
     */
    public Object makeObject() {

        SbbObject retval;
        if (doTraceLogs) {
        	logger.trace("makeObject() for "+serviceID+" and "+sbbComponent);
        }

        final ClassLoader oldClassLoader = SleeContainerUtils
                .getCurrentThreadClassLoader();

        try {
            final ClassLoader cl = sbbComponent.getClassLoader();
            if (System.getSecurityManager()!=null)
                AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    public Object run() {
                        Thread.currentThread().setContextClassLoader(cl);
                        return null;

                    }
                });
            else
                Thread.currentThread().setContextClassLoader(cl);

            retval = new SbbObjectImpl(serviceID,sbbComponent);

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

        retval.setState(SbbObjectState.POOLED);

        return retval;
    }

    public void passivateObject(Object sbb) throws java.lang.Exception {

    	if (doTraceLogs) {
        	logger.trace("passivateObject() for "+sbbComponent);
    	}

        SbbObject sbbObj = (SbbObject) sbb;
        sbbObj.setState(SbbObjectState.POOLED);
    }

    public boolean validateObject(Object sbbo) {

    	boolean retval = ((SbbObject) sbbo).getState() == SbbObjectState.POOLED;

    	if (doTraceLogs) {
        	logger.trace("validateObject() for "+sbbComponent+" returning " + retval);
        }

    	return retval;
    }

}


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

package org.mobicents.slee.container.profile;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.slee.CreateException;
import javax.slee.InvalidArgumentException;
import javax.slee.SLEEException;
import javax.slee.TransactionRequiredLocalException;
import javax.slee.management.ProfileTableNotification;
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.ProfileLocalObject;
import javax.slee.profile.ProfileVerificationException;
import javax.slee.profile.ReadOnlyProfileException;
import javax.slee.profile.UnrecognizedAttributeException;
import javax.slee.profile.UnrecognizedProfileTableNameException;
import javax.slee.profile.UnrecognizedQueryNameException;
import javax.slee.resource.ActivityFlags;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.infinispan.remoting.transport.Address;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.activity.ActivityContext;
import org.mobicents.slee.container.activity.ActivityContextHandle;
import org.mobicents.slee.container.component.profile.ProfileAttribute;
import org.mobicents.slee.container.component.profile.ProfileSpecificationComponent;
import org.mobicents.slee.container.management.ProfileManagementImpl;
import org.mobicents.slee.container.management.TraceManagement;
import org.mobicents.slee.container.management.jmx.ProfileTableUsageMBean;
import org.mobicents.slee.container.profile.entity.ProfileEntity;
import org.mobicents.slee.container.transaction.TransactionalAction;
import org.mobicents.slee.container.util.concurrent.ConcurrentHashSet;
import org.mobicents.slee.runtime.facilities.NotificationSourceWrapperImpl;
import org.mobicents.slee.runtime.facilities.profile.ProfileTableActivityHandleImpl;
import org.mobicents.slee.runtime.facilities.profile.ProfileTableActivityImpl;

/**
 *
 * Start time:11:20:19 2009-03-14

 * Project: restcomm-jainslee-server-core

 *
 *
 * @author  Bartosz Baranowski
 * @author  Alexandre Mendonca
 * @author martins
 */
public class ProfileTableImpl implements ProfileTable, Serializable {

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

	public static final int _UNICODE_RANGE_START = 0x0020;
	public static final int _UNICODE_RANGE_END = 0x007e;
	public static final int _UNICODE_SLASH = 0x002f;

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

	/**
	 *
	 */
	private final ProfileSpecificationComponent component;

	/**
	 *
	 */
	private final String profileTableName;

	/**
	 *
	 */
	private final ProfileManagementImpl profileManagement;
	private final SleeContainer sleeContainer;

	/**
	 *
	 */
	private NotificationSourceWrapperImpl profileTableNotification = null;

	/**
	 *
	 */
	private ProfileTableUsageMBean profileTableUsageMBean = null;

	/**
	 * indicates if this table fires events
	 */
	private final boolean fireEvents;

	/**
	 *
	 */
	private final ProfileTableTransactionView transactionView;

	/**
	 * the entity with the default profile attribute values
	 */
	private ProfileEntity defaultProfileEntity;

	/**
	 *
	 * @param profileTableName
	 * @param component
	 * @param sleeContainer
	 */
	public ProfileTableImpl(final String profileTableName, ProfileSpecificationComponent component, ProfileManagementImpl profileManagement) {

		ProfileTableImpl.validateProfileTableName(profileTableName);
		if (profileManagement == null || component == null) {
			throw new NullPointerException();
		}

		this.component = component;
		this.profileManagement = profileManagement;
		this.sleeContainer = profileManagement.getSleeContainer();

		this.profileTableName = profileTableName;

		this.profileTableNotification = new NotificationSourceWrapperImpl(
				new ProfileTableNotification(this.profileTableName));

		this.fireEvents = component.getDescriptor().getEventsEnabled();
		this.transactionView = new ProfileTableTransactionView(this);
	}

	private boolean traceRegistred = false;

	public void registerTracer() {

		if (!traceRegistred) {
			// register tracer
			final TraceManagement traceMBeanImpl = sleeContainer.getTraceManagement();
			traceMBeanImpl.registerNotificationSource(new ProfileTableNotification(profileTableName));
			TransactionalAction action2 = new TransactionalAction() {
				public void execute() {
					// remove notification sources for profile table
					traceMBeanImpl.deregisterNotificationSource(new ProfileTableNotification(profileTableName));
				}
			};
			sleeContainer.getTransactionManager().getTransactionContext().getAfterRollbackActions().add(action2);
			traceRegistred = true;
		}

	}

	/**
	 *
	 * @return
	 */
	public SleeContainer getSleeContainer() {
		return sleeContainer;
	}

	/**
	 * @return the profileManagement
	 */
	public ProfileManagementImpl getProfileManagement() {
		return profileManagement;
	}

	/**
	 *
	 * @return
	 */
	public boolean doesFireEvents() {
		return fireEvents;
	}

	/**
	 *
	 * @return
	 */
	public String getProfileTableName() {
		return this.profileTableName;
	}

	/**
	 *
	 * @return
	 */
	public ProfileSpecificationComponent getProfileSpecificationComponent() {
		return component;
	}

	/**
	 *
	 * @return
	 */
	public NotificationSourceWrapperImpl getProfileTableNotification() {
		return this.profileTableNotification;
	}

	/**
	 *
	 * @return
	 */
	public ProfileTableUsageMBean getProfileTableUsageMBean() {
		return profileTableUsageMBean;
	}

	/**
	 *
	 * @return
	 */
	public Collection<ProfileID> getProfiles() {
		List<ProfileID> result = new ArrayList<ProfileID>();
		for (ProfileEntity profileEntity : component.getProfileEntityFramework().findAll(this.getProfileTableName())) {
			result.add(new ProfileID(profileTableName,profileEntity.getProfileName()));
		}
		return Collections.unmodifiableCollection(result);
	}

	/**
	 *
	 * @throws ReadOnlyProfileException
	 */
	private void checkProfileSpecIsNotReadOnly() throws ReadOnlyProfileException {
		if (component.getDescriptor().getReadOnly()) {
			throw new ReadOnlyProfileException(component.toString());
		}
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.profile.ProfileTable#create(java.lang.String)
	 */
	public ProfileLocalObject create(String profileName)
			throws NullPointerException, IllegalArgumentException,
			TransactionRequiredLocalException, ReadOnlyProfileException,
			ProfileAlreadyExistsException, CreateException, SLEEException {

		sleeContainer.getTransactionManager().mandateTransaction();

		checkProfileSpecIsNotReadOnly();
		ProfileObjectImpl profileObject = createProfile(profileName);
		profileObject.profilePersist();
		return profileObject.getProfileLocalObject();
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.profile.ProfileTable#find(java.lang.String)
	 */
	public ProfileLocalObject find(String profileName)
			throws NullPointerException, TransactionRequiredLocalException,
			SLEEException {

		if (profileName == null) {
			throw new NullPointerException();
		}

		ProfileObjectImpl profileObject = getProfile(profileName);
		return profileObject == null ? null : profileObject.getProfileLocalObject();
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.profile.ProfileTable#findAll()
	 */
	public Collection<ProfileLocalObject> findAll() throws TransactionRequiredLocalException,
			SLEEException {

		sleeContainer.getTransactionManager().mandateTransaction();

		Collection<ProfileLocalObject> result = new ArrayList<ProfileLocalObject>();
		for (ProfileEntity profileEntity : component.getProfileEntityFramework().findAll(this.getProfileTableName())) {
			result.add(transactionView.getProfile(profileEntity).getProfileLocalObject());
		}
		return Collections.unmodifiableCollection(result);
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.profile.ProfileTable#remove(java.lang.String)
	 */
	public boolean remove(String profileName) throws NullPointerException,
			ReadOnlyProfileException, TransactionRequiredLocalException,
			SLEEException {

		if (profileName == null) {
			throw new NullPointerException("Profile name must not be null");
		}

		checkProfileSpecIsNotReadOnly();

		return this.removeProfile(profileName,true,false);
	}

	/**
	 *
	 * @param profileName
	 * @param invokeConcreteSbb
	 * @return
	 * @throws TransactionRequiredLocalException
	 * @throws SLEEException
	 */
	public boolean removeProfile(String profileName, boolean invokeConcreteSbb, boolean isUninstall)
			throws TransactionRequiredLocalException, SLEEException {

		if (logger.isDebugEnabled()) {
			logger.debug("[remove] on: " + this + " Profile[" + profileName
					+ "]");
		}

		ProfileObjectImpl profileObject = getProfile(profileName);
		if (profileObject != null) {
			// remove using object
			profileObject.profileRemove(invokeConcreteSbb, isUninstall);
			// close mbean if exists
			AbstractProfileMBeanImpl.close(profileTableName,profileName);
			return true;
		}
		else {
			return false;
		}

	}

	/**
	 *
	 * @param profileName
	 * @throws IllegalArgumentException
	 * @throws NullPointerException
	 */
	public static void validateProfileName(String profileName)
			throws IllegalArgumentException, NullPointerException {
		if (profileName == null) {
			throw new NullPointerException("ProfileName must not be null");
		}
		if (profileName.length() == 0) {
			throw new IllegalArgumentException(
					"Profile name must not be empty, see section 10.2.4 of JSLEE 1.1 specs");
		}

		for (int i = 0; i < profileName.length(); i++) {
			Character c = profileName.charAt(i);
			if (!(Character.isLetterOrDigit(c.charValue()) || (_UNICODE_RANGE_START <= c && c <= _UNICODE_RANGE_END))) {
				throw new IllegalArgumentException(
						"Profile name contains illegal character, name: "
								+ profileName + ", at index: " + i);
			}
		}
	}

	/**
	 *
	 * @param profileTableName
	 * @throws IllegalArgumentException
	 * @throws NullPointerException
	 */
	public static void validateProfileTableName(String profileTableName)
			throws IllegalArgumentException, NullPointerException {
		if (profileTableName == null) {
			throw new NullPointerException("ProfileTableName must not be null");
		}
		if (profileTableName.length() == 0) {
			throw new IllegalArgumentException(
					"ProfileTableName must not be empty, see section 10.2.4 of JSLEE 1.1 specs");
		}

		for (int i = 0; i < profileTableName.length(); i++) {
			Character c = profileTableName.charAt(i);
			if (!((Character.isLetterOrDigit(c.charValue()) || (_UNICODE_RANGE_START <= c && c <= _UNICODE_RANGE_END)) && c != _UNICODE_SLASH)) {
				throw new IllegalArgumentException(
						"ProfileTableName contains illegal character, name: "
								+ profileTableName + ", at index: " + i);
			}
		}
	}

	/**
	 *
	 * @return
	 */
	public ProfileEntity getDefaultProfileEntity() {
		return defaultProfileEntity;
	}

	/**
	 *
	 * @throws CreateException
	 * @throws ProfileVerificationException
	 */
	public void createDefaultProfile() throws CreateException, ProfileVerificationException {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating default profile for table "+profileTableName);
		}
		ProfileObjectImpl profileObject = transactionView.createProfile(null);
		profileObject.profileVerify();
		this.defaultProfileEntity = profileObject.getProfileEntity();
	}

	public ProfileObjectImpl createProfile(String newProfileName)
			throws TransactionRequiredLocalException, NullPointerException,
			SLEEException,
			ProfileAlreadyExistsException, CreateException {

		if (logger.isDebugEnabled()) {
			logger.debug("Adding profile with name " + newProfileName + " on table with name "
					+ newProfileName);
		}

		validateProfileName(newProfileName);

		// switch the context classloader to the component cl
		ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();

		try {

			Thread.currentThread().setContextClassLoader(
					component.getClassLoader());

			if (profileExists(newProfileName)) {
				throw new ProfileAlreadyExistsException("Profile with name '"
						+ newProfileName + "' already exists in table '"
						+ this.getProfileTableName() + "'");
			}

			/*
			 * FIXME afaik the default profile doesn't count, let it be till a test fails
			if (component.getDescriptor().isSingleProfile()) {
				throw new SLEEException(
						"Profile Specification indicates that this is single profile, can not create more than one: "
								+ component);
			}
			*/

			return transactionView.createProfile(newProfileName);
		} catch (IllegalArgumentException e) {
			throw new SLEEException(e.getMessage(), e);
		} finally {
			Thread.currentThread().setContextClassLoader(oldClassLoader);
		}

	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.profile.ProfileTable#findProfileByAttribute(java.lang.String, java.lang.Object)
	 */
	public ProfileLocalObject findProfileByAttribute(String attributeName,
			Object attributeValue) throws NullPointerException,
			IllegalArgumentException, TransactionRequiredLocalException,
			SLEEException {

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

		Collection<ProfileLocalObject> plocs = findProfilesByAttribute(attributeName, attributeValue);
	    if(plocs.size() == 0) {
	    	return null;
	    }
	    else {
	    	return plocs.iterator().next();
	    }
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.profile.ProfileTable#findProfilesByAttribute(java.lang.String, java.lang.Object)
	 */
	public Collection<ProfileLocalObject> findProfilesByAttribute(String attributeName,
			Object attributeValue) throws NullPointerException,
			IllegalArgumentException, TransactionRequiredLocalException,
			SLEEException {

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

		sleeContainer.getTransactionManager().mandateTransaction();

		// We get profile entities
		Collection<ProfileEntity> profileEntities = null;
		try {
			profileEntities = getProfileEntitiesByAttribute(attributeName, attributeValue, true);
		}
		catch (AttributeNotIndexedException e) {
			throw new SLEEException(e.getMessage(),e);
		} catch (UnrecognizedAttributeException e) {
			throw new IllegalArgumentException(e);
		} catch (AttributeTypeMismatchException e) {
			throw new IllegalArgumentException(e);
		}

		// We need ProfileLocalObjects
       ArrayList<ProfileLocalObject> plocs = new ArrayList<ProfileLocalObject>();
       for(ProfileEntity profileEntity : profileEntities) {
    	   plocs.add(transactionView.getProfile(profileEntity).getProfileLocalObject());
      }
      return Collections.unmodifiableCollection(plocs);
	}

	/*
	 *
	 */
	public Collection<ProfileID> getProfilesByAttribute(
			String attributeName, Object attributeValue, boolean isSlee11)
			throws UnrecognizedAttributeException,
			AttributeNotIndexedException, AttributeTypeMismatchException,
			SLEEException {

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

		// We get profile entities
		Collection<ProfileEntity> profileEntities = getProfileEntitiesByAttribute(attributeName, attributeValue, isSlee11);

		// We need ProfileIDs
		Collection<ProfileID> profileIDs = new ArrayList<ProfileID>();
		for(ProfileEntity profileEntity : profileEntities) {
			profileIDs.add( new ProfileID(profileEntity.getTableName(), profileEntity.getProfileName()) );
		}

		return Collections.unmodifiableCollection( profileIDs );
	}

	/**
	 * Retrieves the {@link ProfileEntity}s from the persistent store, matching specified attribute name and value type
	 * @param attributeName
	 * @param attributeValue
	 * @param isSlee11
	 * @return
	 * @throws UnrecognizedAttributeException
	 * @throws AttributeNotIndexedException
	 * @throws AttributeTypeMismatchException
	 * @throws SLEEException
	 */
	private Collection<ProfileEntity> getProfileEntitiesByAttribute(
			String attributeName, Object attributeValue, boolean isSlee11)
			throws UnrecognizedAttributeException,
			AttributeNotIndexedException, AttributeTypeMismatchException,
			SLEEException {

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

		ProfileAttribute profileAttribute = getProfileAttribute(attributeName, attributeValue);

		if (isSlee11)  {
			// validate attr value type
			if (!ProfileTableImpl.PROFILE_ATTR_ALLOWED_TYPES.contains(attributeValue.getClass().getName())) {
				throw new AttributeTypeMismatchException(attributeValue.getClass()+" is not a valid profile attribute value type");
			}
		}
		else {
			if (!profileAttribute.isIndex()) {
				throw new AttributeNotIndexedException(component.toString()+" defines an attribute named "+attributeName+" but not indexed");
			}
		}

		return component.getProfileEntityFramework().findProfilesByAttribute(this.getProfileTableName(), profileAttribute, attributeValue);
	}

	/**
	 * Retrieves the {@link ProfileAttribute} from the component, matching specified attribute name and value type
	 * @param attributeName
	 * @param attributeValue
	 * @return
	 * @throws NullPointerException
	 * @throws UnrecognizedAttributeException
	 * @throws AttributeTypeMismatchException
	 */
	private ProfileAttribute getProfileAttribute(String attributeName,
			Object attributeValue) throws NullPointerException, UnrecognizedAttributeException,
			AttributeTypeMismatchException {

		if (attributeName == null) {
			throw new NullPointerException("attribute name is null");
		}
		if (attributeValue == null) {
			throw new NullPointerException("attribute value is null");
		}

		ProfileAttribute profileAttribute = component.getProfileAttributes().get(attributeName);
		if (profileAttribute == null) {
			throw new UnrecognizedAttributeException(component.toString()+" does not defines an attribute named "+attributeName);
		}
		else {
			Class<?> allowedProfileAttributeType = profileAttribute.getNonPrimitiveType().isArray() ? profileAttribute.getNonPrimitiveType().getComponentType() : profileAttribute.getNonPrimitiveType() ;
			if (!allowedProfileAttributeType.getName().equals(attributeValue.getClass().getName())) {
				throw new AttributeTypeMismatchException(component.toString()+" defines an attribute named "+attributeName+" with value type "+profileAttribute.getType()+", the specified value is of type "+attributeValue.getClass());
			}
			else {
				return profileAttribute;
			}
		}
	}

	/**
	 * Determines if profile is in back end storage == visible to other
	 * compoenents than MBean, if null is passed as argumetn it must check for
	 * any other than defualt?
	 */
	public boolean profileExists(String profileName) {

		boolean result = component.getProfileEntityFramework().findProfile(this.getProfileTableName(), profileName) != null;

		if (logger.isDebugEnabled()) {
			logger.debug("Profile named "+profileName+(result ? "" : " does not")+" exists on table named " + this.getProfileTableName());
		}

		return result;
	}
	/**
	 * This method renames Profile Table in backend storage. NOTE: It should not be called directly, use SleeProfileTableManager instead!
	 * @param newProfileTableName
	 */
	public void rename(String newProfileTableName) {
		//we have to do this like that cause once JPA is done, those profiles wont exist, since we do UPDATE of a table name, not a copy
		//thus no profiles will be returned on this call later on. ouch :)
	  Collection<ProfileID> profileIDs = this.getProfiles();
	  component.getProfileEntityFramework().renameProfileTable(this.profileTableName, newProfileTableName);
	  //here we remove beans.
	  for(ProfileID pid: profileIDs)
	  {
		  try{
			AbstractProfileMBeanImpl.close(pid.getProfileTableName(), pid.getProfileName());
		  }catch(Exception e)
		  {
			 if(logger.isEnabledFor(Level.WARN))
			 {
				 logger.warn("Unexpected behaviour on MBean deregistration.", e);
			 }
		  }
	  }

	}

	/**
	 * Triggers remove operation on this profile table.
	 *
	 * @throws UnrecognizedProfileTableNameException
	 */
	public void remove(boolean isUninstall) throws SLEEException {

		if (logger.isTraceEnabled()) {
			logger.trace("removeProfileTable: removing profileTable="
					+ profileTableName);
		}

		// remove the table profiles, at this stage they may use notification source, lets leave it.
		for (ProfileID profileID : getProfiles()) {
			// don't invoke the profile concrete object, to avoid evil profile lifecycle impls
			// that rollbacks tx, as Test1110251Test
			this.removeProfile(profileID.getProfileName(), false, isUninstall);
		}

		// remove default profile
		if (getDefaultProfileEntity() != null) {
			this.removeProfile(null, false, false);
		}

		// add action after commit to remove tracer and close uncommitted mbeans
		TransactionalAction commitAction = new TransactionalAction() {
			public void execute() {
				// remove notification sources for profile table
				final TraceManagement traceMBeanImpl = sleeContainer.getTraceManagement();
				traceMBeanImpl.deregisterNotificationSource(new ProfileTableNotification(profileTableName));
				// close uncommitted mbeans
				closeUncommittedProfileMBeans();
			}
		};
		sleeContainer.getTransactionManager().getTransactionContext().getAfterCommitActions().add(commitAction);

		if (sleeContainer.getSleeState() == SleeState.RUNNING) {
			endActivity();
		}

		// unregister mbean
		unregisterUsageMBean();

		// remove object pool
		profileManagement.getObjectPoolManagement().removeObjectPool(this, sleeContainer.getTransactionManager());

	}

	/**
	 *
	 * @param profileName
	 * @return
	 * @throws TransactionRequiredLocalException
	 * @throws SLEEException
	 */
	public ProfileObjectImpl getProfile(String profileName)
			throws TransactionRequiredLocalException, SLEEException {

		return transactionView.getProfile(profileName);
	}

	/**
	 * Use this method (and the object it returns) very carefully, if the profile entity is not from the current
	 * transaction and changes are done, those won't be persisted
	 *
	 * @param profileEntity
	 * @return
	 * @throws TransactionRequiredLocalException
	 * @throws SLEEException
	 */
	public ProfileObject getProfile(ProfileEntity profileEntity)
		throws TransactionRequiredLocalException, SLEEException {
		return transactionView.getProfile(profileEntity);
	}

	public String toString() {
		return " ProfileTableImpl ( table = "
				+ this.profileTableName + " , component ="
				+ component + " )";
	}

	/**
	 *
	 * @param queryName
	 * @param arguments
	 * @return
	 * @throws InvalidArgumentException
	 * @throws AttributeTypeMismatchException
	 * @throws UnrecognizedQueryNameException
	 * @throws SLEEException
	 * @throws NullPointerException
	 */
	public Collection<ProfileLocalObject> getProfilesByStaticQuery(String queryName, Object[] arguments) throws NullPointerException, SLEEException, UnrecognizedQueryNameException, AttributeTypeMismatchException, InvalidArgumentException {

		sleeContainer.getTransactionManager().mandateTransaction();

		Collection<ProfileLocalObject> plocs = new ArrayList<ProfileLocalObject>();

		for(ProfileEntity profileEntity : component.getProfileEntityFramework().getProfilesByStaticQuery( this.getProfileTableName(), queryName, arguments )) {
			plocs.add(transactionView.getProfile(profileEntity).getProfileLocalObject());
		}

		return Collections.unmodifiableCollection(plocs);
	}

	// ACTIVITY related

	ProfileTableActivityImpl profileTableActivity = null;

	/**
	 *
	 */
	public ProfileTableActivityImpl getActivity() {
		if (profileTableActivity == null) {
			Address clusterLocalAddress = null;
			if (!profileManagement.getJPAConfiguration().isClusteredProfiles()) {
				// special scenario, we may run in a cluster but without clustered
				// profiles, so the activity must be unique for each cluster node
				clusterLocalAddress = sleeContainer.getCluster().getLocalAddress();
			}
			profileTableActivity = new ProfileTableActivityImpl(new ProfileTableActivityHandleImpl(this.profileTableName, clusterLocalAddress));
		}
		return profileTableActivity;
	}

	/**
	 *
	 */
	public ActivityContextHandle getActivityContextHandle() {
		return new ProfileTableActivityContextHandle(getActivity().getHandle());
	}

	/**
	 *
	 * @return
	 */
	public ActivityContext getActivityContext() {
		return sleeContainer.getActivityContextFactory().getActivityContext(getActivityContextHandle());
	}

	/**
	 *
	 */
	public void startActivity() {
		sleeContainer.getActivityContextFactory().createActivityContext(getActivityContextHandle(),ActivityFlags.NO_FLAGS);
	}

	/**
	 *
	 */
	public void endActivity() {
		ActivityContext ac = getActivityContext();
		if (ac != null) {
			ac.endActivity();
		}
	}

	// USAGE MBEAN RELATED

	/**
	 *
	 */
	public void registerUsageMBean() {
		if (component.getUsageParametersInterface() != null) {
			// create resource usage mbean
			try {
				this.profileTableUsageMBean = sleeContainer.getUsageParametersManagement().newProfileTableUsageMBean(profileTableName, component);
			} catch (Throwable t) {
				if (this.profileTableUsageMBean != null) {
					this.profileTableUsageMBean.remove();
				}
				throw new SLEEException(
						"Failed to create and register Table Usage MBean", t);
			}
		}
	}

	/**
	 *
	 */
	public void unregisterUsageMBean() {
		if (this.profileTableUsageMBean != null) {
			try {
				this.profileTableUsageMBean.remove();
			}
			catch (Throwable e) {
				throw new SLEEException(e.getMessage(),e);
			}
		}
	}

	// OPEN PROFILE MBEANS FOR PROFILES NOT CREATED

	/**
	 *
	 */
	private final Set<AbstractProfileMBean> uncommittedProfileMBeans = new ConcurrentHashSet<AbstractProfileMBean>();

	/**
	 *
	 * @param profileMBean
	 */
	public void addUncommittedProfileMBean(AbstractProfileMBean profileMBean) {
		uncommittedProfileMBeans.add(profileMBean);
	}

	/**
	 *
	 * @param profileMBean
	 */
	public void removeUncommittedProfileMBean(AbstractProfileMBean profileMBean) {
		uncommittedProfileMBeans.remove(profileMBean);
	}

	/**
	 *
	 */
	private void closeUncommittedProfileMBeans() {
		// run it in a new thread to ensure no nested transactions
		Runnable r = new Runnable() {
			public void run() {
				for (AbstractProfileMBean profileMBean : uncommittedProfileMBeans) {
					if (logger.isDebugEnabled()) {
						logger.debug("Closing uncommitted mbean "+profileMBean);
					}
					// just rollback the profile creation, since in that use case there is a rollback action to unregister the bean
					try {
						profileMBean.restoreProfile();
					} catch (Throwable e) {
						logger.error(e.getMessage(),e);
					}
				}
			}
		};
		new Thread(r).start();

	}

	public void setDefaultProfileEntity(ProfileEntity profileEntity) {
		this.defaultProfileEntity = profileEntity;

	}

	private static final Set<String> PROFILE_ATTR_ALLOWED_TYPES = getAllowedTypes();

	private static final Set<String> getAllowedTypes() {
		Set<String> tmp = new HashSet<String>();
		for (String type : ProfileAttribute.PRIMITIVE_ALLOWED_PROFILE_ATTRIBUTE_TYPES) {
			tmp.add(type);
		}
		for (String type : ProfileAttribute.NON_PRIMITIVE_ALLOWED_PROFILE_ATTRIBUTE_TYPES) {
			tmp.add(type);
		}
		return Collections.unmodifiableSet(tmp);
	}
}


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

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

 * Project: restcomm-jainslee-server-core

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

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.slee.ComponentID;
import javax.slee.EventTypeID;
import javax.slee.InitialEventSelector;
import javax.slee.SbbID;
import javax.slee.facilities.AlarmFacility;
import javax.slee.management.ComponentDescriptor;
import javax.slee.management.DependencyException;
import javax.slee.management.DeploymentException;
import javax.slee.management.LibraryID;
import javax.slee.profile.ProfileSpecificationID;
import javax.slee.resource.ResourceAdaptorTypeID;

import org.mobicents.slee.container.component.UsageParameterDescriptor;
import org.mobicents.slee.container.component.common.EnvEntryDescriptor;
import org.mobicents.slee.container.component.common.ProfileSpecRefDescriptor;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.SbbDescriptorImpl;
import org.mobicents.slee.container.component.sbb.AbstractSbbClassInfo;
import org.mobicents.slee.container.component.sbb.AbstractSbbClassInfoImpl;
import org.mobicents.slee.container.component.sbb.EventEntryDescriptor;
import org.mobicents.slee.container.component.sbb.ResourceAdaptorEntityBindingDescriptor;
import org.mobicents.slee.container.component.sbb.ResourceAdaptorTypeBindingDescriptor;
import org.mobicents.slee.container.component.sbb.SbbRefDescriptor;
import org.mobicents.slee.container.component.security.PermissionHolderImpl;
import org.mobicents.slee.container.component.validator.SbbComponentValidator;

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

 * Project: restcomm-jainslee-server-core

 *
 * @author baranowb - Bartosz Baranowski
 *
 * @author  Alexandre Mendonca
 */
public class SbbComponentImpl extends AbstractSleeComponentWithUsageParametersInterface implements org.mobicents.slee.container.component.sbb.SbbComponent {

	/**
	 * the sbb descriptor
	 */
	private final SbbDescriptorImpl descriptor;

	/**
	 * the sbb abstract class
	 */
	private Class<?> abstractSbbClass;

	/**
	 * the concrete sbb class, generated by SLEE
	 */
	private Class<?> concreteSbbClass;

	/**
	 * the sbb local interface
	 */
	private Class<?> sbbLocalInterfaceClass;

	/**
	 * the concrete sbb local interface class, generated by SLEE
	 */
	private Class<?> sbbLocalInterfaceConcreteClass;

	/**
	 * the sbb own activity context interface
	 */
	private Class<?> activityContextInterface;

	/**
	 * the concrete sbb own activity context interface class, generated by SLEE
	 */
	private Class<?> activityContextInterfaceConcreteClass;

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

	/**
	 * the event handler methods for this sbb component
	 */
	private Map<EventTypeID, EventHandlerMethod> eventHandlerMethods = null;

	/**
	 * the event handler methods for this sbb component
	 */
	private Map<String, Method> initialEventSelectorMethods = null;

	/**
	 * info about the abstract sbb class
	 */
	private final AbstractSbbClassInfo abstractSbbClassInfo = new AbstractSbbClassInfoImpl();

	/**
	 * flag whihc indicates if the sbb is allowed to be reentrant
	 */
	private final boolean reentrant;

	/**
	 * the alarm facility for the sbb component
	 */
	private AlarmFacility alarmFacility;

	/**
	 *
	 * @param descriptor
	 */
	public SbbComponentImpl(SbbDescriptorImpl descriptor) {
		this.descriptor = descriptor;
		isolateSecurityPermissionsInLocalInterface = descriptor.getSbbLocalInterface()==null ? false : descriptor.getSbbLocalInterface().isIsolateSecurityPermissions();
		reentrant = descriptor.getSbbAbstractClass().isReentrant();
	}

	/**
	 * Retrieves the sbb descriptor
	 *
	 * @return
	 */
	public SbbDescriptorImpl getDescriptor() {
		return descriptor;
	}

	/**
	 * Retrieves the sbb id
	 *
	 * @return
	 */
	public SbbID getSbbID() {
		return descriptor.getSbbID();
	}

	/**
	 * Retrieves the EnvEntryDescriptor
	 *
	 * @return
	 */

	public List<EnvEntryDescriptor> getEnvEntries() {
		return descriptor.getEnvEntries();
	}

	/**
	 * Retrieves the sbb abstract class
	 *
	 * @return
	 */
	public Class<?> getAbstractSbbClass() {
		return abstractSbbClass;
	}

	/**
	 * Retrieves the concrete sbb class, generated by SLEE
	 *
	 * @return
	 */
	public Class<?> getConcreteSbbClass() {
		return concreteSbbClass;
	}

	/**
	 * This must never return null, if no custom interface is defined, this has
	 * to return generic javax.slee.SbbLocalObject FIXME emmartins: this should
	 * return null, since in runtime it will avoid some instanceof for sure
	 *
	 * @return
	 */
	public Class<?> getSbbLocalInterfaceClass() {
		return sbbLocalInterfaceClass;
	}

	/**
	 * Retrieves the concrete sbb local interface class, generated by SLEE
	 *
	 * @return
	 */
	public Class<?> getSbbLocalInterfaceConcreteClass() {
		return sbbLocalInterfaceConcreteClass;
	}

	/**
	 * Retrieves the sbb own activity context interface
	 *
	 * @return
	 */
	public Class<?> getActivityContextInterface() {
		return activityContextInterface;
	}

	/**
	 * Retrieves the concrete sbb own activity context interface class,
	 * generated by SLEE
	 *
	 * @return
	 */
	public Class<?> getActivityContextInterfaceConcreteClass() {
		return activityContextInterfaceConcreteClass;
	}

	/**
	 * Sets the sbb abstract class
	 *
	 * @param abstractSbbClass
	 */
	public void setAbstractSbbClass(Class<?> abstractSbbClass) {
		this.abstractSbbClass = abstractSbbClass;
	}

	/**
	 * Sets the concrete sbb class, generated by SLEE
	 *
	 * @param concreteSbbClass
	 */
	public void setConcreteSbbClass(Class<?> concreteSbbClass) {
		this.concreteSbbClass = concreteSbbClass;
		// build the map of event handler methods, and IES methods, this actualy can be done in one step but its clearer that way, isnt it ?
		buildEventHandlerRefs();
		buildInitialEventSelectorRefs();
	}

	/**
	 * Sets the sbb local interface
	 *
	 * @param sbbLocalInterfaceClass
	 */
	public void setSbbLocalInterfaceClass(Class<?> sbbLocalInterfaceClass) {
		this.sbbLocalInterfaceClass = sbbLocalInterfaceClass;
	}

	/**
	 * Sets the concrete sbb local interface class, generated by SLEE
	 *
	 * @param sbbLocalInterfaceConcreteClass
	 */
	public void setSbbLocalInterfaceConcreteClass(Class<?> sbbLocalInterfaceConcreteClass) {
		this.sbbLocalInterfaceConcreteClass = sbbLocalInterfaceConcreteClass;
	}

	/**
	 * Sets the sbb own activity context interface
	 *
	 * @param activityContextInterface
	 */
	public void setActivityContextInterface(Class<?> activityContextInterface) {
		this.activityContextInterface = activityContextInterface;
	}

	/**
	 * Sets the concrete sbb own activity context interface class, generated by
	 * SLEE
	 *
	 * @param activityContextInterfaceConcreteClass
	 */
	public void setActivityContextInterfaceConcreteClass(Class<?> activityContextInterfaceConcreteClass) {
		this.activityContextInterfaceConcreteClass = activityContextInterfaceConcreteClass;
	}

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

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

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

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

	@Override
	public boolean validate() throws DependencyException, DeploymentException {
		SbbComponentValidator validator = new SbbComponentValidator();
		validator.setComponent(this);
		validator.setComponentRepository(getDeployableUnit().getDeployableUnitRepository());
		return validator.validate();
	}

	/**
	 * Retrieves the JAIN SLEE specs descriptor
	 *
	 * @return
	 */
	public javax.slee.management.SbbDescriptor getSpecsDescriptor() {
		if (specsDescriptor == null) {

			final LibraryID[] libraryIDs = descriptor.getLibraryRefs().toArray(new LibraryID[descriptor.getLibraryRefs().size()]);

			Set<SbbID> sbbIDSet = new HashSet<SbbID>();
			for (SbbRefDescriptor mSbbRef : descriptor.getSbbRefs()) {
				sbbIDSet.add(mSbbRef.getComponentID());
			}
			SbbID[] sbbIDs = sbbIDSet.toArray(new SbbID[sbbIDSet.size()]);

			Set<ProfileSpecificationID> profileSpecSet = new HashSet<ProfileSpecificationID>();
			for (ProfileSpecRefDescriptor mProfileSpecRef : descriptor.getProfileSpecRefs()) {
				profileSpecSet.add(mProfileSpecRef.getComponentID());
			}
			ProfileSpecificationID[] profileSpecs = profileSpecSet.toArray(new ProfileSpecificationID[profileSpecSet.size()]);

			Set<EventTypeID> eventTypeSet = new HashSet<EventTypeID>();
			for (EventEntryDescriptor mEventEntry : descriptor.getEventEntries().values()) {
				eventTypeSet.add(mEventEntry.getEventReference());
			}
			EventTypeID[] eventTypes = eventTypeSet.toArray(new EventTypeID[eventTypeSet.size()]);

			Set<ResourceAdaptorTypeID> raTypeIDSet = new HashSet<ResourceAdaptorTypeID>();
			Set<String> raLinksSet = new HashSet<String>();
			for (ResourceAdaptorTypeBindingDescriptor mResourceAdaptorTypeBinding : descriptor.getResourceAdaptorTypeBindings()) {
				raTypeIDSet.add(mResourceAdaptorTypeBinding.getResourceAdaptorTypeRef());
				for (ResourceAdaptorEntityBindingDescriptor mResourceAdaptorEntityBinding : mResourceAdaptorTypeBinding.getResourceAdaptorEntityBinding()) {
					raLinksSet.add(mResourceAdaptorEntityBinding.getResourceAdaptorEntityLink());
				}
			}
			ResourceAdaptorTypeID[] raTypeIDs = raTypeIDSet.toArray(new ResourceAdaptorTypeID[raTypeIDSet.size()]);
			String[] raLinks = raLinksSet.toArray(new String[raLinksSet.size()]);

			specsDescriptor = new javax.slee.management.SbbDescriptor(getSbbID(), getDeployableUnit().getDeployableUnitID(), getDeploymentUnitSource(), libraryIDs, sbbIDs, eventTypes, profileSpecs,
					descriptor.getAddressProfileSpecRef(), raTypeIDs, raLinks);
		}
		return specsDescriptor;
	}

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

	/**
	 * Retrieves the evetn handler methods for this sbb component, mapped by
	 * event type id
	 *
	 * @return
	 */
	public Map<EventTypeID, EventHandlerMethod> getEventHandlerMethods() {
		return eventHandlerMethods;
	}

	/**
	 * Retrieves the evetn handler methods for this sbb component, mapped by
	 * event type id
	 *
	 * @return
	 */
	public Map<String, Method> getInitialEventSelectorMethods() {
		return initialEventSelectorMethods;
	}

	/**
	 *
	 * @return the abstractSbbClassInfo
	 */
	public AbstractSbbClassInfo getAbstractSbbClassInfo() {
		return abstractSbbClassInfo;
	}

	@Override
	public void processSecurityPermissions() throws DeploymentException {
		try {
			if (this.descriptor.getSecurityPermissions() != null) {
				super.permissions.add(new PermissionHolderImpl(super.getDeploymentDir().toURI(), this.descriptor.getSecurityPermissions()));
			}
		} catch (Exception e) {
			throw new DeploymentException("Failed to make permissions usable.", e);
		}
	}

	@Override
	public void undeployed() {
		super.undeployed();
		abstractSbbClass = null;
		activityContextInterface = null;
		activityContextInterfaceConcreteClass = null;
		concreteSbbClass = null;
		if (eventHandlerMethods != null) {
			eventHandlerMethods.clear();
			eventHandlerMethods = null;
		}
		sbbLocalInterfaceClass = null;
		sbbLocalInterfaceConcreteClass = null;
		sbbLocalObjectClassConstructor = null;
		specsDescriptor = null;
	}

	private void buildEventHandlerRefs()
	{
		eventHandlerMethods = new HashMap<EventTypeID, EventHandlerMethod>();
		for (EventEntryDescriptor eventEntry : descriptor.getEventEntries().values()) {
			if (eventEntry.isReceived()) {
				String eventHandlerMethodName = "on" + eventEntry.getEventName();
				for (Method method : concreteSbbClass.getMethods()) {
					if (method.getName().equals(eventHandlerMethodName)) {
						EventHandlerMethod eventHandlerMethod = new EventHandlerMethod(method);
						if (method.getParameterTypes().length == 3) {
							eventHandlerMethod.setHasEventContextParam(true);
						}
						eventHandlerMethods.put(eventEntry.getEventReference(), eventHandlerMethod);
						break;
					}
				}
			}
		}
	}
	private void buildInitialEventSelectorRefs()
	{
		initialEventSelectorMethods = new HashMap<String, Method>();
		Class<?>[] argtypes = new Class[] { InitialEventSelector.class };
		for (EventEntryDescriptor eventEntry : descriptor.getEventEntries().values()) {
			if (eventEntry.isReceived() && eventEntry.isInitialEvent() && eventEntry.getInitialEventSelectorMethod() != null && !this.initialEventSelectorMethods.containsKey(eventEntry.getInitialEventSelectorMethod())) {

				for (Method method : concreteSbbClass.getMethods()) {
					if (method.getName().equals(eventEntry.getInitialEventSelectorMethod()) && Arrays.equals(method.getParameterTypes(),argtypes)) {
						this.initialEventSelectorMethods.put(eventEntry.getInitialEventSelectorMethod(), method);
						break;
					}
				}
			}
		}
	}

	/**
	 * cached value of the isolate security permissions property of the sbb
	 * local interface in the sbb descriptor
	 */
	private final boolean isolateSecurityPermissionsInLocalInterface;

	/**
	 * Provides a shortcut to the value of the isolate security permissions
	 * property of the sbb local interface in the sbb descriptor.
	 *
	 * @return the isolateSecurityPermissionsInLocalInterface
	 */
	public boolean isolateSecurityPermissionsInLocalInterface() {
		return isolateSecurityPermissionsInLocalInterface;
	}

	/**
	 * the constructor for the SLEE generated implementation class of the custom sbb local object interface
	 */
	private Constructor<?> sbbLocalObjectClassConstructor;

	/**
	 * Retrieves the constructor for the SLEE generated implementation class of the custom sbb local object interface.
	 * @return the sbbLocalObjectClassConstructor
	 */
	public Constructor<?> getSbbLocalObjectClassConstructor() {
		return sbbLocalObjectClassConstructor;
	}

	/**
	 * Sets the constructor for the SLEE generated implementation class of the custom sbb local object interface.
	 * @param sbbLocalObjectClassConstructor the sbbLocalObjectClassConstructor to set
	 */
	public void setSbbLocalObjectClassConstructor(
			Constructor<?> sbbLocalObjectClassConstructor) {
		this.sbbLocalObjectClassConstructor = sbbLocalObjectClassConstructor;
	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.container.component.AbstractSleeComponentWithUsageParametersInterface#getUsageParametersList()
	 */
	@Override
	public List<UsageParameterDescriptor> getUsageParametersList() {
		return descriptor.getSbbUsageParametersInterface().getUsageParameter();
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.component.sbb.SbbComponent#isReentrant()
	 */
	public boolean isReentrant() {
		return reentrant;
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.component.sbb.SbbComponent#getAlarmFacility()
	 */
	public AlarmFacility getAlarmFacility() {
		return alarmFacility;
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.component.sbb.SbbComponent#setAlarmFacility(javax.slee.facilities.AlarmFacility)
	 */
	public void setAlarmFacility(AlarmFacility alarmFacility) {
		this.alarmFacility = alarmFacility;
	}
}


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

import javax.slee.SLEEException;
import javax.slee.SbbLocalObject;
import javax.slee.TransactionRequiredLocalException;
import javax.slee.TransactionRolledbackLocalException;
import javax.slee.facilities.TimerID;
import javax.transaction.SystemException;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.activity.ActivityContext;
import org.mobicents.slee.container.activity.ActivityContextInterface;
import org.mobicents.slee.container.activity.ActivityEventQueueManager;
import org.mobicents.slee.container.event.EventContext;
import org.mobicents.slee.container.eventrouter.EventRoutingTask;
import org.mobicents.slee.container.sbbentity.SbbEntity;
import org.mobicents.slee.container.transaction.SleeTransaction;
import org.mobicents.slee.container.transaction.SleeTransactionManager;
import org.mobicents.slee.container.transaction.TransactionContext;
import org.mobicents.slee.container.transaction.TransactionalAction;

/**
 *
 * Activity context interface - default implementation. The Sbb deployer has to
 * imbed an instance of this as a proxy object in each sbb ACI.
 *
 * This is the SLEE wrapper data structure for Activity Contexts. The Sbb gets
 * to access this rather than the activity. The reason this exists is because
 * the activity context can be at a different location than the activity context
 * interface (does not need to be co-located in the same jvm. )
 *
 * @author M. Ranganathan
 * @author Ralf Siedow
 * @author martins
 *
 */
public class ActivityContextInterfaceImpl implements ActivityContextInterface {

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

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

	private boolean doTraceLogs = logger.isTraceEnabled();

	private final ActivityContext activityContext;

	/**
	 * This is allocated by the Slee to wrap an incoming event (activity).
	 *
	 * @param activityContextHandle
	 */
	public ActivityContextInterfaceImpl(ActivityContext activityContext) {
		this.activityContext = activityContext;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.ActivityContextInterface#getActivity()
	 */
	public Object getActivity() throws TransactionRequiredLocalException,
			SLEEException {

		sleeContainer.getTransactionManager().mandateTransaction();

		return activityContext.getActivityContextHandle().getActivityObject();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.ActivityContextInterface#attach(javax.slee.SbbLocalObject)
	 */
	public void attach(SbbLocalObject sbbLocalObject)
			throws NullPointerException, TransactionRequiredLocalException,
			TransactionRolledbackLocalException, SLEEException {

		if (doTraceLogs) {
        	logger.trace("attach( ac = "+activityContext+" , sbbLocalObject = " + sbbLocalObject + " )");
		}

		if (sbbLocalObject == null)
			throw new NullPointerException("null SbbLocalObject !");

		sleeContainer.getTransactionManager().mandateTransaction();

		org.mobicents.slee.container.sbb.SbbLocalObject sbbLocalObjectImpl = (org.mobicents.slee.container.sbb.SbbLocalObject) sbbLocalObject;

		SbbEntity sbbEntity = sbbLocalObjectImpl.getSbbEntity();

		boolean attached = getActivityContext().attachSbbEntity(sbbEntity.getSbbEntityId());

		boolean setRollbackAndThrowException = false;

		if (attached) {
			try {
				if (sbbEntity.isRemoved()) {
					setRollbackAndThrowException = true;
				} else {
					// attach entity from ac
					sbbEntity.afterACAttach(getActivityContext().getActivityContextHandle());
				}
			} catch (Exception e) {
				setRollbackAndThrowException = true;
			}
		}

		if (setRollbackAndThrowException) {
			try {
				sleeContainer.getTransactionManager().setRollbackOnly();
			} catch (SystemException e) {
				logger
						.warn(
								"failed to set rollback flag while asserting valid sbb entity",
								e);
			}
			throw new TransactionRolledbackLocalException(
					"Failed to attach invalid sbb entity. SbbID " + sbbEntity.getSbbEntityId());
		}

		if (attached) {

			//            	JSLEE 1.0 Spec, Section 8.5.8 excerpt:
			//        		The SLEE delivers the event to an SBB entity that stays attached once. The SLEE may deliver the
			//        		event to the same SBB entity more than once if it has been detached and then re -attached.
			final EventRoutingTask routingTask = activityContext.getLocalActivityContext().getCurrentEventRoutingTask();
			EventContext eventContextImpl = routingTask != null ? routingTask.getEventContext() : null;
			if (eventContextImpl != null && eventContextImpl.getSbbEntitiesThatHandledEvent().remove(sbbEntity.getSbbEntityId())) {
				if (doTraceLogs) {
		        	logger.trace("Removed the SBB Entity ["
									+ sbbEntity.getSbbEntityId()
									+ "] from the delivered set of activity context ["
									+ getActivityContext().getActivityContextHandle()
									+ "]. Seems to be a reattachment after detachment in the same event delivery transaction. See JSLEE 1.0 Spec, Section 8.5.8.");
				}
			}
		}

	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.ActivityContextInterface#detach(javax.slee.SbbLocalObject)
	 */
	public void detach(SbbLocalObject sbbLocalObject)
			throws NullPointerException, TransactionRequiredLocalException,
			TransactionRolledbackLocalException, SLEEException {

		if (doTraceLogs) {
        	logger.trace("detach( ac = "+activityContext+" , sbbLocalObject = " + sbbLocalObject + " )");
		}

		if (sbbLocalObject == null)
			throw new NullPointerException("null SbbLocalObject !");

		sleeContainer.getTransactionManager().mandateTransaction();

		org.mobicents.slee.container.sbb.SbbLocalObject sbbLocalObjectImpl = (org.mobicents.slee.container.sbb.SbbLocalObject) sbbLocalObject;

		SbbEntity sbbEntity = sbbLocalObjectImpl.getSbbEntity();

		// detach ac from entity
		final ActivityContext ac = getActivityContext();
		ac.detachSbbEntity(sbbEntity.getSbbEntityId());

		boolean setRollbackAndThrowException = false;
		try {
			if (sbbEntity.isRemoved()) {
				setRollbackAndThrowException = true;
			} else {
				// detach entity from ac
				sbbEntity.afterACDetach(getActivityContext().getActivityContextHandle());
			}
		} catch (Exception e) {
			setRollbackAndThrowException = true;
		}
		if (setRollbackAndThrowException) {
			try {
				sleeContainer.getTransactionManager().setRollbackOnly();
			} catch (SystemException e) {
				logger
						.warn(
								"failed to set rollback flag while asserting valid sbb entity",
								e);
			}
			throw new TransactionRolledbackLocalException(
					"Failed to detach invalid sbb entity. SbbID " + sbbEntity.getSbbEntityId());
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.ActivityContextInterface#isEnding()
	 */
	public boolean isEnding() throws TransactionRequiredLocalException,
			SLEEException {
		sleeContainer.getTransactionManager().mandateTransaction();
		return getActivityContext().isEnding();
	}

	public ActivityContext getActivityContext() {
		return activityContext;
	}

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

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

	/*
	 * (non-Javadoc)
	 * @see javax.slee.ActivityContextInterface#isAttached(javax.slee.SbbLocalObject)
	 */
	public boolean isAttached(SbbLocalObject sbbLocalObject) throws NullPointerException,
			TransactionRequiredLocalException,
			TransactionRolledbackLocalException, SLEEException {

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

		sleeContainer.getTransactionManager().mandateTransaction();

		if (sbbLocalObject instanceof org.mobicents.slee.container.sbb.SbbLocalObject) {
			org.mobicents.slee.container.sbb.SbbLocalObject sbbLocalObjectImpl = (org.mobicents.slee.container.sbb.SbbLocalObject) sbbLocalObject;
			SbbEntity sbbEntity = sbbLocalObjectImpl.getSbbEntity();
			if (sbbEntity != null && !sbbEntity.isRemoved()) {
				return sbbEntity.isAttached(activityContext.getActivityContextHandle());
			}
		}

		try {
			sleeContainer.getTransactionManager().setRollbackOnly();
		} catch (Exception e) {
			throw new SLEEException(e.getMessage(),e);
		}
		throw new TransactionRolledbackLocalException("the sbbLocalObject argument must represent a valid SBB entity");
	}

	private static final String[] EMPTY_STRING_ARRAY = {};
	private static final TimerID[] EMPTY_TIMERID_ARRAY = {};

	// SLEE 1.1 Extensions

	@Override
	public String[] getNamesBound() {
		return activityContext.getNamingBindings().toArray(EMPTY_STRING_ARRAY);
	}

	@Override
	public TimerID[] getTimers() {
		return activityContext.getAttachedTimers().toArray(EMPTY_TIMERID_ARRAY);
	}

	@Override
	public void suspend() throws TransactionRequiredLocalException,
			SLEEException {
		final SleeTransactionManager txManager = sleeContainer
				.getTransactionManager();
		txManager.mandateTransaction();
		try {
			final SleeTransaction tx = txManager.getTransaction();
			final ActivityEventQueueManager aeqm = activityContext
					.getLocalActivityContext().getEventQueueManager();
			aeqm.createBarrier(tx);
			final TransactionalAction action = new TransactionalAction() {
				public void execute() {
					aeqm.removeBarrier(tx);
				}
			};
			final TransactionContext tc = tx.getTransactionContext();
			tc.getAfterCommitActions().add(action);
			tc.getAfterRollbackActions().add(action);
		} 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.management;

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

import javax.slee.management.DeployableUnitID;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.component.ComponentManagementImpl;
import org.mobicents.slee.container.component.deployment.DeployableUnitBuilderImpl;
import org.mobicents.slee.container.component.deployment.DeployableUnitImpl;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.DeployableUnitDescriptorFactoryImpl;
import org.mobicents.slee.container.component.du.DeployableUnit;
import org.mobicents.slee.container.component.du.DeployableUnitManagement;

public class DeployableUnitManagementImpl implements DeployableUnitManagement {

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

	private final ConcurrentHashMap<DeployableUnitID, DeployableUnitImpl> deployableUnits = new ConcurrentHashMap<DeployableUnitID, DeployableUnitImpl>();

	private final DeployableUnitBuilderImpl deployableUnitBuilder;
	private final DeployableUnitDescriptorFactoryImpl deployableUnitDescriptorFactory;

	/**
	 *
	 */
	public DeployableUnitManagementImpl(
			ComponentManagementImpl componentManagement) {
		this.deployableUnitBuilder = new DeployableUnitBuilderImpl(
				componentManagement);
		this.deployableUnitDescriptorFactory = new DeployableUnitDescriptorFactoryImpl();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.core.component.du.DeployableUnitManagement#
	 * addDeployableUnit(org.mobicents.slee.core.component.du.DeployableUnit)
	 */
	public void addDeployableUnit(final DeployableUnit deployableUnit) {

		if (deployableUnit == null)
			throw new NullPointerException("null deployableUnit");

		if (logger.isTraceEnabled()) {
			logger.trace("Adding DU :  "
							+ deployableUnit.getDeployableUnitID());
		}

		deployableUnits.put(deployableUnit.getDeployableUnitID(),
				(DeployableUnitImpl) deployableUnit);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.core.component.du.DeployableUnitManagement#
	 * getDeployableUnitBuilder()
	 */
	public DeployableUnitBuilderImpl getDeployableUnitBuilder() {
		return deployableUnitBuilder;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.core.component.du.DeployableUnitManagement#
	 * getDeployableUnitDescriptorFactory()
	 */
	public DeployableUnitDescriptorFactoryImpl getDeployableUnitDescriptorFactory() {
		return deployableUnitDescriptorFactory;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.core.component.du.DeployableUnitManagement#
	 * getDeployableUnits()
	 */
	public DeployableUnitID[] getDeployableUnits() {
		Set<DeployableUnitID> deployableUnitIDs = deployableUnits.keySet();
		return deployableUnitIDs.toArray(new DeployableUnitID[deployableUnitIDs
				.size()]);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.core.component.du.DeployableUnitManagement#
	 * getDeployableUnit(javax.slee.management.DeployableUnitID)
	 */
	public DeployableUnitImpl getDeployableUnit(
			DeployableUnitID deployableUnitID) {
		return deployableUnits.get(deployableUnitID);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @seeorg.mobicents.slee.core.component.du.DeployableUnitManagement#
	 * removeDeployableUnit(javax.slee.management.DeployableUnitID)
	 */
	public void removeDeployableUnit(DeployableUnitID deployableUnitID) {

		if (logger.isTraceEnabled()) {
			logger.trace("Removing DU with id:  " + deployableUnitID);
		}

		if (deployableUnitID == null)
			throw new NullPointerException("null id");

		deployableUnits.remove(deployableUnitID);

	}

	@Override
	public String toString() {
		return "Deployable Unit Management: " + "\n+-- Deployable Unit IDs: "
				+ deployableUnits.keySet();
	}
}