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

/***************************************************
 *                                                 *
 *  Restcomm: The Open Source VoIP Platform       *
 *                                                 *
 *  Distributable under LGPL license.              *
 *  See terms of license at gnu.org.               *
 *                                                 *
 ***************************************************/

package org.mobicents.slee.runtime.facilities;

import java.util.HashSet;
import java.util.Hashtable;

import javax.slee.ComponentID;
import javax.slee.UnrecognizedComponentException;
import javax.slee.facilities.FacilityException;
import javax.slee.facilities.Level;
import javax.slee.management.ProfileTableNotification;
import javax.slee.management.ResourceAdaptorEntityNotification;
import javax.slee.management.SbbNotification;
import javax.slee.management.SubsystemNotification;
import javax.slee.management.TraceNotification;
import javax.transaction.SystemException;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.facilities.TraceFacility;
import org.mobicents.slee.container.management.jmx.TraceMBeanImpl;
import org.mobicents.slee.container.transaction.TransactionalAction;

/**
 *Implementation of the trace facility.
 *
 *@author M. Ranganathan
 *@author baranowb
 *
 */
public class TraceFacilityImpl implements TraceFacility {

	private Hashtable<ComponentID, MTraceLevel> traceLevelTable;
	private TraceMBeanImpl traceMBeanImpl; // The MBean for this trace facility.
	private HashSet<String> notificationTypes;

	private static Logger log = Logger.getLogger(TraceFacilityImpl.class);

	/*
	 * @return Returns the traceMBeanImpl.
	 */
	public TraceMBeanImpl getTraceMBeanImpl() {
		return traceMBeanImpl;
	}

	@Override
	public String toString() {
		return "Trace Facility Impl : "
			+ "\n+-- Notification Types: "	+ notificationTypes
			+ "\n" + traceMBeanImpl;
	}

	static class MTraceLevel {
		private Level level;
		private int seqno;

		public MTraceLevel(Level level) {
			this.level = level;
		}

		public int getSeqno() {
			return this.seqno++;
		}

		public Level getLevel() {
			return this.level;
		}
	}

	public TraceFacilityImpl(TraceMBeanImpl traceMB) {
		this.notificationTypes = new HashSet<String>();

		this.traceLevelTable = new Hashtable<ComponentID, MTraceLevel>();
		this.traceMBeanImpl = traceMB;

		//FIXME: default:
		this.notificationTypes.add(ResourceAdaptorEntityNotification.TRACE_NOTIFICATION_TYPE);
		this.notificationTypes.add(SbbNotification.TRACE_NOTIFICATION_TYPE);
		this.notificationTypes.add(ProfileTableNotification.TRACE_NOTIFICATION_TYPE);
		//FIXME: ???
		this.notificationTypes.add(SubsystemNotification.TRACE_NOTIFICATION_TYPE);
	}

	public void setTraceLevelOnTransaction(final ComponentID componentId, Level newLevel) throws SystemException {
		MTraceLevel traceLevel = this.traceLevelTable.get(componentId);
		final Level oldLevel = traceLevel == null ? null : traceLevel.level;
		if (traceLevel == null) {
			this.traceLevelTable.put(componentId, new MTraceLevel(newLevel));
		} else {
			traceLevel.level = newLevel;
		}
		// since we are in a tx and this information is not tx aware ad rollback
		// action
		TransactionalAction action = new TransactionalAction() {
			public void execute() {
				if (oldLevel == null) {
					traceLevelTable.remove(componentId);
				} else {
					traceLevelTable.get(componentId).level = oldLevel;
				}
			}
		};
		SleeContainer.lookupFromJndi().getTransactionManager().getTransactionContext().getAfterRollbackActions().add(action);
	}

	public void setTraceLevel(ComponentID componentId, Level newLevel) {
		MTraceLevel traceLevel = this.traceLevelTable.get(componentId);
		if (traceLevel == null) {
			this.traceLevelTable.put(componentId, new MTraceLevel(newLevel));
		} else {
			traceLevel.level = newLevel;
		}
	}

	public void unSetTraceLevel(final ComponentID componentId) throws SystemException {
		final MTraceLevel level = traceLevelTable.remove(componentId);
		if (level != null) {
			// since we are in a tx and this information is not tx aware ad
			// rollback action
			TransactionalAction action = new TransactionalAction() {
				public void execute() {
					traceLevelTable.put(componentId, level);
				}
			};
			SleeContainer.lookupFromJndi().getTransactionManager().getTransactionContext().getAfterRollbackActions().add(action);
		}
	}

	public void checkComponentID(ComponentID componentId) throws UnrecognizedComponentException {
		if (this.traceLevelTable.get(componentId) == null)
			throw new UnrecognizedComponentException(componentId.toString());
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.facilities.TraceFacility#getTraceLevel(javax.slee.ComponentID)
	 */
	public Level getTraceLevel(ComponentID componentId) throws NullPointerException, UnrecognizedComponentException, FacilityException {
		checkComponentID(componentId);
		return this.traceLevelTable.get(componentId).getLevel();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.facilities.TraceFacility#createTrace(javax.slee.ComponentID,
	 * javax.slee.facilities.Level, java.lang.String, java.lang.String, long)
	 */
	public void createTrace(ComponentID componentId, Level level, String messageType, String message, long timeStamp) throws NullPointerException, IllegalArgumentException,
			UnrecognizedComponentException, FacilityException {
		if (log.isDebugEnabled()) {
			log.debug("createTrace: " + componentId + " level = " + level + " messageType " + messageType + " message " + message + " timeStamp " + timeStamp);
		}
		checkComponentID(componentId);
		MTraceLevel tl = this.traceLevelTable.get(componentId);
		this.notificationTypes.add(messageType);
		if (tl == null)
			throw new UnrecognizedComponentException("Could not find " + componentId);
		Level lev = tl.getLevel();
		int seqno = tl.getSeqno();
		if (lev.isOff())
			return;
		// Check if we should log this message.
		// if (level.isHigherLevel(lev)) {
		if (!lev.isHigherLevel(level)) {
			TraceNotification traceNotification = new TraceNotification(traceMBeanImpl, messageType, componentId, level, message, null, seqno, timeStamp);
			this.traceMBeanImpl.sendNotification(traceNotification);
		}

	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.facilities.TraceFacility#createTrace(javax.slee.ComponentID,
	 * javax.slee.facilities.Level, java.lang.String, java.lang.String,
	 * java.lang.Throwable, long)
	 */
	public void createTrace(ComponentID componentId, Level level, String messageType, String message, Throwable cause, long timeStamp) throws NullPointerException, IllegalArgumentException,
			UnrecognizedComponentException, FacilityException {
		checkComponentID(componentId);

		MTraceLevel tl = this.traceLevelTable.get(componentId);
		if (log.isDebugEnabled()) {
			log.debug(" createTrace: " + componentId + " level " + level + " messageType " + messageType + " message " + message + " cause " + cause + " time stamp " + timeStamp);
		}
		if (tl == null)
			throw new UnrecognizedComponentException("Could not find " + componentId);
		this.notificationTypes.add(messageType);
		Level lev = tl.getLevel();
		int seqno = tl.getSeqno();
		if (lev.isOff())
			return;
		// Check if we should log this message.
		if (level.isHigherLevel(lev) || level.toInt() == lev.toInt()) {
			TraceNotification traceNotification = new TraceNotification(traceMBeanImpl, messageType, componentId, level, message, cause, seqno, timeStamp);
			this.traceMBeanImpl.sendNotification(traceNotification);
		}

	}

	public String[] getNotificationTypes() {
		String ntypes[] = new String[this.notificationTypes.size()];
		ntypes = this.notificationTypes.toArray(ntypes);
		return ntypes;
	}

}


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

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

import org.jboss.logging.Logger;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

/**
 *
 * DeployableUnit Wrapper for providing some useful URL manipulation and VFS hacks.
 *
 * @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a>
 */
public class DeployableUnitWrapper {
  // The logger.
  private static Logger logger = Logger.getLogger(DeployableUnitWrapper.class);

  private URL url;

  private String fileName;

  private String fullPath;

  public DeployableUnitWrapper(URL url, String name) {
    try {
      gatherInfoFromURL(url);

      // Only for WildFly
      if (this.fileName.contentEquals("content")) {
        this.fileName = name;
      }
    }
    catch (MalformedURLException e) {
      logger.error(e.getLocalizedMessage(), e);
    }
  }

  // Private -------------------------------------------------------

  private void gatherInfoFromURL(URL url) throws MalformedURLException {
    // Weird VFS behavior... returns jar:file:...jar!/
    if(url.getProtocol().equals("jar")) {
      this.url = new URL(url.getFile().replaceFirst("!/", "/"));
    }
    else {
      this.url = url;
    }

    this.fullPath = this.url.getFile();

    this.fileName = getFileNameInternal(fullPath);
  }

  private String getFileNameInternal(String fullPath) {
    String fileName = fullPath;

    if (fileName.endsWith("/")) {
      fileName = fileName.substring(0, fileName.length() - 1);
    }

    fileName = fileName.substring(fileName.lastIndexOf("/") + 1);

    return fileName;
  }

  // Getters and Setters -------------------------------------------

  public URL getUrl() {
    return url;
  }

  public String getFileName() {
    return fileName;
  }

  public String getFullPath() {
    return fullPath;
  }

  public URL getEntry(String path) {
    URL retURL = null;

    try {
      retURL = new URL(this.url + "/" + path);

      try {
        retURL.openStream().close();
      }
      catch ( IOException e ) {
        retURL = null;
      }
    }
    catch ( MalformedURLException e ) {
      logger.error(e.getLocalizedMessage(), e);
    }

    return  retURL;
  }
}


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

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.Serializable;
import java.util.Arrays;

/**
 * Small class to wrap event fired from remote server. It exists to hide serialization of real event
 * and not to pass byte[] as argument.
 *
 * @author baranowb
 *
 */
public class RemoteEventWrapper implements Externalizable {

	protected transient byte[] serializedEvent;

	public RemoteEventWrapper() {
		super();
		// default constructor, so JVM can create instance.
	}

	// add more.
	public RemoteEventWrapper(Serializable event) throws IOException {
		setEvent(event);
	}

	public void setEvent(Serializable event) throws IOException {

		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutputStream os = new ObjectOutputStream(bos);
		os.writeObject(event);
		this.serializedEvent = bos.toByteArray(); // do that in APP thread :)
	}

	public Object getEvent() throws IOException, ClassNotFoundException {

		ByteArrayInputStream bis = new ByteArrayInputStream(this.serializedEvent);
		TCCLObjectInputStream ois = new TCCLObjectInputStream(bis);
		return ois.readObject();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
	 */
	@Override
	public void writeExternal(ObjectOutput out) throws IOException {

		if(this.serializedEvent == null)
		{
			throw new IOException("No serialized event set.");
		}
		// add id?
		out.writeInt(this.serializedEvent.length);
		out.write(this.serializedEvent);
        out.flush();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
	 */
	@Override
	public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
		int len = in.readInt();
		this.serializedEvent = new byte[len];
		in.readFully(serializedEvent);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + Arrays.hashCode(serializedEvent);
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		RemoteEventWrapper other = (RemoteEventWrapper) obj;
		if (!Arrays.equals(serializedEvent, other.serializedEvent))
			return false;
		return true;
	}

	/**
	 * Small class with hack to make ObjectInputStream aware of Thread Context Class Loader
	 * @author baranowb
	 *
	 */
	private class TCCLObjectInputStream extends ObjectInputStream
	{
		//possibly this should be moved to more generic package, so we can use it, ie. Marshaler objects of RA??

		/**
		 * @throws IOException
		 * @throws SecurityException
		 */
		public TCCLObjectInputStream() throws IOException, SecurityException {
			super();
		}

		/**
		 * @param in
		 * @throws IOException
		 */
		public TCCLObjectInputStream(InputStream in) throws IOException {
			super(in);
		}

		@Override
		public Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
			ClassLoader currentTccl = null;
			try {
				currentTccl = Thread.currentThread().getContextClassLoader();
				return currentTccl.loadClass(desc.getName());
			} catch (Exception e) {

			}

			return super.resolveClass(desc);
		}

	}
}


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

package org.mobicents.slee.runtime.facilities.nullactivity;

import javax.slee.SLEEException;
import javax.slee.TransactionRequiredLocalException;
import javax.slee.nullactivity.NullActivity;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.facilities.nullactivity.NullActivityHandle;

/**
 * Implementation of the null activity.
 *
 * @author M. Ranganathan
 * @author Eduardo Martins
 *
 */
public class NullActivityImpl implements NullActivity {

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

	private final NullActivityHandle handle;

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

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

	public NullActivityImpl(NullActivityHandle handle) {
		this.handle = handle;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.nullactivity.NullActivity#endActivity()
	 */

	public void endActivity() throws TransactionRequiredLocalException,
			SLEEException {
		// Check if in valid context.

		if (logger.isDebugEnabled()) {
			logger.debug("NullActivity.endActivity()");
		}
		sleeContainer.getTransactionManager().mandateTransaction();

		sleeContainer.getActivityContextFactory().getActivityContext(
				new NullActivityContextHandle(handle))
				.endActivity();
	}

	protected NullActivityHandle getHandle() {
		return handle;
	}

	public int hashCode() {
		return handle.hashCode();
	}

	public boolean equals(Object object) {
		if ((object != null) && (object.getClass() == this.getClass())) {
			NullActivityImpl other = (NullActivityImpl) object;
			return this.handle.equals(other.handle);
		} else {
			return false;
		}
	}
}


package javax.slee.profile.query;

/**
 * The Not class is a composite dynamic query expression that
 * inverts the match result of its nested query expression.
 */
public final class Not extends QueryExpression {
    /**
     * Create a Not query expression.
     * @param expr the query expression who's match result will be inverted
     *        by this Not expression.
     * @throws NullPointerException if expr is null.
     */
    public Not(QueryExpression expr) {
        if (expr == null) throw new NullPointerException("expr is null");
        this.expr = expr;
    }

    /**
     * Get the query expression who's match result will be inverted by this Not
     * query expression.
     * @return the nested query expression.
     */
    public QueryExpression getExpression() { return expr; }

    // protected

    // javadoc copied from parent
    protected void toString(StringBuffer buf) {
        buf.append("!(");
        expr.toString(buf);
        buf.append(')');
    }

    // package

    /**
     * Check whether the specified expression contains a reference, either direct
     * or indirect, to this expression.
     * @param expr the expression to check and possibly recurse through.
     * @throws IllegalArgumentException if a cyclic expression is detected.
     */
    void checkForCycles(QueryExpression expr) throws IllegalArgumentException {
        // is the expression argument equal to this?
        if (expr == this) throw new IllegalArgumentException("Cyclic expression detected");

        // recurse through nested expression if it's a composite expression
        QueryExpression nested = this.expr;
        if (nested instanceof CompositeQueryExpression) {
            ((CompositeQueryExpression)nested).checkForCycles(expr);
        }
        else if (nested instanceof Not) {
            ((Not)nested).checkForCycles(expr);
        }
    }

    private final QueryExpression expr;
}


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

/***************************************************
 *                                                 *
 *  Restcomm: The Open Source JSLEE Platform      *
 *                                                 *
 *  Distributable under LGPL license.              *
 *  See terms of license at gnu.org.               *
 *                                                 *
 ***************************************************/

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

import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;

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

import org.apache.log4j.Logger;
import org.mobicents.slee.container.component.SbbComponentImpl;
import org.mobicents.slee.container.component.deployment.ClassPool;

/**
 * Class decorating the sbb abstract class. The byte code is modified IF
 * necessary to trap SBB code that violates the SLEE spec:
 * <pre>
 * 	1) write access to java:comp/env
 *  2) new Thread()
 * </pre>
 * TODO: Currently we check the SBB abstract class itself, but not its
 * ascendands or utility classes it uses.
 *
 * @author Ivelin Ivanov
 *
 */
public class SbbAbstractClassDecorator {

    /**
     * the sbb abstract class
     */
    private CtClass sbbAbstractClass = null;

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

    /**
     * the sbb concrete methods written by the SBB developer
     */
    private Map concreteMethods = null;

    private final SbbComponentImpl component;

    /**
     * Optimization variable. Helps avoid writing to disk abstract classes, which are not modified.
     */
    private boolean isAbstractSbbClassDecorated = false;

    /**
     * Constructor
     */
    public SbbAbstractClassDecorator(SbbComponentImpl component) {
        this.component = component;
    }

    /**
     * Decorate the abstract sbb Class
     *
     * @return the decorated sbb abstract class
     */
    public boolean decorateAbstractSbb() throws DeploymentException {

    	ClassPool pool = component.getClassPool();
    	String sbbAbstractClassName = component.getDescriptor().getSbbAbstractClass().getSbbAbstractClassName();
        try {
            sbbAbstractClass = pool.get(sbbAbstractClassName);
        } catch (NotFoundException nfe) {
            throw new DeploymentException("Could not find Abstract Sbb Class: "
                    + sbbAbstractClassName, nfe);
        }

        // populate the list of concrete methods. It will be needed by the
        // decorating methods.
        concreteMethods = new HashMap();
    	CtMethod[] methods = sbbAbstractClass.getDeclaredMethods();
    	for (int i = 0; i < methods.length; i++) {
    	    int mods = methods[i].getModifiers();
    		if (!Modifier.isAbstract(mods) && !Modifier.isNative(mods)) {
    			concreteMethods.put(methods[i].getName() + methods[i].getSignature(), methods[i]);
    		}
    	}

        decorateENCBindCalls();
        decorateNewThreadCalls();

        if (isAbstractSbbClassDecorated) {
        	try {
        		String deployDir = component.getDeploymentDir().getAbsolutePath();
        		sbbAbstractClass.writeFile(deployDir);
        		sbbAbstractClass.detach();
        		// the file on disk is now in sync with the latest in-memory version
        		if (logger.isDebugEnabled()) {
        			logger.debug("Modified Abstract Class "
        					+ sbbAbstractClass.getName()
        					+ " generated in the following path "
        					+ deployDir);
        		}
        		//} catch (NotFoundException e) {
        		//    String s = "Error writing modified abstract sbb class";
        		//    logger.error(s,e);
        		//    throw new DeploymentException (s,e);
        	} catch (Throwable e) {
        		throw new SLEEException ( e.getMessage(), e);
        	} finally {
        		sbbAbstractClass.defrost();
        	}
        	return true;
        }
        else {
        	return false;
        }
    }

    /**
     *
     * If there are new Thread() calls, replace with exception.
     *
     * Required by SLEE 1.0 spec.
     *
     *
     */
    private void decorateNewThreadCalls() {
        // TODO: Find which TCK test shows the required functionality.
    }

    /**
     *
     * If there are bind calls to ENC, replace with
     * OperationNotSupportedException exception.
     *
     * Required by SLEE 1.0 spec.
     *
     * @see com.opencloud.sleetck.lib.testsuite.sbb.abstractclass.Test522Test
     *
     */
    private void decorateENCBindCalls() {
        Iterator iter = concreteMethods.values().iterator();
        while (iter.hasNext()) {
            CtMethod method = (CtMethod) iter.next();
            try {
                trapMethodIfENCBindCall(method);
            } catch (CannotCompileException e) {
                throw new SLEEException(
                        "Could not decorate ENC bind calls for sbb abstract class: "
                                + sbbAbstractClass, e);
            }
        }
    }

    private void trapMethodIfENCBindCall(CtMethod method)
            throws CannotCompileException {
        method.instrument(new ExprEditor() {

            public void edit(MethodCall m) throws CannotCompileException {
                // the call has to be on a JNDI Context object
                boolean isJndiCtx = false;
                try {
                    // see if the method call is on javax.naming.Context or a derived type
                    if (m.getClassName().equals(javax.naming.Context.class.getName())) {
                        isJndiCtx = true;
                    } else {
                        CtClass cl0 = component.getClassPool().get(m.getClassName());
                        CtClass[] cl0Interfaces = cl0.getInterfaces();
                        for (int i = 0; i < cl0Interfaces.length; i++) {
                            CtClass cl0If = cl0Interfaces[i];
                            if (cl0If.getName().equals(javax.naming.Context.class.getName())) {
                                isJndiCtx = true;
                                break;
                            }
                        }
                    }
                } catch (NotFoundException e) {
                	// The class is not in the pool so ignore it
                	return;
                    //throw new CannotCompileException(e);
                }
                if (!isJndiCtx)
                    return;

                /*
                 * trap calls to Contenxt bind, unbind, rebind
                 */
                if (m.getMethodName().endsWith("bind") || m.getMethodName().equals("createSubcontext")) {
                    m.replace("{ "
                                + "String fullJndiName = $0.composeName($1, $0.getNameInNamespace());"
                                + "System.err.println(\"TRAPPED SBB METHOD - JNDI BIND CALL; fullJndiName: \" + fullJndiName);"
                                + "if (fullJndiName.startsWith(\"java:comp/env\")"
                                +     " || " + "fullJndiName.startsWith(\"env\")"
                            	+     ") {"
                                + "	   throw new javax.naming.OperationNotSupportedException(\"SBB is not allowed write access to java:comp/env. See SLEE 1.0 spec for details. \");	"
                                + "} "
                                + "else {$_ = $proceed($$);}; "
                            + "}");
                    isAbstractSbbClassDecorated = true;
                }
            }
        });
    } // trapMethodIfENCBindCall

}


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

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

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Arrays;
import java.util.Set;

import javax.slee.SLEEException;
import javax.slee.TransactionRolledbackLocalException;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.SleeContainerUtils;
import org.mobicents.slee.container.jndi.JndiManagement;
import org.mobicents.slee.container.sbbentity.SbbEntity;
import org.mobicents.slee.container.sbbentity.SbbEntityID;
import org.mobicents.slee.runtime.sbb.SbbConcrete;

/**
 * An invoker for the sbb local object.
 *
 * @author M. Ranganathan
 * @author Ivelin Ivanov
 * @author martins
 */
public class SbbLocalObjectInterceptor {

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

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

    private boolean setRollbackOnly;

	public Object invokeAndReturnObject(final SbbConcrete sbbConcrete,
			String methodName, final Object[] args, Class<?>[] types)
			throws Exception {

		if (logger.isTraceEnabled()) {
			logger.trace("invokeAndReturnObject : sbbConcrete = " + sbbConcrete
					+ " , methodName = " + methodName + " , args = "
					+ Arrays.asList(args) + " , types = "
					+ Arrays.asList(types));
		}

		if (this.setRollbackOnly) {
			throw new TransactionRolledbackLocalException(
					"Previous invocation caused rollback");
		}

		final Method meth = sbbConcrete.getClass().getMethod(methodName, types);
		final SbbEntity sbbEntity = sbbConcrete.getSbbEntity();

		Set<SbbEntityID> invokedsbbEntities = null;
		if (!sbbEntity.isReentrant()) {
			invokedsbbEntities = sleeContainer
				.getTransactionManager().getTransactionContext().getInvokedNonReentrantSbbEntities();
			if (!invokedsbbEntities.add(sbbEntity.getSbbEntityId())) {
				throw new SLEEException(" unable to invoke sbb local object, re-entrancy not allowed by sbb "+sbbEntity.getSbbId());
			}
		}

		final ClassLoader currentThreadClassLoader = SleeContainerUtils.getCurrentThreadClassLoader();
		SleeContainerUtils.setCurrentThreadClassLoader(sbbEntity.getSbbComponent().getClassLoader());

		final JndiManagement jndiManagement = sleeContainer.getJndiManagement();
		jndiManagement.pushJndiContext(sbbEntity.getSbbComponent());

		try {
			if (System.getSecurityManager() == null
					|| !sbbEntity.getSbbComponent()
							.isolateSecurityPermissionsInLocalInterface()) {
				return meth.invoke(sbbConcrete, args);
			} else {
				try {
					// This is required. Since domain chain may indicate RA for
					// instance, or SLEE deployer. If we don't do that test
					// tests/runtime/security/Test1112012Test.xml fails
					return AccessController
							.doPrivileged(new PrivilegedExceptionAction<Object>() {
								public Object run()
										throws IllegalAccessException,
										InvocationTargetException {
									return meth.invoke(sbbConcrete, args);
								}
							});
				} catch (PrivilegedActionException pae) {
					final Throwable cause = pae.getException();
					if (cause instanceof InvocationTargetException) {
						processInvocationTargetException((InvocationTargetException)cause);
						// the code above always throws exception
						return null;
					} else {
						throw pae.getException();
					}
				}
			}
		} catch (InvocationTargetException ex) {
			processInvocationTargetException(ex);
			// the code above always throws exception
			return null;
		} finally {
			jndiManagement.popJndiContext();
			SleeContainerUtils.setCurrentThreadClassLoader(currentThreadClassLoader);
			if (invokedsbbEntities != null) {
				invokedsbbEntities.remove(sbbEntity.getSbbEntityId());
			}
		}
	}

	private void processInvocationTargetException(InvocationTargetException exception) throws Exception {
		// Remember the actual exception is hidden inside the
		// InvocationTarget exception when you use reflection!
		final Throwable realException = exception.getCause();
		if (realException instanceof RuntimeException) {
			sleeContainer.getTransactionManager().setRollbackOnly();
			this.setRollbackOnly = true;
			throw new TransactionRolledbackLocalException(
					"SbbLocalObject Invocation resulted in exception!",realException);
		}
		else if (realException instanceof Exception) {
			throw (Exception) realException;
		}
		else {
			throw new SLEEException("Dude!!",realException);
		}
	}

	// Invokers for the simple types

	public void invokeAndReturnvoid(SbbConcrete proxy, String methodName,
			Object[] args, Class<?>[] argTypes) throws Exception {
		invokeAndReturnObject(proxy, methodName, args, argTypes);
	}

	public boolean invokeAndReturnboolean(SbbConcrete proxy, String methodName,
			Object[] args, Class<?>[] argTypes) throws Exception {
		final Object retval = invokeAndReturnObject(proxy, methodName, args,
				argTypes);
		if (logger.isTraceEnabled()) {
			logger.trace("invokeAndReturnObject : returned = " + retval);
		}
		return ((Boolean) retval).booleanValue();
	}

	public int invokeAndReturnint(SbbConcrete proxy, String methodName,
			Object[] args, Class<?>[] types) throws Exception {
		final Object retval = invokeAndReturnObject(proxy, methodName, args,
				types);
		if (logger.isTraceEnabled()) {
			logger.trace("invokeAndReturnObject : returned = " + retval);
		}
		return ((Integer) retval).intValue();
	}

	public long invokeAndReturnlong(SbbConcrete proxy, String methodName,
			Object[] args, Class<?>[] types) throws Exception {
		Object retval = invokeAndReturnObject(proxy, methodName, args, types);
		if (logger.isTraceEnabled()) {
			logger.trace("invokeAndReturnObject : returned = " + retval);
		}
		return ((Long) retval).longValue();
	}

	public double invokeAndReturndouble(SbbConcrete proxy, String methodName,
			Object[] args, Class<?>[] types) throws Exception {
		Object retval = invokeAndReturnObject(proxy, methodName, args, types);
		if (logger.isTraceEnabled()) {
			logger.trace("invokeAndReturnObject : returned = " + retval);
		}
		return ((Double) retval).doubleValue();
	}

	public char invokeAndReturnchar(SbbConcrete proxy, String methodName,
			Object[] args, Class<?>[] types) throws Exception {
		Object retval = invokeAndReturnObject(proxy, methodName, args, types);
		if (logger.isTraceEnabled()) {
			logger.trace("invokeAndReturnObject : returned = " + retval);
		}
		return ((Character) retval).charValue();
	}

	public float invokeAndReturnfloat(SbbConcrete proxy, String methodName,
			Object[] args, Class<?>[] types) throws Exception {
		Object retval = invokeAndReturnObject(proxy, methodName, args, types);
		if (logger.isTraceEnabled()) {
			logger.trace("invokeAndReturnObject : returned = " + retval);
		}
		return ((Float) retval).floatValue();
	}

	public float invokeAndReturnshort(SbbConcrete proxy, String methodName,
			Object[] args, Class<?>[] types) throws Exception {
		Object retval = invokeAndReturnObject(proxy, methodName, args, types);
		if (logger.isTraceEnabled()) {
			logger.trace("invokeAndReturnObject : returned = " + retval);
		}
		return ((Short) retval).shortValue();
	}

}


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

/*
 * Created on Mar 14, 2005
 *
 * The Open SLEE Project
 *
 * A SLEE for the People
 *
 * 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.resource.deployment;

import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtMethod;
import javassist.CtNewMethod;

import javax.slee.resource.ResourceAdaptorTypeID;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.component.ClassPool;
import org.mobicents.slee.container.component.ratype.ResourceAdaptorTypeComponent;
import org.mobicents.slee.container.deployment.ConcreteClassGeneratorUtils;
import org.mobicents.slee.resource.AbstractActivityContextInterfaceFactory;

/**
 * Generator for the concrete aci factory for an ra type
 * @author martins
 */
public class ConcreteActivityContextInterfaceFactoryGenerator {

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

    private final ResourceAdaptorTypeComponent component;

    public ConcreteActivityContextInterfaceFactoryGenerator(ResourceAdaptorTypeComponent component) {
    	this.component = component;
    }

    /**
	 * Create a constructor. This method simply records the input parameters in
	 * appropriately named fields.
	 *
	 * @param
	 * @param classes
	 */
    private void createConstructor(CtClass concreteClass, CtClass sleeContainerClass, CtClass resourceAdaptorTypeIDClass)
            throws Exception {

        CtConstructor ctCons = new CtConstructor(new CtClass[]{sleeContainerClass,resourceAdaptorTypeIDClass}, concreteClass);
        ctCons.setBody("{ super($1,$2); }");
        concreteClass.addConstructor(ctCons);

    }

    public void generateClass() throws Exception {

    	if(component.getActivityContextInterfaceFactoryInterface() == null) {
    		return;
    	}

    	ClassPool classPool = component.getClassPool();

        String interfaceName = component.getActivityContextInterfaceFactoryInterface().getName();
        CtClass interfaceCtClass = classPool.get(interfaceName);

        // make the class
		String concreteClassName = interfaceName + "Impl";
		if (logger.isDebugEnabled()) {
        	logger.debug("generating "+concreteClassName);
        }
		CtClass concreteCtClass = classPool.makeClass(concreteClassName);
        // set interface
        ConcreteClassGeneratorUtils.createInterfaceLinks(concreteCtClass,new CtClass[]{interfaceCtClass});
        // set super class
        CtClass superCtClass = classPool.get(AbstractActivityContextInterfaceFactory.class.getName());
        concreteCtClass.setSuperclass(superCtClass);
        // create constructor
        this.createConstructor(concreteCtClass, classPool.get(SleeContainer.class
                .getName()),classPool.get(ResourceAdaptorTypeID.class
                        .getName()));
        // generate methods
        for (CtMethod method : interfaceCtClass.getMethods()) {
        	if (method.getName().equals("getActivityContextInterface")) {
        		CtMethod concreteMethod = CtNewMethod.copy(method,concreteCtClass, null);
            	concreteMethod.setBody("{ return super.getACI($1); }");
            	concreteCtClass.addMethod(concreteMethod);
        	}
        }
        // write file
        String deploymentPathStr = component.getDeploymentDir().getAbsolutePath();
        concreteCtClass.writeFile(deploymentPathStr);
        logger.debug("Writing file " + concreteClassName);
        // load class into component
        component.setActivityContextInterfaceFactoryConcreteClass(Thread.currentThread().getContextClassLoader().loadClass(concreteCtClass.getName()));
        // and defrost in javassist pool
        concreteCtClass.defrost();
    }

}


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

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

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TimerTask;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import javax.slee.SbbID;
import javax.slee.facilities.TimerID;
import javax.slee.management.ManagementException;
import javax.slee.nullactivity.NullActivity;

import org.apache.log4j.Logger;
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.activity.ActivityType;
import org.mobicents.slee.container.management.jmx.editors.ComponentIDPropertyEditor;
import org.mobicents.slee.container.resource.ResourceAdaptorActivityContextHandle;
import org.mobicents.slee.container.resource.ResourceAdaptorEntity;
import org.mobicents.slee.container.sbbentity.SbbEntity;
import org.mobicents.slee.container.sbbentity.SbbEntityFactory;
import org.mobicents.slee.container.sbbentity.SbbEntityID;
import org.mobicents.slee.runtime.activity.ActivityContextFactoryImpl;
import org.mobicents.slee.runtime.activity.ActivityContextImpl;

/**
 * This class provides minimum information for management console. It also tries
 * to clean container of dead activities
 *
 * @author Bartosz Baranowski
 * @author Eduardo Martins
 *
 */
public class ActivityManagementMBeanImpl extends MobicentsServiceMBeanSupport
		implements ActivityManagementMBeanImplMBean {

	// Name convention is to conform to other mbeans - also ServiceMBeanSupport
	// is not StandadMBean which allows
	// Passing MBean interface class which enables custom names this is why
	// MBean interface has sufix - MBeanImplMbean

	private final ActivityContextFactoryImpl acFactory;
	private final SbbEntityFactory sbbEntityFactory;

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

	public ActivityManagementMBeanImpl(SleeContainer sleeContainer) {
		super(sleeContainer);
		this.acFactory = (ActivityContextFactoryImpl) sleeContainer.getActivityContextFactory();
		this.sbbEntityFactory = sleeContainer.getSbbEntityFactory();
	}

	// === PROPERTIES

	public int getActivityContextCount() {
		return this.acFactory.getActivityContextCount();
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.ActivityManagementMBeanImplMBean#setTimeBetweenLivenessQueries(long)
	 */
	public void setTimeBetweenLivenessQueries(long set) {
		acFactory.getConfiguration().setTimeBetweenLivenessQueries(set);
		if (set == 0) {
			cancelLivenessQuery();
		}
		else {
			if (scheduledFuture == null) {
				scheduleLivenessQuery();
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.ActivityManagementMBeanImplMBean#getTimeBetweenLivenessQueries()
	 */
	public long getTimeBetweenLivenessQueries() {
		return acFactory.getConfiguration().getTimeBetweenLivenessQueries();
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.ActivityManagementMBeanImplMBean#setActivityContextMaxIdleTime(long)
	 */
	public void setActivityContextMaxIdleTime(long set) {
		acFactory.getConfiguration().setMaxTimeIdle(set);
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.ActivityManagementMBeanImplMBean#getActivityContextMaxIdleTime()
	 */
	public long getActivityContextMaxIdleTime() {
		return acFactory.getConfiguration().getMaxTimeIdle();
	}

	// --- OPERATIONS

	public void endActivity(ActivityContextHandle ach) throws ManagementException {

		// Again this is tx method
		logger.info("Trying to stop null activity[" + ach + "]!!");
		ActivityContext ac = acFactory.getActivityContext(ach);
		if (ac == null) {
			logger.debug("There is no ac associated with given acID["
						+ ach + "]!!");
			throw new ManagementException("Can not find AC for given ID["
					+ ach + "], try again!!!");
		}
		if (ac.getActivityContextHandle().getActivityType() == ActivityType.NULL) {
			logger.debug("Scheduling activity end for acID[" + ach
						+ "]");
			NullActivity nullActivity = (NullActivity) ac.getActivityContextHandle().getActivityObject();
			if (nullActivity != null) {
				nullActivity.endActivity();
			}
		} else {
			logger.debug("AC is not null activity context");
			throw new IllegalArgumentException("Given ID[" + ach
					+ "] does not point to NullActivity");
		}
	}

	public void queryActivityContextLiveness() {

		logger.info("Extorting liveliness query!!");
		// prepareBean();
		cancelLivenessQuery();
		new PeriodicLivelinessScanner().run();
		logger.info("Extortion complete");
		// currentQuestioner=new PeriodicLivelinessScanner();

	}

	public String[] listActivityContextsFactories() {
		logger.info("Listing AC factories");
		Set<String> factoriesSet = new HashSet<String>();
		for (ActivityContextHandle ach : this.acFactory.getAllActivityContextsHandles()) {
			factoriesSet.add(ach.getActivityType() == ActivityType.RA ? ((ResourceAdaptorActivityContextHandle)ach).getResourceAdaptorEntity().getName() : "");
		}
		if (factoriesSet.isEmpty())
			return null;
		String[] ret = new String[factoriesSet.size()];
		ret = (String[]) factoriesSet.toArray(ret);
		return ret;
	}

	public Object[] listActivityContexts(boolean inDetails) {
		logger.info("Listing ACs with details[" + inDetails + "]");
		return listWithCriteria(false, inDetails, LIST_BY_NO_CRITERIA, null);
	}

	public Object[] retrieveActivityContextDetails(ActivityContextHandle ach)
			throws ManagementException {
		logger.info("Retrieving AC details for " + ach);
		ActivityContextImpl ac = this.acFactory.getActivityContext(ach);
		if (ac == null) {
			logger.debug("Ac retrieval failed, no such ac[" + ach
						+ "]!!!");
			throw new ManagementException(
						"Activity Context does not exist (ACID[" + ach
						+ "]), try another one!!");
		}
		return getDetails(ac);
	}

	/**
	 * This is main place where SLEE is accessed. This functions lists AC in
	 * various different ways. It can either return Object[] of arrays
	 * representing AC of simple Object[] that in fact contains String objects
	 * representing IDs of Activity Contexts
	 *
	 * @param listIDsOnly -
	 *            tells to list only its, if this is true, second boolean flag
	 *            is ignored. Return value is Object[]{String,String,....}
	 * @param inDetails -
	 *            Tells whether sub-arrays containing name bindings, attached
	 *            sbb entities should be passed, or only value representing
	 *            their length. If true arrays are passed, if false, only
	 *            values.
	 * @param criteria -
	 *            Critteria to search by - if this is different than
	 *            {@link ActivityManagementMBeanImplMBean.LIST_BY_NO_CRITERIA}
	 *            next parameter has to have value.
	 * @param comparisonCriteria -
	 *            this has to contain String representation of criteria ac
	 *            should be looked by: SbbEID, RA Entity Name , SbbID or
	 *            activity class name - like getClass().getName().
	 * @return
	 *

	 *
Object[]{Stirng, String}

	 *
Object[] ={@link #retrieveActivityContextDetails()},{@link #retrieveActivityContextDetails()},....
	 *

	 *

	 */
	private Object[] listWithCriteria(boolean listIDsOnly, boolean inDetails,
			int criteria, String comparisonCriteria) {

		logger.info("Listing with criteria[" + criteria + "] with details["
				+ inDetails + "] only IDS[" + listIDsOnly + "]");

		Iterator<ActivityContextHandle> it = this.acFactory.getAllActivityContextsHandles().iterator();
		ArrayList<Object> lst = new ArrayList<Object>();

		// Needed by LIST_BY_SBBID
		HashMap<SbbEntityID,SbbID> sbbEntityIdToSbbID = new HashMap<SbbEntityID,SbbID>();

		while (it.hasNext()) {
			ActivityContextHandle achOrig = it.next();
			//JmxActivityContextHandle ach = ActivityContextHandleSerializer.encode(achOrig);
			ActivityContextImpl ac = this.acFactory.getActivityContext(achOrig);
			if (ac == null) {
				continue;
			}
			Object activity = achOrig.getActivityObject();

			if (activity != null) {

	      String acId = ac.getStringID();
	      String acSource = achOrig.getActivityType() == ActivityType.RA ? ((ResourceAdaptorActivityContextHandle)achOrig).getResourceAdaptorEntity().getName() : "";

	      switch (criteria) {
				case LIST_BY_ACTIVITY_CLASS:

					if (!activity.getClass().getCanonicalName().equals(comparisonCriteria)) {
						ac = null; // we dont want this one here
					}
					break;

				case LIST_BY_RAENTITY:

					if (achOrig.getActivityType() == ActivityType.RA) {
						if (!acSource.equals(comparisonCriteria))
							ac = null;
					} else
						ac = null;
					break;

				case LIST_BY_SBBENTITY:

					for (SbbEntityID sbbEntityID : ac.getSbbAttachmentSet()) {
						if (sbbEntityID.toString().equals(comparisonCriteria)) {
							break;
						}
					}
					ac = null;
					break;

				case LIST_BY_SBBID:
					ComponentIDPropertyEditor propertyEditor = new ComponentIDPropertyEditor();
					propertyEditor.setAsText(comparisonCriteria);
					SbbID idBeingLookedUp = (SbbID) propertyEditor.getValue();
					boolean match = false;
					SbbID implSbbID = null;
					for (SbbEntityID sbbEntityID : ac.getSbbAttachmentSet()) {
						if (sbbEntityIdToSbbID.containsKey(sbbEntityID)) {
							implSbbID = sbbEntityIdToSbbID.get(sbbEntityID);
						} else {
							SbbEntity sbbe = sbbEntityFactory.getSbbEntity(sbbEntityID,false);
							if (sbbe == null) {
								continue;
							}
							implSbbID = sbbe.getSbbId();
							sbbEntityIdToSbbID.put(sbbEntityID, implSbbID);
						}

						if (!implSbbID.equals(idBeingLookedUp)) {

							match = false;
							continue;
						} else {
							match = true;
							break;
						}

					}

					if (!match) {
						ac = null;
					}

					break;

				case LIST_BY_NO_CRITERIA:

					break;

				default:

					continue;
				}

				if (ac == null)
					continue;

				// Now we have to check - if we want only IDS
				Object singleResult = null;
				if (!listIDsOnly) {
					logger.debug("Adding AC[" + acId + "]");

					Object[] o = getDetails(ac);

					if (!inDetails) {

						// This is stupid, but can save some bandwith, not sure if
						// we
						// should care. But Console is java script, and
						// sometimes that can be pain, so lets ease it
					    o[SBB_ATTACHMENTS] = Integer.toString(((Object[]) o[SBB_ATTACHMENTS]).length);
						o[NAMES_BOUND_TO] = Integer.toString(((Object[]) o[NAMES_BOUND_TO]).length);
						o[TIMERS_ATTACHED] = Integer.toString(((Object[]) o[TIMERS_ATTACHED]).length);
						o[DATA_PROPERTIES] = Integer.toString(((Object[]) o[DATA_PROPERTIES]).length);
					}

					singleResult = o;

				} else {

					singleResult = acId;
				}

				lst.add(singleResult);
			}

		}
		if (lst.isEmpty())
			return null;

		logger.info("RETURN SIZE[" + lst.size() + "]");

		Object[] ret = new Object[lst.size()];
		ret = lst.toArray(ret);

		return ret;
	}

	/*
	 * FIXME uncomment code when everything is commited
	 *
	 * This method should be run in tx
	 */
	@SuppressWarnings("rawtypes")
	private Object[] getDetails(ActivityContextImpl ac) {

		logger.debug("Retrieveing details for acID["
				+ ac.getActivityContextHandle() + "]");
		Object[] o = new Object[ARRAY_SIZE];

		ActivityContextHandle achOrig = ac.getActivityContextHandle();
		//JmxActivityContextHandle ach = ActivityContextHandleSerializer.encode(achOrig);
		String acId = ac.getStringID();

		o[ActivityManagementMBeanImplMBean.AC_ID] = acId;
		logger.debug("======[getDetails]["
				+ o[ActivityManagementMBeanImplMBean.AC_ID] + "]["
				+ ac.hashCode() + "]");

		if (achOrig.getActivityType() == ActivityType.RA) {
			o[RA] = ((ResourceAdaptorActivityContextHandle)achOrig).getResourceAdaptorEntity().getName();
		}

		o[ACTIVITY_CLASS] = achOrig.getActivityObject().getClass().getName();
		logger.debug("======[getDetails][ACTIVITY_CLASS][" + o[ACTIVITY_CLASS]
				+ "]");
		// Date d = new Date(ac.getLastAccessTime());
		// o[LAST_ACCESS_TIME] = d;
		o[LAST_ACCESS_TIME] = ac.getLastAccessTime() + "";
		logger.debug("======[getDetails][LAST_ACCESS_TIME]["
				+ o[LAST_ACCESS_TIME] + "]["
				+ new Date(Long.parseLong((String) o[LAST_ACCESS_TIME])) + "]");

		Set<SbbEntityID> sbbAttachmentSet = ac.getSbbAttachmentSet();
		String[] tmp = new String[sbbAttachmentSet.size()];
		Iterator<?> it = sbbAttachmentSet.iterator();
		int counter = 0;
		while (it.hasNext()) {
			tmp[counter++] = it.next().toString();
		}
		o[SBB_ATTACHMENTS] = tmp;

		Set<String> nameBindindsSet = ac.getNamingBindings();
		tmp = new String[nameBindindsSet.size()];
		tmp = nameBindindsSet.toArray(tmp);
		o[NAMES_BOUND_TO] = tmp;

		Set<TimerID> attachedTimersSet = ac.getAttachedTimers();
		tmp = new String[attachedTimersSet.size()];
		it = attachedTimersSet.iterator();
		counter = 0;
		while (it.hasNext()) {
			tmp[counter++] = ((TimerID) it.next()).toString();
		}
		o[TIMERS_ATTACHED] = tmp;

		Map m = ac.getDataAttributes();
		tmp = new String[m.size()];
		it = m.keySet().iterator();
		counter = 0;
		while (it.hasNext()) {
			Object k = it.next();
			Object v = m.get(k);
			tmp[counter++] = k + "=" + v;
		}
		o[DATA_PROPERTIES] = tmp;

		return o;
	}

	// Should those methods throw something if sbbeid, classname or etity does
	// not exist?

	public Object[] retrieveActivityContextIDByActivityType(
			String fullQualifiedActivityClassName) {

		logger.info("Retrieving AC by activity class name["
				+ fullQualifiedActivityClassName + "]");
		return listWithCriteria(true, true, LIST_BY_ACTIVITY_CLASS,
					fullQualifiedActivityClassName);
	}

	public Object[] retrieveActivityContextIDByResourceAdaptorEntityName(
			String entityName) {

		logger.info("Retrieving AC by entity name[" + entityName + "]");
		return listWithCriteria(false, true, LIST_BY_RAENTITY, entityName);
	}

	public Object[] retrieveActivityContextIDBySbbEntityID(String sbbEID) {

		logger.info("Retrieving ACs by sbb entity id [" + sbbEID + "]");
		return listWithCriteria(true, true, LIST_BY_SBBENTITY, sbbEID);
	}

	public Object[] retrieveActivityContextIDBySbbID(String sbbID) {

		logger.info("Retrieving ACs by sbb id [" + sbbID + "]");
		return listWithCriteria(true, true, LIST_BY_SBBID, sbbID);
	}

	// TimerClass to run periodic livelines querry - here is decided which ac
	// are going to be querried, and possibly destroyed
	// , depends on impl

	/**
	 * FIXME uncomment code when everything is commited
	 */
	private class PeriodicLivelinessScanner extends TimerTask {

		private void queryLiveness(ActivityContextHandle ach,long currentTime) {

			if (ach.getActivityType() != ActivityType.RA)
				return;

			if(logger.isDebugEnabled())
				logger
					.debug("Periodic Liveliness Task is on the run, processing AC "+ach);

			ActivityContextImpl ac = acFactory.getActivityContext(ach);
			if(ac == null) {
				return;
			}

			if ((currentTime - ac.getLastAccessTime()) < acFactory.getConfiguration().getMaxTimeIdleInMs()) {
				// This one has been accessed in near past, so we dont
				// want to query it
				return;
			}

			final ResourceAdaptorActivityContextHandle raach = (ResourceAdaptorActivityContextHandle) ach;
			final ResourceAdaptorEntity raEntity = raach.getResourceAdaptorEntity();
			if (logger.isDebugEnabled()) {
				logger.debug("Invoking ra entity "+raEntity.getName()+" queryLiveness() for activity handle "+ach.getActivityHandle());
			}
			raEntity.getResourceAdaptorObject().queryLiveness(
								ach.getActivityHandle());

		}

		public void run() {
			long currentTime = System.currentTimeMillis();
			for (ActivityContextHandle ach : acFactory.getAllActivityContextsHandles()) {
				this.queryLiveness(ach,currentTime);
			}
			scheduleLivenessQuery();
		}

	}

	// -------------------- JBOSS MBean LIFECYCLE METHODS

	private ScheduledFuture<?> scheduledFuture;

	private void scheduleLivenessQuery() {
		final long timeBetweenLivenessQueries = acFactory.getConfiguration().getTimeBetweenLivenessQueries();
		if (timeBetweenLivenessQueries > 0) {
			this.scheduledFuture = this.acFactory.getSleeContainer().getNonClusteredScheduler().schedule(new PeriodicLivelinessScanner(),timeBetweenLivenessQueries,TimeUnit.MINUTES);
			if(logger.isDebugEnabled())
				logger.debug("Periodic Liveliness Task scheduled to run in "+timeBetweenLivenessQueries+" minutes");
		}
		else {
			this.scheduledFuture = null;
		}
	}

	public void cancelLivenessQuery() {
		if (scheduledFuture != null) {
			scheduledFuture.cancel(true);
			scheduledFuture = null;
		}
	}

	/**
	 *
	 *
	 * start MBean service lifecycle method
	 *
	 */
	public void startService() throws Exception {
		if(logger.isDebugEnabled()) {
			logger.debug("Starting Activity Manager MBean");
		}
		logger.info("Activity Management MBean started");
		scheduleLivenessQuery();
	}

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

}


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

import java.util.Map;

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

import org.mobicents.slee.container.activity.ActivityContext;
import org.mobicents.slee.container.activity.ActivityContextInterface;
import org.mobicents.slee.container.component.sbb.SbbComponent;

/**
 * Base class code for a concrete implementation of
 * {@link javax.slee.ActivityContextInterface} by an sbb.
 *
 * @author martins
 *
 */
public class SbbActivityContextInterfaceImpl implements
		ActivityContextInterface {

	private final ActivityContextInterface aciImpl;
	private final SbbComponent sbbComponent;

	public SbbActivityContextInterfaceImpl(
			ActivityContextInterface aciImpl, SbbComponent sbbComponent) {
		this.aciImpl = aciImpl;
		this.sbbComponent = sbbComponent;
	}

	public ActivityContext getActivityContext() {
		return aciImpl.getActivityContext();
	}

	public ActivityContextInterface getAciImpl() {
		return aciImpl;
	}

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

	@Override
	public boolean equals(Object obj) {
		// even if there may be different java interfaces for an AC, equality
		// should be defined only by the AC
		if (obj != null && obj instanceof ActivityContextInterface) {
			return ((ActivityContextInterface) obj).getActivityContext()
					.equals(this.aciImpl.getActivityContext());
		} else {
			return false;
		}
	}

	public void attach(SbbLocalObject arg0) throws NullPointerException,
			TransactionRequiredLocalException,
			TransactionRolledbackLocalException, SLEEException {
		aciImpl.attach(arg0);
	}

	public void detach(SbbLocalObject arg0) throws NullPointerException,
			TransactionRequiredLocalException,
			TransactionRolledbackLocalException, SLEEException {
		aciImpl.detach(arg0);
	}

	public Object getActivity() throws TransactionRequiredLocalException,
			SLEEException {
		return aciImpl.getActivity();
	}

	public boolean isEnding() throws TransactionRequiredLocalException,
			SLEEException {
		return aciImpl.isEnding();
	}

	public boolean isAttached(SbbLocalObject arg0) throws NullPointerException,
			TransactionRequiredLocalException,
			TransactionRolledbackLocalException, SLEEException {
		return aciImpl.isAttached(arg0);
	}

	/**
	 * Computes the real aci data field name
	 *
	 * @param fieldName
	 * @return
	 */
	private String getRealFieldName(String fieldName) {
		String realFieldName = sbbComponent.getDescriptor()
				.getActivityContextAttributeAliases().get(fieldName);
		if (realFieldName == null) {
			// not there then it has no alias, lets set one based on sbb id
			realFieldName = sbbComponent.getSbbID().toString() + "."
					+ fieldName;
			final Map<String, String> aliases = sbbComponent.getDescriptor()
					.getActivityContextAttributeAliases();
			synchronized (aliases) {
				aliases.put(fieldName, realFieldName);
			}
		}
		return realFieldName;
	}

	/**
	 * Sets an sbb aci data field value
	 *
	 * @param fieldName
	 * @param value
	 */
	public void setFieldValue(String fieldName, Object value) {
		String realFieldName = getRealFieldName(fieldName);
		aciImpl.getActivityContext().setDataAttribute(realFieldName, value);
	}

	/**
	 * Sets an sbb aci data field value
	 *
	 * @param fieldName
	 * @param value
	 */
	public void setFieldValue(String fieldName, byte value) {
		String realFieldName = getRealFieldName(fieldName);
		aciImpl.getActivityContext().setDataAttribute(realFieldName, value);
	}

	/**
	 * Sets an sbb aci data field value
	 *
	 * @param fieldName
	 * @param value
	 */
	public void setFieldValue(String fieldName, short value) {
		String realFieldName = getRealFieldName(fieldName);
		aciImpl.getActivityContext().setDataAttribute(realFieldName, value);
	}

	/**
	 * Sets an sbb aci data field value
	 *
	 * @param fieldName
	 * @param value
	 */
	public void setFieldValue(String fieldName, int value) {
		String realFieldName = getRealFieldName(fieldName);
		aciImpl.getActivityContext().setDataAttribute(realFieldName, value);
	}

	/**
	 * Sets an sbb aci data field value
	 *
	 * @param fieldName
	 * @param value
	 */
	public void setFieldValue(String fieldName, long value) {
		String realFieldName = getRealFieldName(fieldName);
		aciImpl.getActivityContext().setDataAttribute(realFieldName, value);
	}

	/**
	 * Sets an sbb aci data field value
	 *
	 * @param fieldName
	 * @param value
	 */
	public void setFieldValue(String fieldName, float value) {
		String realFieldName = getRealFieldName(fieldName);
		aciImpl.getActivityContext().setDataAttribute(realFieldName, value);
	}

	/**
	 * Sets an sbb aci data field value
	 *
	 * @param fieldName
	 * @param value
	 */
	public void setFieldValue(String fieldName, double value) {
		String realFieldName = getRealFieldName(fieldName);
		aciImpl.getActivityContext().setDataAttribute(realFieldName, value);
	}

	/**
	 * Sets an sbb aci data field value
	 *
	 * @param fieldName
	 * @param value
	 */
	public void setFieldValue(String fieldName, boolean value) {
		String realFieldName = getRealFieldName(fieldName);
		aciImpl.getActivityContext().setDataAttribute(realFieldName, value);
	}

	/**
	 * Sets an sbb aci data field value
	 *
	 * @param fieldName
	 * @param value
	 */
	public void setFieldValue(String fieldName, char value) {
		String realFieldName = getRealFieldName(fieldName);
		aciImpl.getActivityContext().setDataAttribute(realFieldName, value);
	}

	/**
	 * Retrieves an sbb aci data field value
	 *
	 * @param fieldName
	 * @param returnType
	 * @return
	 */
	public Object getFieldValue(String fieldName, Class<?> returnType) {

		String realFieldName = getRealFieldName(fieldName);

		Object value = aciImpl.getActivityContext().getDataAttribute(
				realFieldName);

		if (value == null) {
			if (returnType.isPrimitive()) {
				if (returnType.equals(Integer.TYPE)) {
					return Integer.valueOf(0);
				} else if (returnType.equals(Boolean.TYPE)) {
					return Boolean.FALSE;
				} else if (returnType.equals(Long.TYPE)) {
					return Long.valueOf(0);
				} else if (returnType.equals(Double.TYPE)) {
					return Double.valueOf(0);
				} else if (returnType.equals(Float.TYPE)) {
					return Float.valueOf(0);
				}
			}
		}

		return value;
	}

	// SLEE 1.1 Extensions

	@Override
	public String[] getNamesBound() {
		return aciImpl.getNamesBound();
	}

	@Override
	public TimerID[] getTimers() {
		return aciImpl.getTimers();
	}

	@Override
	public void suspend() throws TransactionRequiredLocalException,
			SLEEException {
		aciImpl.suspend();
	}
}


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

import org.apache.log4j.Logger;

import javax.resource.ResourceException;
import javax.slee.Address;
import javax.slee.EventTypeID;
import javax.slee.UnrecognizedActivityException;
import javax.slee.UnrecognizedEventException;
import javax.slee.connection.ExternalActivityHandle;
import javax.slee.connection.SleeConnection;

/**
 * Connection object which proxies calls.
 * @author baranowb
 *
 */
public class SleeConnectionImpl implements SleeConnection {

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

	private MobicentsSleeConnectionFactoryImpl sleeConnectionFactory;
	private SleeConnectionService service;

	SleeConnectionImpl(SleeConnectionService service,MobicentsSleeConnectionFactoryImpl sleeConnectionFactoryImpl) {
		super();

		this.sleeConnectionFactory = sleeConnectionFactoryImpl;
		this.service = service;

	}

	/* (non-Javadoc)
	 * @see javax.slee.connection.SleeConnection#close()
	 */
	public void close() throws ResourceException {
		if(service == null)
		{
			throw new ResourceException("Connection is in closed state");
		}else
		{
			this.service = null;
			this.sleeConnectionFactory.connectionClosed(this);
		}

	}

	/* (non-Javadoc)
	 * @see javax.slee.connection.SleeConnection#createActivityHandle()
	 */
	public ExternalActivityHandle createActivityHandle() throws ResourceException {
		if(this.service == null)
		{
			throw new ResourceException("Connection is in closed state");
		}

		return this.service.createActivityHandle();
	}

	/* (non-Javadoc)
	 * @see javax.slee.connection.SleeConnection#fireEvent(java.lang.Object, javax.slee.EventTypeID, javax.slee.connection.ExternalActivityHandle, javax.slee.Address)
	 */
	public void fireEvent(Object event, EventTypeID eventType,
			ExternalActivityHandle activityHandle, Address address) throws NullPointerException,
			UnrecognizedActivityException, UnrecognizedEventException, ResourceException {
		if(service == null)
		{
			throw new ResourceException("Connection is in closed state");
		}

		if (logger.isDebugEnabled()) {
			logger.debug("fireEvent(event=" + event + ",eventType=" + eventType
					+ ",activityHandle=" + activityHandle + ",address="
					+ address + ")");
		}

		this.service.fireEvent(event, eventType, activityHandle, address);
	}

	/* (non-Javadoc)
	 * @see javax.slee.connection.SleeConnection#getEventTypeID(java.lang.String, java.lang.String, java.lang.String)
	 */
	public EventTypeID getEventTypeID(String name, String vendor, String version) throws UnrecognizedEventException, ResourceException {
		if(service == null)
		{
			throw new ResourceException("Connection is in closed state");
		}
		return service.getEventTypeID(name, vendor, version);
	}

	void start(SleeConnectionService service) {
		this.service = service;
	}

}


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

import org.apache.log4j.Logger;
//import org.jboss.as.naming.WritableServiceBasedNamingStore;
//import org.jboss.msc.service.ServiceName;
//import org.jboss.msc.service.ServiceTarget;
import org.mobicents.slee.container.AbstractSleeContainerModule;
import org.mobicents.slee.container.util.JndiRegistry;

//import org.jboss.util.naming.Util;
//import javax.naming.Context;
//import javax.naming.InitialContext;
//import javax.naming.NamingException;

import javax.resource.ResourceException;
import javax.slee.connection.SleeConnection;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * @author baranowb
 *
 */
public class MobicentsSleeConnectionFactoryImpl
		extends AbstractSleeContainerModule
		implements MobicentsSleeConnectionFactory, Serializable {

	/**
	 *
	 */
	private static final long serialVersionUID = 1L;
	//not this class implements serializable, but its bound only to local JVM, its not accessbile outside!
	private static final String _DEFAULT_NAME="/MobicentsConnectionFactory";
	private static final Logger logger = Logger.getLogger(MobicentsSleeConnectionFactoryImpl.class);

	//private JndiRegistry registry = null;
	private String jndiName = _DEFAULT_NAME;
	private List<SleeConnection> connectionList = new ArrayList<SleeConnection>();
	private transient SleeConnectionService service;

	public MobicentsSleeConnectionFactoryImpl() {
		super();
		//registry = new JndiRegistry();
	}

	/* (non-Javadoc)
	 * @see javax.slee.connection.SleeConnectionFactory#getConnection()
	 */
	public SleeConnection getConnection() throws ResourceException {
		//this method is listed as MBean method, upon lookup in jmx console it will create connection, its a possible leak
		//with list.
		synchronized (connectionList) {
			SleeConnectionImpl conn;
			if(connectionList.size()>0)
			{
				if(logger.isDebugEnabled())
				{
					logger.debug("Using connection from pool.");
				}
				conn = (SleeConnectionImpl) connectionList.remove(0);
				conn.start(this.service);
			}else
			{
				if(logger.isDebugEnabled())
				{
					logger.debug("Creating new connection.");
				}
				conn = new SleeConnectionImpl(this.service,this);
			}
			return conn;

		}

	}

	public void start() throws Exception
	{

	}

	public void stop()
	{

	}

	//local methods called by connection
	void connectionClosed(SleeConnectionImpl conn)
	{
		synchronized (connectionList) {
			this.connectionList.add(conn);
		}
	}

	//bean methods

	public String getJNDIName() {

		return this.jndiName;
	}

	public void setJNDIName(String name) {
		this.jndiName = name;

	}

	@Override
	public void sleeInitialization() {
		this.service = super.sleeContainer.getSleeConnectionService();

        /*
		try {
			registry.setServiceContainer(super.sleeContainer.getServiceController().getServiceContainer());
			registry.bindToJndi("java:"+this.getJNDIName(), this);
		} catch (Throwable t) {
			t.printStackTrace();
		}
        */

		/*
		//ServiceTarget serviceTarget = super.sleeContainer.getServiceController().getServiceContainer();
		ServiceName serviceName = super.sleeContainer.getServiceController().getName();
		if (serviceName != null) {
			logger.info("serviceName: "+serviceName);

			//bind
			try {
				InitialContext ctx = new InitialContext();
				WritableServiceBasedNamingStore.pushOwner(serviceName);
				ctx.bind("java:global" + this.getJNDIName(), this);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				WritableServiceBasedNamingStore.popOwner();
			}
		}
		*/
	}

	@Override
	public void sleeShutdown() {

        /*
		try {
			registry.unbindFromJndi("java:"+this.getJNDIName());
		} catch (Throwable t) {
			t.printStackTrace();
		}
		*/

		/*
		//unbind
		try {
			//Context ctx;
			//ctx = (Context) new InitialContext(); //.lookup("jndi:");
			//Util.unbind(ctx, "jndi:"+this.jndiName);

			NamingContext ctx = new InitialContext(null);
			ctx.unbind("jndi:"+this.jndiName);

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		*/
	}

}