/*
 * 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:17:44:15 2009-01-25

 * Project: restcomm-jainslee-server-core

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

import java.io.File;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.slee.ComponentID;
import javax.slee.EventTypeID;
import javax.slee.SbbID;
import javax.slee.ServiceID;
import javax.slee.management.DeployableUnitDescriptor;
import javax.slee.management.DeployableUnitID;
import javax.slee.management.LibraryID;
import javax.slee.profile.ProfileSpecificationID;
import javax.slee.resource.ResourceAdaptorID;
import javax.slee.resource.ResourceAdaptorTypeID;

import org.mobicents.slee.container.component.AbstractSleeComponent;
import org.mobicents.slee.container.component.ComponentRepository;
import org.mobicents.slee.container.component.SleeComponent;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.DeployableUnitDescriptorImpl;
import org.mobicents.slee.container.component.du.DeployableUnit;
import org.mobicents.slee.container.component.event.EventTypeComponent;
import org.mobicents.slee.container.component.library.LibraryComponent;
import org.mobicents.slee.container.component.profile.ProfileSpecificationComponent;
import org.mobicents.slee.container.component.ra.ResourceAdaptorComponent;
import org.mobicents.slee.container.component.ratype.ResourceAdaptorTypeComponent;
import org.mobicents.slee.container.component.sbb.SbbComponent;
import org.mobicents.slee.container.component.service.ServiceComponent;

/**
 * Start time:17:44:15 2009-01-25

 * Project: restcomm-jainslee-server-core

 *
 * @author baranowb - Bartosz Baranowski
 *
 * @author  Alexandre Mendonca
 */
public class DeployableUnitImpl implements DeployableUnit {

	/**
	 * the DU id
	 */
	private final DeployableUnitID id;

	/**
	 * the DU descriptor
	 */
	private final DeployableUnitDescriptorImpl descriptor;

	/**
	 * the DU repository, provides an extended view of the container's component
	 * repository
	 */
	private final DeployableUnitRepositoryImpl repository;

	/**
	 * the temp dir where the DU is installed
	 */
	private final File deploymentDir;

	/**
	 * the DU event type components
	 */
	private final Map<EventTypeID, EventTypeComponent> eventTypeComponents = new HashMap<EventTypeID, EventTypeComponent>();

	/**
	 * the DU library components
	 */
	private final Map<LibraryID, LibraryComponent> libraryComponents = new HashMap<LibraryID, LibraryComponent>();

	/**
	 * the DU profile spec components
	 */
	private final Map<ProfileSpecificationID, ProfileSpecificationComponent> profileSpecificationComponents = new HashMap<ProfileSpecificationID, ProfileSpecificationComponent>();

	/**
	 * the DU ra components
	 */
	private final Map<ResourceAdaptorID, ResourceAdaptorComponent> resourceAdaptorComponents = new HashMap<ResourceAdaptorID, ResourceAdaptorComponent>();

	/**
	 * the DU ratype components
	 */
	private final Map<ResourceAdaptorTypeID, ResourceAdaptorTypeComponent> resourceAdaptorTypeComponents = new HashMap<ResourceAdaptorTypeID, ResourceAdaptorTypeComponent>();

	/**
	 * the DU sbb components
	 */
	private final Map<SbbID, SbbComponent> sbbComponents = new HashMap<SbbID, SbbComponent>();

	/**
	 * the DU service components
	 */
	private final Map<ServiceID, ServiceComponent> serviceComponents = new HashMap<ServiceID, ServiceComponent>();

	/**
	 * the date this deployable unit was built
	 */
	private final Date date = new Date();

	public DeployableUnitImpl(DeployableUnitID deployableUnitID,
			DeployableUnitDescriptorImpl duDescriptor,
			ComponentRepository componentRepository, File deploymentDir) {
		if (deployableUnitID == null) {
			throw new NullPointerException("null deployableUnitID");
		}
		if (duDescriptor == null) {
			throw new NullPointerException("null duDescriptor");
		}
		if (componentRepository == null) {
			throw new NullPointerException("null componentRepository");
		}
		if (deploymentDir == null) {
			throw new NullPointerException("null deploymentDir");
		}
		this.id = deployableUnitID;
		this.descriptor = duDescriptor;
		this.repository = new DeployableUnitRepositoryImpl(this,
				componentRepository);
		this.deploymentDir = deploymentDir;
	}

	/**
	 * Retrieves the DU descriptor
	 *
	 * @return
	 */
	public DeployableUnitDescriptorImpl getDeployableUnitDescriptor() {
		return descriptor;
	}

	/**
	 * Retrieves the DU id
	 *
	 * @return
	 */
	public DeployableUnitID getDeployableUnitID() {
		return id;
	}

	/**
	 * Retrieves the DU component repository
	 *
	 * @return
	 */
	public DeployableUnitRepositoryImpl getDeployableUnitRepository() {
		return repository;
	}

	/**
	 * Retrieves the temp dir where the DU is installed
	 *
	 * @return
	 */
	public File getDeploymentDir() {
		return deploymentDir;
	}

	/**
	 * Retrieves the DU event type components
	 *
	 * @return
	 */
	public Map<EventTypeID, EventTypeComponent> getEventTypeComponents() {
		return eventTypeComponents;
	}

	/**
	 * Retrieves the DU library components
	 *
	 * @return
	 */
	public Map<LibraryID, LibraryComponent> getLibraryComponents() {
		return libraryComponents;
	}

	/**
	 * Retrieves the DU profile spec components
	 *
	 * @return
	 */
	public Map<ProfileSpecificationID, ProfileSpecificationComponent> getProfileSpecificationComponents() {
		return profileSpecificationComponents;
	}

	/**
	 * Retrieves the DU ra components
	 *
	 * @return
	 */
	public Map<ResourceAdaptorID, ResourceAdaptorComponent> getResourceAdaptorComponents() {
		return resourceAdaptorComponents;
	}

	/**
	 * Retrieves the DU ratype components
	 *
	 * @return
	 */
	public Map<ResourceAdaptorTypeID, ResourceAdaptorTypeComponent> getResourceAdaptorTypeComponents() {
		return resourceAdaptorTypeComponents;
	}

	/**
	 * Retrieves the DU sbb components
	 *
	 * @return
	 */
	public Map<SbbID, SbbComponent> getSbbComponents() {
		return sbbComponents;
	}

	/**
	 * Retrieves the DU service components
	 *
	 * @return
	 */
	public Map<ServiceID, ServiceComponent> getServiceComponents() {
		return serviceComponents;
	}

	/**
	 * Returns an unmodifiable set with all {@link AbstractSleeComponent}s of the
	 * deployable unit.
	 *
	 * @return
	 */
	public Set<SleeComponent> getDeployableUnitComponents() {
		Set<SleeComponent> result = new HashSet<SleeComponent>();
		result.addAll(getEventTypeComponents().values());
		result.addAll(getLibraryComponents().values());
		result.addAll(getProfileSpecificationComponents().values());
		result.addAll(getResourceAdaptorComponents().values());
		result.addAll(getResourceAdaptorTypeComponents().values());
		result.addAll(getSbbComponents().values());
		result.addAll(getServiceComponents().values());
		return Collections.unmodifiableSet(result);
	}

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

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

	/**
	 * Undeploys this unit
	 */
	public void undeploy() {
		// remove components
		for (SleeComponent component : getDeployableUnitComponents()) {
			component.undeployed();
		}
		// now delete the deployment dir
		deletePath(getDeploymentDir());
	}

	/**
	 * deletes the whole path, going through directories
	 *
	 * @param path
	 */
	private void deletePath(File path) {
		if (path.isDirectory()) {
			File[] files = path.listFiles();
			if (files != null) {
				for (File file : files) {
					deletePath(file);
				}
			}
		}
		path.delete();
	}

	/**
	 * Returns the {@link DeployableUnitDescriptor} for this deployable unit.
	 *
	 * @return
	 */
	public javax.slee.management.DeployableUnitDescriptor getSpecsDeployableUnitDescriptor() {
		Set<ComponentID> componentIDs = new HashSet<ComponentID>();
		for (SleeComponent component : getDeployableUnitComponents()) {
			componentIDs.add(component.getComponentID());
		}
		return new DeployableUnitDescriptor(getDeployableUnitID(), date,
				componentIDs.toArray(new ComponentID[0]));
	}

}


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

import org.mobicents.slee.container.activity.ActivityContextHandle;
import org.mobicents.slee.container.event.EventUnreferencedCallback;
import org.mobicents.slee.runtime.activity.ActivityContextFactoryImpl;
import org.mobicents.slee.runtime.activity.ActivityContextImpl;

/**
 * @author martins
 *
 */
public class ActivityEndEventUnreferencedCallback implements EventUnreferencedCallback {

	private final ActivityContextHandle ach;
	private final ActivityContextFactoryImpl factory;

	/**
	 * @param ach
	 * @param factory
	 */
	public ActivityEndEventUnreferencedCallback(ActivityContextHandle ach,
			ActivityContextFactoryImpl factory) {
		this.ach = ach;
		this.factory = factory;
	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.container.event.EventUnreferencedCallback#eventUnreferenced()
	 */
	public void eventUnreferenced() {
		ActivityContextImpl ac = factory.getActivityContext(ach);
		if(ac != null) {
			ac.activityEnded();
		}
	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.container.event.EventUnreferencedCallback#requiresTransaction()
	 */
	public boolean requiresTransaction() {
		return true;
	}

}


/*
 * 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.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

import org.infinispan.remoting.transport.Address;
import org.mobicents.slee.container.activity.ActivityContextHandle;
import org.mobicents.slee.container.activity.ActivityType;
import org.mobicents.slee.runtime.facilities.profile.ProfileTableActivityHandleImpl;
import org.mobicents.slee.runtime.facilities.profile.ProfileTableActivityImpl;

/**
 * @author martins
 *
 */
public class ProfileTableActivityContextHandle implements ActivityContextHandle {

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

	private ProfileTableActivityHandleImpl activityHandle;

	private ProfileTableActivityImpl activityObject;

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

	}

	/**
	 *
	 */
	public ProfileTableActivityContextHandle(
			ProfileTableActivityHandleImpl activityHandle) {
		this.activityHandle = activityHandle;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.runtime.activity.ActivityContextHandle#getActivity()
	 */
	public ProfileTableActivityImpl getActivityObject() {
		if (activityObject == null) {
			activityObject = new ProfileTableActivityImpl(activityHandle);
		}
		return activityObject;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.runtime.activity.ActivityContextHandle#getActivityHandle
	 * ()
	 */
	public ProfileTableActivityHandleImpl getActivityHandle() {
		return activityHandle;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.runtime.activity.ActivityContextHandle#getActivityType
	 * ()
	 */
	public ActivityType getActivityType() {
		return ActivityType.PTABLE;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (obj.getClass() == this.getClass()) {
			final ProfileTableActivityContextHandle other = (ProfileTableActivityContextHandle) obj;
			return other.activityHandle.equals(this.activityHandle);
		} else {
			return false;
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		return activityHandle.hashCode();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return new StringBuilder("ACH=").append(getActivityType()).append('>')
				.append(activityHandle).toString();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
	 */
	@Override
	public void readExternal(ObjectInput in) throws IOException,
			ClassNotFoundException {
		this.activityHandle = new ProfileTableActivityHandleImpl(in.readUTF(),
				(Address) in.readObject());
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
	 */
	@Override
	public void writeExternal(ObjectOutput out) throws IOException {
		out.writeUTF(activityHandle.getProfileTable());
		out.writeObject(activityHandle.getClusterLocalAddress());
	}
}


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

import java.beans.Introspector;
import java.util.HashSet;
import java.util.Set;

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

import javax.slee.management.ManagementException;
import javax.slee.management.NotificationSource;
import javax.slee.usage.UsageNotificationManagerMBean;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.component.ClassPool;
import org.mobicents.slee.container.component.SleeComponentWithUsageParametersInterface;
import org.mobicents.slee.container.management.jmx.UsageNotificationManagerMBeanImpl;

/**
 * Generator for the concrete usage usage parameter mbean.
 * @author F.Moggia
 * @author Michele La Porta
 * @author martins
 */
public class ConcreteUsageNotificationManagerMBeanGenerator {

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

    private final SleeComponentWithUsageParametersInterface component;

    public ConcreteUsageNotificationManagerMBeanGenerator(SleeComponentWithUsageParametersInterface 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 usageMBeanInterface, CtClass notificationSource,CtClass usageComponent)
            throws Exception {

        CtConstructor ctCons = new CtConstructor(new CtClass[]{usageMBeanInterface,notificationSource,usageComponent}, concreteClass);
        ctCons.setBody("{ super($1,$2,$3); }");
        concreteClass.addConstructor(ctCons);

    }

    public void generateConcreteUsageNotificationManagerMBean(
            ) throws Exception {

    	Class<?> interfaceClass = component.getUsageParametersInterface();
        if (interfaceClass == null)
            return;

        ClassPool classPool = component.getClassPool();

        String usageParamInterfaceName = interfaceClass.getName();
        CtClass usageParamInterface = classPool.get(usageParamInterfaceName);

        CtClass usageMBeanInterface = classPool.get(UsageNotificationManagerMBean.class
                .getName());
        CtClass usageMBeanImplClass = classPool.get(UsageNotificationManagerMBeanImpl.class
                .getName());

        // generate the mbean interface
        String concreteMBeanInterfaceName = usageParamInterfaceName + "NotificationManagerMBean";
        CtClass ctInterface = classPool.makeInterface(concreteMBeanInterfaceName);
		ctInterface.addInterface(usageMBeanInterface);
        // generate the mbean class
		String concreteMBeanClassName = usageParamInterfaceName + "NotificationManagerMBeanImpl";
        CtClass ctClass = classPool.makeClass(concreteMBeanClassName);
        ctClass.setSuperclass(usageMBeanImplClass);
        ConcreteClassGeneratorUtils.createInterfaceLinks(ctClass,new CtClass[]{ctInterface});

        if (logger.isTraceEnabled()) {
        	logger.trace("generating "+concreteMBeanInterfaceName+" and "+concreteMBeanClassName);
        }

        // create constructor
        this.createConstructor(ctClass, classPool.get(Class.class.getName()),classPool.get(NotificationSource.class
                .getName()),classPool.get(SleeComponentWithUsageParametersInterface.class
                        .getName()));

        CtMethod[] methods = usageParamInterface.getMethods();

        Set<String> userParams = new HashSet<String>();
        for (CtMethod ctMethod : methods) {
        	if (!ctMethod.getDeclaringClass().getName().equals(Object.class.getName())) {
        		if (ctMethod.getName().startsWith("increment")) {
        			userParams.add(ctMethod.getName().substring("increment".length()));
        		}
        		else if (ctMethod.getName().startsWith("sample")) {
        			userParams.add(ctMethod.getName().substring("sample".length()));
        		}
        		else if (ctMethod.getName().startsWith("get")) {
        			userParams.add(ctMethod.getName().substring("get".length()));
        		}
        	}
        }

        for(String userParam : userParams) {
        	generateInterfaceMethod(ctInterface, userParam);
            generateConcreteMethod(ctClass, userParam);
        }

        String deploymentPathStr = component.getDeploymentDir().getAbsolutePath();
        ctInterface.writeFile(deploymentPathStr);
        logger.trace("Writing file " + concreteMBeanInterfaceName);
        ctClass.writeFile(deploymentPathStr);
        logger.trace("Writing file " + concreteMBeanClassName);

        component.setUsageNotificationManagerMBeanConcreteInterface(Thread.currentThread().getContextClassLoader().loadClass(concreteMBeanInterfaceName));
        component.setUsageNotificationManagerMBeanImplConcreteClass(Thread.currentThread().getContextClassLoader().loadClass(concreteMBeanClassName));

        ctInterface.defrost();
        ctClass.defrost();
    }

    private void generateConcreteMethod(CtClass ctClass, String userParamName) throws Exception{

        String userParamNameLowerCase = Introspector.decapitalize(userParamName);

        String getterBody = "public boolean get" + userParamName + "NotificationsEnabled"
                    + "() throws " + ManagementException.class.getName() + " {"
                    + "return getNotificationsEnabled(\""+userParamNameLowerCase+"\");"
                    + "}";
        if (logger.isTraceEnabled())
        	logger.trace("getNotificationsEnabled method for user param "+userParamName+" :\n" + getterBody);
        CtMethod getterMethod = CtNewMethod.make(getterBody, ctClass);
        ctClass.addMethod(getterMethod);

        String setterBody = "public void set" + userParamName + "NotificationsEnabled"
        + "(boolean enabled) throws " + ManagementException.class.getName() + " {"
        + " setNotificationsEnabled(\""+userParamNameLowerCase+"\",enabled);"
        + "}";
        if (logger.isTraceEnabled())
        	logger.trace("setNotificationsEnabled method for user param "+userParamName+" :\n" + setterBody);
        CtMethod setterMethod = CtNewMethod.make(setterBody, ctClass);
        ctClass.addMethod(setterMethod);
    }

    private void generateInterfaceMethod(CtClass ctClass,  String userParamName)
            throws Exception {

        ClassPool classPool = component.getClassPool();
        CtClass managementExceptionClass = classPool.get(ManagementException.class.getName());

       // add the getter method
       CtClass[] getterParameters = {};
       CtClass[] getterExceptions = {managementExceptionClass};
       CtMethod getterMethod = CtNewMethod.abstractMethod(CtClass.booleanType,
                    "get" + userParamName + "NotificationsEnabled",
                    getterParameters,
                    getterExceptions,
                    ctClass);
       ctClass.addMethod(getterMethod);
       // add the setter method
       CtClass[] setterParameters = {CtClass.booleanType};
       CtClass[] setterExceptions = {managementExceptionClass};
       CtMethod setterMethod = CtNewMethod.abstractMethod(CtClass.voidType,
                    "set" + userParamName + "NotificationsEnabled",
                    setterParameters,
                    setterExceptions,
                    ctClass);
       ctClass.addMethod(setterMethod);
    }

}


/*
 * 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 org.mobicents.slee.container.congestion.CongestionControlImpl;

/**
 * Configuration of the congestion control module.
 * @author martins
 *
 */
public class CongestionControlConfiguration implements CongestionControlConfigurationMBean {

	private int minFreeMemoryToTurnOff;

	private int minFreeMemoryToTurnOn;

	private int periodBetweenChecks;

	private boolean refuseStartActivity;

	private boolean refuseFireEvent;

	private CongestionControlImpl congestureControl;

	/**
	 *
	 * @return
	 */
	public CongestionControlImpl getCongestureControl() {
		return congestureControl;
	}

	/**
	 *
	 * @param congestureControl
	 */
	public void setCongestionControl(CongestionControlImpl congestureControl) {
		this.congestureControl = congestureControl;
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.CongestionControlConfigurationMBean#getMinFreeMemoryToTurnOn()
	 */
	public int getMinFreeMemoryToTurnOn() {
		return minFreeMemoryToTurnOn;
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.CongestionControlConfigurationMBean#setMinFreeMemoryToTurnOn(int)
	 */
	public void setMinFreeMemoryToTurnOn(int minFreeMemoryToTurnOn) throws IllegalArgumentException {
		if (minFreeMemoryToTurnOn < 0 || minFreeMemoryToTurnOn > 100) {
			throw new IllegalArgumentException("param value must be within 0 - 100%");
		}
		this.minFreeMemoryToTurnOn = minFreeMemoryToTurnOn;
		if (congestureControl != null) {
			congestureControl.configurationUpdate();
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.CongestionControlConfigurationMBean#getMinFreeMemoryToTurnOff()
	 */
	public int getMinFreeMemoryToTurnOff() {
		return minFreeMemoryToTurnOff;
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.CongestionControlConfigurationMBean#setMinFreeMemoryToTurnOff(int)
	 */
	public void setMinFreeMemoryToTurnOff(int minFreeMemoryToTurnOff) throws IllegalArgumentException {
		if (minFreeMemoryToTurnOff < 0 || minFreeMemoryToTurnOff > 100) {
			throw new IllegalArgumentException("param value must be within 0 - 100%");
		}
		this.minFreeMemoryToTurnOff = minFreeMemoryToTurnOff;
		if (congestureControl != null) {
			congestureControl.configurationUpdate();
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.CongestionControlConfigurationMBean#getPeriodBetweenChecks()
	 */
	public int getPeriodBetweenChecks() {
		return periodBetweenChecks;
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.CongestionControlConfigurationMBean#setPeriodBetweenChecks(int)
	 */
	public void setPeriodBetweenChecks(int periodBetweenChecks) throws IllegalArgumentException {
		if (periodBetweenChecks < 0) {
			throw new IllegalArgumentException("param value must not be negative");
		}
		this.periodBetweenChecks = periodBetweenChecks;
		if (congestureControl != null) {
			congestureControl.configurationUpdate();
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.CongestionControlConfigurationMBean#isRefuseStartActivity()
	 */
	public boolean isRefuseStartActivity() {
		return refuseStartActivity;
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.CongestionControlConfigurationMBean#setRefuseStartActivity(boolean)
	 */
	public void setRefuseStartActivity(boolean refuseStartActivity) {
		this.refuseStartActivity = refuseStartActivity;
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.CongestionControlConfigurationMBean#isRefuseFireEvent()
	 */
	public boolean isRefuseFireEvent() {
		return refuseFireEvent;
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.CongestionControlConfigurationMBean#setRefuseFireEvent(boolean)
	 */
	public void setRefuseFireEvent(boolean refuseFireEvent) {
		this.refuseFireEvent = refuseFireEvent;
	}

	@Override
	public String toString() {
		return "periodBetweenChecks = "+periodBetweenChecks+", minFreeMemoryToTurnOn = "+minFreeMemoryToTurnOn+"%, minFreeMemoryToTurnOff = "+minFreeMemoryToTurnOff+"%, refuseStartActivity = "+refuseStartActivity+", refuseFireEvent = "+refuseFireEvent;
	}
}


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

package org.mobicents.slee.container.deployment;

import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.Modifier;
import javassist.NotFoundException;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.slee.EventContext;
import javax.slee.EventTypeID;
import javax.slee.SLEEException;
import javax.slee.Sbb;
import javax.slee.SbbLocalObject;
import javax.slee.management.DeploymentException;
import javax.slee.profile.ProfileLocalObject;

import org.apache.log4j.Logger;
import org.mobicents.slee.ActivityContextInterfaceExt;
import org.mobicents.slee.container.activity.ActivityContextInterface;
import org.mobicents.slee.container.component.ClassPool;
import org.mobicents.slee.container.component.sbb.AbstractSbbClassInfo;
import org.mobicents.slee.container.component.sbb.CMPFieldDescriptor;
import org.mobicents.slee.container.component.sbb.EventEntryDescriptor;
import org.mobicents.slee.container.component.sbb.GetChildRelationMethodDescriptor;
import org.mobicents.slee.container.component.sbb.GetProfileCMPMethodDescriptor;
import org.mobicents.slee.container.component.sbb.SbbAbstractClassDescriptor;
import org.mobicents.slee.container.component.sbb.SbbComponent;
import org.mobicents.slee.container.management.jmx.MobicentsManagementMBean;
import org.mobicents.slee.container.sbb.SbbObjectState;
import org.mobicents.slee.container.sbbentity.SbbEntity;
import org.mobicents.slee.runtime.sbb.SbbAbstractMethodHandler;
import org.mobicents.slee.runtime.sbb.SbbConcrete;
import org.mobicents.slee.runtime.sbb.SbbLocalObjectImpl;

/**
 * Class generating the sbb concrete class from a sbb abstract class provided by
 * a sbb developer
 *
 *
 * @author DERUELLE Jean <a
 *         href="mailto:jean.deruelle@gmail.com">jean.deruelle@gmail.com </a>
 * @author M. Ranganathan
 * @author Ivelin Ivanov
 * @author Stefano Gamma
 * @author Eduardo Martins (v2)
 *
 */
public class ConcreteSbbGenerator {

	/**
	 * configuration from bean
	 */
	private Boolean initializeReferenceDataTypesWithNull = false;

	/**
	 * the sbb component
	 */
	private final SbbComponent sbbComponent;

	/**
	 * the sbb abstract class used to generate the concrete class
	 */
	private CtClass sbbAbstractClass = null;

	/**
	 * the sbb concrete class to generate
	 */
	private CtClass sbbConcreteClass = null;

	/**
	 * Logger to logg information
	 */
	private static Logger logger = null;

	/**
	 * the sbb abstract methods used to generate the concrete class methods
	 */
	private Map<?,?> abstractMethods = null;

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

	private Map<?,?> superClassesAbstractMethods;

	/**
	 * The path where classes will reside
	 */
	private final String deployDir;

	static {
		logger = Logger.getLogger(ConcreteSbbGenerator.class);
	}

	/**
	 * Constructor
	 */
	public ConcreteSbbGenerator(SbbComponent sbbComponent) {
		// get configuration properties from bean
		try {
			//MBeanServerConnection mbeanServer = (MBeanServerConnection) new InitialContext().lookup("jmx/rmi/RMIAdaptor");
			MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
			this.initializeReferenceDataTypesWithNull = (Boolean) mbeanServer.
				getAttribute(new ObjectName(MobicentsManagementMBean.OBJECT_NAME), "InitializeReferenceDataTypesWithNull");
		}
		catch (Exception e) {
			logger.error("InitializeReferenceDataTypesWithNull is not configured in jboss-beans.xml. Exception message: " + e.getMessage());
		}

		this.sbbComponent = sbbComponent;
		this.deployDir = sbbComponent.getDeploymentDir().getAbsolutePath();
		this.pool = sbbComponent.getClassPool();

		// FIXED: NPE when accessing not initialized CMP
		// see https://github.com/RestComm/jain-slee/issues/87
		// import package javax.slee for javax.slee.TransactionRequiredLocalException
		this.pool.getClassPool().importPackage("javax.slee");
	}

	/**
	 * Generate the concrete sbb Class
	 *
	 * @return the concrete sbb class
	 */
	public void generateConcreteSbb() throws DeploymentException {
		String sbbAbstractClassName = sbbComponent.getAbstractSbbClass()
				.getName();
		String sbbConcreteClassName = ConcreteClassGeneratorUtils
				.getSbbConcreteClassName(sbbAbstractClassName);

		sbbConcreteClass = pool.makeClass(sbbConcreteClassName);

		try {

			try {
				sbbAbstractClass = pool.get(sbbAbstractClassName);
			} catch (NotFoundException nfe) {
				throw new DeploymentException(nfe.getMessage(), nfe);
			}

			generateAbstractSbbClassInfo();

			try {
				ConcreteClassGeneratorUtils.createInterfaceLinks(
						sbbConcreteClass, new CtClass[] { pool
								.get(SbbConcrete.class.getName()) });
			} catch (NotFoundException nfe) {
				throw new DeploymentException(nfe.getMessage(), nfe);
			}

			ConcreteClassGeneratorUtils.createInheritanceLink(sbbConcreteClass,
					sbbAbstractClass);

			abstractMethods = ClassUtils
					.getAbstractMethodsFromClass(sbbAbstractClass);
			superClassesAbstractMethods = ClassUtils
					.getSuperClassesAbstractMethodsFromClass(sbbAbstractClass);

			try {
				createFields(new CtClass[] {
						pool.get(SbbEntity.class.getName()),
						pool.get(SbbObjectState.class.getName()) });

				CtClass[] parameters = new CtClass[] { pool.get(SbbEntity.class
						.getName()) };
				createSbbEntityGetterAndSetter(sbbConcreteClass);
				createDefaultUsageParameterGetter(sbbConcreteClass);
				createNamedUsageParameterGetter(sbbConcreteClass);
				createDefaultConstructor();
				createConstructorWithParameter(parameters);

			} catch (NotFoundException nfe) {
				logger.error("Constructor With Parameter not created");
				throw new DeploymentException("Constructor not created.", nfe);
			}

			SbbAbstractClassDescriptor mSbbAbstractClass = sbbComponent.getDescriptor()
					.getSbbAbstractClass();
			createCMPAccessors(mSbbAbstractClass.getCmpFields());
			createGetChildRelationsMethod(mSbbAbstractClass
					.getChildRelationMethods().values());
			createGetProfileCMPMethods(mSbbAbstractClass.getProfileCMPMethods()
					.values());
			createFireEventMethods(sbbComponent.getDescriptor()
					.getEventEntries().values());
			// GetUsageParametersMethod[] usageParameters=
			// sbbDeploymentDescriptor.getUsageParametersMethods();

			// if the activity context interface has been defined in the
			// descriptor
			// file
			// then generates the concrete class of the activity context
			// interface
			// and implements the narrow method

			if (sbbComponent.getDescriptor()
					.getSbbActivityContextInterface() != null) {
				Class<?> activityContextInterfaceClass = null;
				try {
					activityContextInterfaceClass = Thread.currentThread()
							.getContextClassLoader().loadClass(
									sbbComponent.getDescriptor()
									.getSbbActivityContextInterface());
				} catch (ClassNotFoundException e2) {
					String s = "Error creating constructor -  class not found";
					logger.error(s, e2);
					throw new DeploymentException(s, e2);
				}
				// Check the activity context interface for illegal method
				// names.
				Method[] methods = activityContextInterfaceClass.getMethods();
				ArrayList<String> allSetters = new ArrayList<String>();
				ArrayList<String> missingSetters = new ArrayList<String>();
				if (methods != null) {
					for (int i = 0; i < methods.length; i++) {
						if (!methods[i].getDeclaringClass().getName().equals(
								javax.slee.ActivityContextInterface.class.getName()) && !methods[i].getDeclaringClass().getName().equals(
										ActivityContextInterfaceExt.class.getName())) {
							String methodName = methods[i].getName();
							// setters should have a single parameter and should
							// return void type.
							if (methodName.startsWith("set")) {
								Class<?>[] args = methods[i].getParameterTypes();

								// setter should only have one argument
								if (args.length != 1)
									throw new DeploymentException(
											"Setter method '"
													+ methodName
													+ "' should only have one argument.");

								// setter return type should be void
								Class<?> returnClass = methods[i].getReturnType();
								if (!returnClass.equals(Void.TYPE))
									throw new DeploymentException(
											"Setter method '"
													+ methodName
													+ "' return type should be void.");

								allSetters.add(methodName);
							} else if (methodName.startsWith("get")) {
								Class<?>[] args = methods[i].getParameterTypes();

								// getter should have no parameters.
								if (args != null && args.length != 0)
									throw new DeploymentException(
											"Getter method '"
													+ methodName
													+ "' should have no parameters.");

								// getter return type should not be void
								if (methods[i].getReturnType()
										.equals(Void.TYPE))
									throw new DeploymentException(
											"Getter method '"
													+ methodName
													+ "' return type cannot be void.");

								String setterName = methodName.replaceFirst(
										"get", "set");

								try {
									activityContextInterfaceClass.getMethod(
											setterName, methods[i]
													.getReturnType());
								} catch (NoSuchMethodException nsme) {
									missingSetters.add(setterName);
								}
							} else {
								throw new DeploymentException(
										"Invalid method '"
												+ methodName
												+ "' in SBB Activity Context Interface.");
							}
						}

					}

					// Check if the missing setters aren't defined with
					// different arg
					for (String setter : missingSetters)
						if (allSetters.contains(setter))
							throw new DeploymentException(
									"Getter argument type and"
											+ " setter return type for attribute '"
											+ setter.replaceFirst("set", "")
													.toLowerCase()
											+ "' must be the same.");
				}
				/*
				 * CtMethod[] abstractClassMethods =
				 * sbbAbstractClass.getDeclaredMethods();
				 *
				 * for ( int i = 0; i < abstractClassMethods.length; i ++ ) {
				 * CtMethod ctMethod = abstractClassMethods[i]; if ( !
				 * Modifier.isAbstract(ctMethod.getModifiers())) {
				 * this.createMethodWrapper(sbbConcreteClass,ctMethod); } }
				 */

				// check if the concrete class has already been generated.
				// if that the case, the guess is that the concrete class is a
				// safe
				// one
				// and so it is not generated again
				// avoid also problems of class already loaded from the class
				// loader
				//
				CtClass activityContextInterface = null;
				try {
					activityContextInterface = pool
							.get(activityContextInterfaceClass.getName());

					createField(activityContextInterface,
							"sbbActivityContextInterface");

					this
							.createSetActivityContextInterfaceMethod(activityContextInterface);

					ConcreteActivityContextInterfaceGenerator concreteActivityContextInterfaceGenerator = new ConcreteActivityContextInterfaceGenerator(
							activityContextInterfaceClass.getName(), deployDir,
							pool);

					Class<?> concreteActivityContextInterfaceClass = concreteActivityContextInterfaceGenerator
							.generateActivityContextInterfaceConcreteClass();

					createGetSbbActivityContextInterfaceMethod(
							activityContextInterface,
							concreteActivityContextInterfaceClass);
					// set the concrete activity context interface class in
					// the
					// descriptor
					if (logger.isDebugEnabled()) {
						logger.debug("SETTING ACI concrete class  "
								+ concreteActivityContextInterfaceClass
								+ " in " + sbbComponent);
					}
					sbbComponent
							.setActivityContextInterfaceConcreteClass(concreteActivityContextInterfaceClass);

				} catch (NotFoundException nfe) {
					logger
							.error("Narrow Activity context interface method and "
									+ "activity context interface concrete class not created");
					throw new DeploymentException(nfe.getMessage(), nfe);
				} finally {
					/*
					 * if (activityContextInterface != null) {
					 * activityContextInterface.detach(); }
					 */
				}

			}
			// if the sbb local object has been defined in the descriptor file
			// then generates the concrete class of the sbb local object
			// and implements the narrow method
			Class<?> sbbLocalInterfaceClass = sbbComponent
					.getSbbLocalInterfaceClass();
			if (logger.isTraceEnabled()) {
	            logger.trace("Sbb Local Object interface :"
						+ sbbLocalInterfaceClass);
			}
			if (sbbLocalInterfaceClass != null
					&& !sbbLocalInterfaceClass.getName().equals(
					"javax.slee.SbbLocalObject")) {
				try {
					pool.get(sbbLocalInterfaceClass.getName());
					ConcreteSbbLocalObjectGenerator concreteSbbLocalObjectGenerator = new ConcreteSbbLocalObjectGenerator(
							sbbLocalInterfaceClass.getName(),
							sbbAbstractClassName, this.deployDir, pool);
					Class<?> concreteSbbLocalObjectClass = concreteSbbLocalObjectGenerator
					.generateSbbLocalObjectConcreteClass();
					// set the sbb Local object class in the descriptor
					sbbComponent
					.setSbbLocalInterfaceConcreteClass(concreteSbbLocalObjectClass);

				} catch (NotFoundException nfe) {
					String s = "sbb Local Object concrete class not created for interface "
						+ sbbLocalInterfaceClass.getName();
					throw new DeploymentException(s, nfe);
				}

			}
			// if there is no interface defined in the descriptor for sbb local
			// object
			// then the slee implementation is taken
			else {

				try {
					sbbComponent
							.setSbbLocalInterfaceClass(SbbLocalObject.class);
					sbbComponent
							.setSbbLocalInterfaceConcreteClass(SbbLocalObjectImpl.class);
				} catch (Exception e) {
					throw new DeploymentException(e.getMessage(), e);
				}
			}
			try {
				sbbConcreteClass.writeFile(deployDir);
				// @@2.4+ -> 3.4+
				// pool.writeFile(sbbConcreteClassName, deployPath);
				if (logger.isDebugEnabled()) {
					logger.debug("Concrete Class " + sbbConcreteClassName
							+ " generated in the following path " + deployDir);
				}
			} catch (Exception e) {
				String s = "Error generating concrete class";
				throw new DeploymentException(s, e);
			}

			Class<?> clazz = null;
			try {
				clazz = Thread.currentThread().getContextClassLoader()
						.loadClass(sbbConcreteClassName);
			} catch (ClassNotFoundException e1) {
				String s = "What the heck?! Could not find generated class. Is it under the chair?";
				throw new DeploymentException(s, e1);
			}
			// set the concrete class in the descriptor
			sbbComponent.setConcreteSbbClass(clazz);

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

			}
		}

		// uh uh
		if (sbbComponent.getConcreteSbbClass() == null) {
			throw new DeploymentException(
					"concrete sbb class generation failed and I don't know why, bug bug ?!? :)");
		}
	}

	/**
	 * Generates info that indicates if a method from {@link Sbb} interface
	 * should be invoked or not, in runtime.
	 */
	private void generateAbstractSbbClassInfo() {

		CtClass sbbClass = null;
		try {
			sbbClass = pool.get(Sbb.class.getName());
		} catch (NotFoundException e) {
			throw new SLEEException(e.getMessage(), e);
		}

		AbstractSbbClassInfo abstractSbbClassInfo = sbbComponent.getAbstractSbbClassInfo();

		for (CtMethod sbbClassMethod : sbbClass.getDeclaredMethods()) {
			for (CtMethod sbbAbstractClassMethod : sbbAbstractClass
					.getMethods()) {
				if (sbbAbstractClassMethod.getName().equals(
						sbbClassMethod.getName())
						&& sbbAbstractClassMethod.getSignature().equals(
								sbbClassMethod.getSignature())) {
					// match, save info
					abstractSbbClassInfo.setInvokeInfo(sbbAbstractClassMethod
							.getMethodInfo().getName(), !sbbAbstractClassMethod
							.isEmpty());
					break;
				}
			}
		}

	}

	/**
	 * @param parameter
	 * @param parameterName
	 */
	private void createField(CtClass parameter, String parameterName) {
		// TODO Auto-generated method stub
		try {
			CtField ctField = new CtField(parameter, parameterName,
					sbbConcreteClass);
			ctField.setModifiers(Modifier.PRIVATE);
			sbbConcreteClass.addField(ctField);
		} catch (CannotCompileException cce) {
			cce.printStackTrace();
		}
	}

	/**
	 * Creates a constructor with parameters <BR>
	 * For every parameter a field of the same class is created in the concrete
	 * class And each field is gonna be initialized with the corresponding
	 * parameter
	 *
	 * @param parameters
	 *            the parameters of the constructor to add
	 * @throws DeploymentException
	 */
	protected void createConstructorWithParameter(CtClass[] parameters)
			throws DeploymentException {
		CtConstructor constructorWithParameter = new CtConstructor(parameters,
				sbbConcreteClass);
		String constructorBody = "{" + "this();";
		/*
		 * for (int i = 0; i < parameters.length; i++) { String parameterName =
		 * parameters[i].getName(); parameterName =
		 * parameterName.substring(parameterName .lastIndexOf(".") + 1); String
		 * firstCharLowerCase = parameterName.substring(0, 1) .toLowerCase();
		 * parameterName = firstCharLowerCase.concat(parameterName
		 * .substring(1));
		 *
		 * int paramNumber = i + 1; constructorBody += parameterName + "=$" +
		 * paramNumber + ";"; }
		 */
		constructorBody += "this.setSbbEntity($1);";
		constructorBody += "}";
		try {
			sbbConcreteClass.addConstructor(constructorWithParameter);
			constructorWithParameter.setBody(constructorBody);
			if (logger.isTraceEnabled()) {
	            logger.trace("ConstructorWithParameter created");
			}
		} catch (CannotCompileException e) {
			throw new DeploymentException(e.getMessage(), e);
		}
	}

	private void createFields(CtClass[] parameters) throws DeploymentException {
		for (int i = 0; i < parameters.length; i++) {
			String parameterName = parameters[i].getName();
			parameterName = parameterName.substring(parameterName
					.lastIndexOf(".") + 1);
			String firstCharLowerCase = parameterName.substring(0, 1)
					.toLowerCase();
			parameterName = firstCharLowerCase.concat(parameterName
					.substring(1));
			try {
				CtField ctField = new CtField(parameters[i], parameterName,
						sbbConcreteClass);
				ctField.setModifiers(Modifier.PRIVATE);
				sbbConcreteClass.addField(ctField);
			} catch (CannotCompileException e) {
				throw new DeploymentException(e.getMessage(), e);
			}
		}
	}

	/**
	 * Create a default constructor on the Sbb Concrete Class
	 *
	 * @throws DeploymentException
	 */
	protected void createDefaultConstructor() throws DeploymentException {

		CtConstructor defaultConstructor = new CtConstructor(null,
				sbbConcreteClass);
		// We need a "do nothing" constructor because the
		// convergence name creation method may need to actually
		// create the object instance to run the method that
		// creates the convergence name.

		String constructorBody = "{ }";

		try {
			defaultConstructor.setBody(constructorBody);
			sbbConcreteClass.addConstructor(defaultConstructor);
			logger.trace("DefaultConstructor created");
		} catch (CannotCompileException e) {
			throw new DeploymentException(e.getMessage(), e);
		}
	}

	/**
	 * Create a default usage parameter getter and setter.
	 *
	 * @param sbbConcrete
	 * @throws DeploymentException
	 */
	private void createDefaultUsageParameterGetter(CtClass sbbConcrete)
			throws DeploymentException {
		String methodName = "getDefaultSbbUsageParameterSet";
		CtMethod method = (CtMethod) abstractMethods.get(methodName);
		if (method == null) {
			method = (CtMethod) superClassesAbstractMethods.get(methodName);
		}
		if (method != null) {
			try {
				// copy method from abstract to concrete class
				CtMethod concreteMethod = CtNewMethod.copy(method,
						sbbConcreteClass, null);
				// create the method body
				String concreteMethodBody = "{ return ($r)"
						+ SbbAbstractMethodHandler.class.getName()
						+ ".getDefaultSbbUsageParameterSet(sbbEntity); }";
				if (logger.isTraceEnabled()) {
		            logger.trace("Generated method " + methodName
							+ " , body = " + concreteMethodBody);
				}
				concreteMethod.setBody(concreteMethodBody);
				sbbConcreteClass.addMethod(concreteMethod);
			} catch (CannotCompileException cce) {
				throw new SLEEException("Cannot compile method "
						+ method.getName(), cce);
			}
		}
	}

	/**
	 * Create a named usage parameter getter.
	 *
	 * @param sbbConcrete
	 * @throws DeploymentException
	 */

	private void createNamedUsageParameterGetter(CtClass sbbConcrete)
			throws DeploymentException {
		String methodName = "getSbbUsageParameterSet";
		CtMethod method = (CtMethod) abstractMethods.get(methodName);
		if (method == null) {
			method = (CtMethod) superClassesAbstractMethods.get(methodName);
		}
		if (method != null) {
			try {
				// copy method from abstract to concrete class
				CtMethod concreteMethod = CtNewMethod.copy(method,
						sbbConcreteClass, null);
				// create the method body
				String concreteMethodBody = "{ return ($r)"
						+ SbbAbstractMethodHandler.class.getName()
						+ ".getSbbUsageParameterSet(sbbEntity,$1); }";
				if (logger.isTraceEnabled()) {
		            logger.trace("Generated method " + methodName
							+ " , body = " + concreteMethodBody);
				}
				concreteMethod.setBody(concreteMethodBody);
				sbbConcreteClass.addMethod(concreteMethod);
			} catch (CannotCompileException cce) {
				throw new SLEEException("Cannot compile method "
						+ method.getName(), cce);
			}
		}
	}

	/**
	 * Create a method to retrive the entity from the SbbObject.
	 *
	 * @param sbbConcrete
	 * @throws DeploymentException
	 */
	private void createSbbEntityGetterAndSetter(CtClass sbbConcrete)
			throws DeploymentException {
		try {
			CtMethod getSbbEntity = CtNewMethod
					.make("public " + SbbEntity.class.getName()
							+ " getSbbEntity() { return this.sbbEntity; }",
							sbbConcrete);
			getSbbEntity.setModifiers(Modifier.PUBLIC);
			sbbConcrete.addMethod(getSbbEntity);
			CtMethod setSbbEntity = CtNewMethod.make(
					"public void setSbbEntity ( " + SbbEntity.class.getName()
							+ " sbbEntity )" + "{"
							+ "this.sbbEntity = sbbEntity;" + "}", sbbConcrete);

			setSbbEntity.setModifiers(Modifier.PUBLIC);
			sbbConcrete.addMethod(setSbbEntity);
		} catch (Exception e) {
			throw new DeploymentException(e.getMessage(), e);
		}
	}

	/**
	 * Create the cmp field setters and getters
	 *
	 * @param cmps
	 *            the description of the cmp fields
	 * @throws DeploymentException
	 */
	protected void createCMPAccessors(Collection<CMPFieldDescriptor> cmps)
			throws DeploymentException {

		for (CMPFieldDescriptor cmp : cmps) {
			String fieldName = cmp.getCmpFieldName();
			// Set the first char of the accessor to UpperCase to follow the
			// javabean requirements
			fieldName = fieldName.substring(0, 1).toUpperCase()
					+ fieldName.substring(1);

			String getterMethodName = "get" + fieldName;
			CtMethod getterMethod = (CtMethod) abstractMethods
					.get(getterMethodName);
			if (getterMethod == null) {
				getterMethod = (CtMethod) this.superClassesAbstractMethods
				.get(getterMethodName);
			}
			if (getterMethod == null) {
				throw new SLEEException("can't find abstract method "
						+ getterMethodName);
			}

			// generate the acessor method name sufix from type
			String getterHandlerMethodName = "getCMPFieldOfType";
			boolean getterHandlerMethodNeedResultCast = false;
			String setterHandlerMethodName = "setCMPFieldOfType";
			try {
				CtClass ctClassCmpType = getterMethod.getReturnType();
				if (ctClassCmpType.isPrimitive()) {
					// boolean, byte, char, short, int, long, float, double
					String ctClassCmpTypeName = ctClassCmpType.getName();
					if (ctClassCmpTypeName.equals(boolean.class.getName())) {
						getterHandlerMethodName += "Boolean";
					}
					else if (ctClassCmpTypeName.equals(byte.class.getName())) {
						getterHandlerMethodName += "Byte";
					}
					else if (ctClassCmpTypeName.equals(char.class.getName())) {
						getterHandlerMethodName += "Char";
					}
					else if (ctClassCmpTypeName.equals(short.class.getName())) {
						getterHandlerMethodName += "Short";
					}
					else if (ctClassCmpTypeName.equals(int.class.getName())) {
						getterHandlerMethodName += "Integer";
					}
					else if (ctClassCmpTypeName.equals(long.class.getName())) {
						getterHandlerMethodName += "Long";
					}
					else if (ctClassCmpTypeName.equals(float.class.getName())) {
						getterHandlerMethodName += "Float";
					}
					else if (ctClassCmpTypeName.equals(double.class.getName())) {
						getterHandlerMethodName += "Double";
					}
					else {
						throw new SLEEException("unexpected primitive type "
								+ ctClassCmpTypeName);
					}
					getterHandlerMethodNeedResultCast = true;
					setterHandlerMethodName += "PrimitiveOrUnknown";
				}
				else {
					// aci, event context, sbb local object, profile local object, Boolean, Byte, Char, Short, Integer, Long, Float, Double, unknown, array, enum, annotation
					if (!ctClassCmpType.isArray() && !ctClassCmpType.isEnum() && !ctClassCmpType.isAnnotation()) {
						// aci, event context, sbb local object, profile local object, Boolean, Byte, Char, Short, Integer, Long, Float, Double, unknown
						Class<?> classCmpType = Thread.currentThread().getContextClassLoader().loadClass(ctClassCmpType.getName());
						if (javax.slee.ActivityContextInterface.class.isAssignableFrom(classCmpType)) {
							getterHandlerMethodName += "ActivityContextInterface";
							setterHandlerMethodName += "ActivityContextInterface";
						}
						else if (EventContext.class.isAssignableFrom(classCmpType)) {
							getterHandlerMethodName += "EventContext";
							setterHandlerMethodName += "EventContext";
						}
						else if (ProfileLocalObject.class.isAssignableFrom(classCmpType)) {
							getterHandlerMethodName += "ProfileLocalObject";
							setterHandlerMethodName += "ProfileLocalObject";
						}
						else if (SbbLocalObject.class.isAssignableFrom(classCmpType)) {
							getterHandlerMethodName += "SbbLocalObject";
							setterHandlerMethodName += "SbbLocalObject";
						}
						else {
							// Boolean, Byte, Char, Short, Integer, Long, Float, Double, unknown
							if (this.initializeReferenceDataTypesWithNull) {
								getterHandlerMethodName += "Unknown";
								getterHandlerMethodNeedResultCast = true;
							} else { // initialized with 0
								String ctClassCmpTypeName = ctClassCmpType.getName();
								if (ctClassCmpTypeName.equals(Boolean.class.getName())) {
									getterHandlerMethodName += "Boolean";
								} else if (ctClassCmpTypeName.equals(Byte.class.getName())) {
									getterHandlerMethodName += "Byte";
								} else if (ctClassCmpTypeName.equals(Character.class.getName())) {
									getterHandlerMethodName += "Char";
								} else if (ctClassCmpTypeName.equals(Short.class.getName())) {
									getterHandlerMethodName += "Short";
								} else if (ctClassCmpTypeName.equals(Integer.class.getName())) {
									getterHandlerMethodName += "Integer";
								} else if (ctClassCmpTypeName.equals(Long.class.getName())) {
									getterHandlerMethodName += "Long";
								} else if (ctClassCmpTypeName.equals(Float.class.getName())) {
									getterHandlerMethodName += "Float";
								} else if (ctClassCmpTypeName.equals(Double.class.getName())) {
									getterHandlerMethodName += "Double";
								} else {
									getterHandlerMethodName += "Unknown";
									getterHandlerMethodNeedResultCast = true;
								}
							}
							setterHandlerMethodName += "PrimitiveOrUnknown";
						}
					}
					else {
						// array, enum, annotation == same as unknown
						getterHandlerMethodName += "Unknown";
						getterHandlerMethodNeedResultCast = true;
						setterHandlerMethodName += "PrimitiveOrUnknown";
					}
				}
			} catch (Exception cce) {
				throw new SLEEException("Cannot determine the cmp type for cmp field named "+fieldName, cce);
			}

			try {
				// copy method from abstract to concrete class
				CtMethod concreteGetterMethod = CtNewMethod.copy(getterMethod,
						sbbConcreteClass, null);
				// create the method body

				// FIXED: NPE when accessing not initialized CMP
				// see https://github.com/RestComm/jain-slee/issues/87
				String concreteGetterMethodBody = "{ "
						+ "if (sbbEntity == null) "
						+ "    throw new TransactionRequiredLocalException(\"Cannot get CMP field. SBB entity is null\");"
						+ "return " + ( getterHandlerMethodNeedResultCast ? "($r)" : "") + SbbAbstractMethodHandler.class.getName() + "." + getterHandlerMethodName+ "(sbbEntity,\"" + cmp.getCmpFieldName() + "\");"
						+ " }";
				if (logger.isTraceEnabled()) {
		            logger.trace("Generated method " + getterMethodName
							+ " , body = " + concreteGetterMethodBody);
				}
				concreteGetterMethod.setBody(concreteGetterMethodBody);
				sbbConcreteClass.addMethod(concreteGetterMethod);
			} catch (Exception cce) {
				throw new SLEEException("Cannot compile method "
						+ getterMethod.getName(), cce);
			}

			String setterMethodName = "set" + fieldName;
			CtMethod setterMethod = (CtMethod) abstractMethods
					.get(setterMethodName);
			if (setterMethod == null) {
				setterMethod = (CtMethod) this.superClassesAbstractMethods
						.get(setterMethodName);
			}
			if (setterMethod == null) {
				throw new SLEEException("can't find abstract method "
						+ setterMethodName);
			}

			try {
				// copy method from abstract to concrete class
				CtMethod concreteSetterMethod = CtNewMethod.copy(setterMethod,
						sbbConcreteClass, null);
				// create the method body

				// FIXED: NPE when accessing not initialized CMP
				// see https://github.com/RestComm/jain-slee/issues/87
				String concreteSetterMethodBody = "{ "
						+ "if (sbbEntity == null) "
						+ "    throw new TransactionRequiredLocalException(\"Cannot set CMP field. SBB entity is null\");"
						+ SbbAbstractMethodHandler.class.getName()
						+ "."+setterHandlerMethodName+"(sbbEntity,\"" + cmp.getCmpFieldName()
						+ "\",$1); }";
				if (logger.isTraceEnabled()) {
		            logger.trace("Generated method " + setterMethodName
							+ " , body = " + concreteSetterMethodBody);
				}
				concreteSetterMethod.setBody(concreteSetterMethodBody);
				sbbConcreteClass.addMethod(concreteSetterMethod);
			} catch (CannotCompileException cce) {
				throw new SLEEException("Cannot compile method "
						+ getterMethod.getName(), cce);
			}
		}

	}

	private String getEventTypeIDInstantionString(EventEntryDescriptor mEventEntry) {
		String eventTypeIDClassName = EventTypeID.class.getName();
		return eventTypeIDClassName + " eventTypeID = new "
				+ eventTypeIDClassName + "(\""
				+ mEventEntry.getEventReference().getName() + "\",\""
				+ mEventEntry.getEventReference().getVendor()
				+ "\",\""
				+ mEventEntry.getEventReference().getVersion()
				+ "\");";
	}

	/**
	 * Create the implementation of the fire event methods
	 *
	 * @param mEventEntries
	 *            the set of fire event
	 */
	protected void createFireEventMethods(Collection<EventEntryDescriptor> mEventEntries) {
		if (mEventEntries == null)
			return;
		for (EventEntryDescriptor mEventEntry : mEventEntries) {
			if (mEventEntry.isFired()) {
				String methodName = "fire" + mEventEntry.getEventName();
				CtMethod method = (CtMethod) abstractMethods.get(methodName);
				if (method == null) {
					method = (CtMethod) superClassesAbstractMethods
							.get(methodName);
				}
				if (method != null) {
					try {
						// copy method from abstract to concrete class
						CtMethod concreteMethod = CtNewMethod.copy(method,
								sbbConcreteClass, null);
						// create the method body
						String concreteMethodBody = "{";
						concreteMethodBody += getEventTypeIDInstantionString(mEventEntry);
						concreteMethodBody += SbbAbstractMethodHandler.class
								.getName()
								+ ".fireEvent(sbbEntity,eventTypeID";
						for (int i = 0; i < method.getParameterTypes().length; i++) {
							concreteMethodBody += ",$" + (i + 1);
						}
						concreteMethodBody += ");}";
						if (logger.isTraceEnabled()) {
				            logger.trace("Generated method " + methodName
									+ " , body = " + concreteMethodBody);
						}
						concreteMethod.setBody(concreteMethodBody);
						sbbConcreteClass.addMethod(concreteMethod);
					} catch (Exception e) {
						throw new SLEEException("Cannot compile method "
								+ method.getName(), e);
					}
				}
			}
		}
	}

	/**
	 * Create the get child relation method (this method redirects the call to a
	 * child relation interceptor)
	 *
	 * @param childRelations
	 *            the childRelations method to add to the concrete class
	 */
	protected void createGetChildRelationsMethod(
			Collection<GetChildRelationMethodDescriptor> childRelations) {
		if (childRelations == null)
			return;
		for (GetChildRelationMethodDescriptor childRelation : childRelations) {
			String methodName = childRelation.getChildRelationMethodName();
			CtMethod method = (CtMethod) abstractMethods.get(methodName);
			if (method == null) {
				method = (CtMethod) superClassesAbstractMethods.get(methodName);
			}
			if (method != null) {
				try {
					// copy method from abstract to concrete class
					CtMethod concreteMethod = CtNewMethod.copy(method,
							sbbConcreteClass, null);
					// create the method body
					String concreteMethodBody = "{ return "
							+ SbbAbstractMethodHandler.class.getName()
							+ ".getChildRelation(sbbEntity,\"" + methodName
							+ "\"); }";
					if (logger.isTraceEnabled()) {
			            logger.trace("Generated method " + methodName
								+ " , body = " + concreteMethodBody);
					}
					concreteMethod.setBody(concreteMethodBody);
					sbbConcreteClass.addMethod(concreteMethod);
				} catch (CannotCompileException cce) {
					throw new SLEEException("Cannot compile method "
							+ method.getName(), cce);
				}
			}
		}
	}

	/**
	 * Create the get profile CMP method (this method redirects the call to a
	 * profile cmp interceptor)
	 *
	 * @param cmpProfiles
	 *            the CMP Profiles method to add to the concrete class
	 */
	protected void createGetProfileCMPMethods(
			Collection<GetProfileCMPMethodDescriptor> cmpProfiles) {
		if (cmpProfiles == null) {
			if (logger.isTraceEnabled()) {
	            logger.trace("no CMP Profile method implementation to generate.");
			}
			return;
		}
		for (GetProfileCMPMethodDescriptor cmpProfile : cmpProfiles) {
			String methodName = cmpProfile.getProfileCmpMethodName();
			CtMethod method = (CtMethod) abstractMethods.get(methodName);
			if (method == null)
				method = (CtMethod) superClassesAbstractMethods.get(methodName);
			if (method != null)
				try {
					// copy method from abstract to concrete class
					CtMethod concreteMethod = CtNewMethod.copy(method,
							sbbConcreteClass, null);
					// create the method body
					String concreteMethodBody = "{ return "
							+ SbbAbstractMethodHandler.class.getName()
							+ ".getProfileCMPMethod(sbbEntity,\"" + methodName
							+ "\",$1); }";
					if (logger.isTraceEnabled()) {
			            logger.trace("Generated method " + methodName
								+ " , body = " + concreteMethodBody);
					}
					concreteMethod.setBody(concreteMethodBody);
					sbbConcreteClass.addMethod(concreteMethod);
				} catch (CannotCompileException cce) {
					throw new SLEEException("Cannot compile method "
							+ method.getName(), cce);
				}
		}
	}

	protected void createSetActivityContextInterfaceMethod(
			CtClass activityContextInterface) throws DeploymentException {
		String methodToAdd = "public void sbbSetActivityContextInterface( Object aci ) {"
				+ "this.sbbActivityContextInterface = ("
				+ activityContextInterface.getName() + ") aci ; } ";
		CtMethod methodTest;
		try {
			methodTest = CtNewMethod.make(methodToAdd, sbbConcreteClass);
			sbbConcreteClass.addMethod(methodTest);
			logger.trace("Method " + methodToAdd + " added");
		} catch (CannotCompileException e) {
			throw new DeploymentException(e.getMessage(), e);
		}
	}

	/**
	 * Create the narrow method to get the activity context interface
	 *
	 * @param activityContextInterface
	 *            the activity context interface return type of the narrow
	 *            method
	 * @param concreteActivityContextInterfaceClass
	 * @throws DeploymentException
	 */
	protected void createGetSbbActivityContextInterfaceMethod(
			CtClass activityContextInterface,
			Class<?> concreteActivityContextInterfaceClass)
			throws DeploymentException {
		String methodToAdd = "public "
				+ activityContextInterface.getName()
				+ " asSbbActivityContextInterface(javax.slee.ActivityContextInterface aci) {"
				+ "if(aci==null)"
				+ "     throw new "
				+ IllegalStateException.class.getName()
				+ "(\"Passed argument can not be of null value.\");"
				+ " if(sbbEntity == null || sbbEntity.getSbbObject().getState() != "
				+ SbbObjectState.class.getName() + ".READY) { throw new "
				+ IllegalStateException.class.getName()
				+ "(\"Cannot call asSbbActivityContextInterface\"); } "
				+ "else if ( aci instanceof "
				+ concreteActivityContextInterfaceClass.getName()
				+ ") return aci;" + "else return  new "
				+ concreteActivityContextInterfaceClass.getName() + " ( (" + ActivityContextInterface.class.getName() + ") $1, "
				+ "sbbEntity.getSbbComponent());" + "}";
		CtMethod methodTest;
		try {
			methodTest = CtNewMethod.make(methodToAdd, sbbConcreteClass);
			sbbConcreteClass.addMethod(methodTest);
			if (logger.isTraceEnabled()) {
				logger.trace("Method " + methodToAdd + " added");
			}
		} catch (CannotCompileException e) {
			throw new DeploymentException(e.getMessage(), e);
		}
	}

	/**
	 *
	 * @param usageParameters
	 */
	/*
	 * protected void createSbbUsageParameterInterface(
	 * GetUsageParametersMethod[] usageParameters){ }
	 */
}


package javax.slee.profile.query;

import java.util.ArrayList;

/**
 * The CompositeQueryExpression class is the base class for all dynamic
 * query expressions that are containers of other query expressions.
 */
public abstract class CompositeQueryExpression extends QueryExpression {
    /**
     * Get the query expressions that have been added to this composite expression.
     * @return the query expressions that have been added to this composite expression.
     */
    public final QueryExpression[] getExpressions() {
        return (QueryExpression[])exprs.toArray(new QueryExpression[exprs.size()]);
    }

    // protected

    /**
     * Add a query expression to this composite expression.
     * @param expr the expression to add.
     * @throws NullPointerException if expr is null.
     * @throws IllegalArgumentException if adding the query expression to this
     *        composite expression would generate a cyclic expression.
     */
    protected final void add(QueryExpression expr) throws NullPointerException, IllegalArgumentException {
        if (expr == null) throw new NullPointerException("expr is null");

        // check for cycles
        if (expr instanceof CompositeQueryExpression) {
            ((CompositeQueryExpression)expr).checkForCycles(this);
        }
        else if (expr instanceof Not) {
            ((Not)expr).checkForCycles(this);
        }

        // no cycles, so add the expression to the list
        exprs.add(expr);
    }

    // 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 all nested expressions that are composite expressions
        for (int i=0; i<exprs.size(); i++) {
            QueryExpression nested = (QueryExpression)exprs.get(i);
            if (nested instanceof CompositeQueryExpression) {
                ((CompositeQueryExpression)nested).checkForCycles(expr);
            }
            else if (nested instanceof Not) {
                ((Not)nested).checkForCycles(expr);
            }
        }
    }

    private final ArrayList exprs = new ArrayList();
}


/*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * 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;

import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NameAlreadyBoundException;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.RefAddr;
import javax.naming.StringRefAddr;
import javax.naming.spi.ObjectFactory;

/**
 * A utility class that allows one to bind a non-serializable object into a
 * local JNDI context. The binding will only be valid for the lifetime of the
 * VM in which the JNDI InitialContext lives. An example usage code snippet is:
 *

    // The non-Serializable object to bind
    Object nonserializable = ...;
    // An arbitrary key to use in the StringRefAddr. The best key is the jndi
    // name that the object will be bound under.
    String key = ...;
    // This places nonserializable into the NonSerializableFactory hashmap under key
    NonSerializableFactory.rebind(key, nonserializable);

    Context ctx = new InitialContext();
    // Bind a reference to nonserializable using NonSerializableFactory as the ObjectFactory
    String className = nonserializable.getClass().getName();
    String factory = NonSerializableFactory.class.getName();
    StringRefAddr addr = new StringRefAddr("nns", key);
    Reference memoryRef = new Reference(className, addr, factory, null);
    ctx.rebind(key, memoryRef);

 *
 * Or you can use the {@link #rebind(javax.naming.Context, String, Object)} convenience
 * method to simplify the number of steps to:
 *

    Context ctx = new InitialContext();
    // The non-Serializable object to bind
    Object nonserializable = ...;
    // The jndiName that the object will be bound into ctx with
    String jndiName = ...;
    // This places nonserializable into the NonSerializableFactory hashmap under key
    NonSerializableFactory.rebind(ctx, jndiName, nonserializable);

 *
 * To unbind the object, use the following code snippet:
 *

	new InitialContext().unbind(key);
	NonSerializableFactory.unbind(key);

 *
 * @see javax.naming.spi.ObjectFactory
 * @see #rebind(javax.naming.Context, String, Object)
 *
 * @author Scott Stark.
 * @version $Revision: 2787 $
*/
@SuppressWarnings("unchecked")
public class NonSerializableFactory implements ObjectFactory
{
    private static Map wrapperMap = Collections.synchronizedMap(new HashMap());

    /** Place an object into the NonSerializableFactory namespace for subsequent
    access by getObject. There cannot be an already existing binding for key.

    @param key the name to bind target under. This should typically be the
    name that will be used to bind target in the JNDI namespace, but it does
    not have to be.
    @param target the non-Serializable object to bind.
    @throws javax.naming.NameAlreadyBoundException thrown if key already exists in the
     NonSerializableFactory map
    */
    public static synchronized void bind(String key, Object target) throws NameAlreadyBoundException
    {
        if( wrapperMap.containsKey(key) == true )
            throw new NameAlreadyBoundException(key+" already exists in the NonSerializableFactory map");
        wrapperMap.put(key, target);
    }
    /** Place or replace an object in the NonSerializableFactory namespce
     for subsequent access by getObject. Any existing binding for key will be
     replaced by target.

    @param key the name to bind target under. This should typically be the
    name that will be used to bind target in the JNDI namespace, but it does
    not have to be.
    @param target the non-Serializable object to bind.
    */
    public static void rebind(String key, Object target)
    {
        wrapperMap.put(key, target);
    }

    /** Remove a binding from the NonSerializableFactory map.

    @param key the key into the NonSerializableFactory map to remove.
    @throws javax.naming.NameNotFoundException thrown if key does not exist in the
     NonSerializableFactory map
    */
    public static void unbind(String key) throws NameNotFoundException
    {
        if( wrapperMap.remove(key) == null )
            throw new NameNotFoundException(key+" was not found in the NonSerializableFactory map");
    }
    /** Remove a binding from the NonSerializableFactory map.

    @param name the name for the key into NonSerializableFactory map to remove.
     The key is obtained as name.toString().
    @throws javax.naming.NameNotFoundException thrown if key does not exist in the
     NonSerializableFactory map
    */
    public static void unbind(Name name) throws NameNotFoundException
    {
        String key = name.toString();
        if( wrapperMap.remove(key) == null )
            throw new NameNotFoundException(key+" was not found in the NonSerializableFactory map");
    }

    /** Lookup a value from the NonSerializableFactory map.
    * @param key
    @return the object bound to key is one exists, null otherwise.
    */
    public static Object lookup(String key)
    {
        return wrapperMap.get(key);
    }
    /** Lookup a value from the NonSerializableFactory map.
    * @param name
    @return the object bound to key is one exists, null otherwise.
    */
    public static Object lookup(Name name)
    {
        String key = name.toString();
        return wrapperMap.get(key);
    }

    /** A convience method that simplifies the process of rebinding a
        non-zerializable object into a JNDI context.

    @param ctx the JNDI context to rebind to.
    @param key the key to use in both the NonSerializableFactory map and JNDI. It
        must be a valid name for use in ctx.bind().
    @param target the non-Serializable object to bind.
    @throws javax.naming.NamingException thrown on failure to rebind key into ctx.
    */
    public static synchronized void rebind(Context ctx, String key, Object target) throws NamingException
    {
        NonSerializableFactory.rebind(key, target);
        // Bind a reference to target using NonSerializableFactory as the ObjectFactory
        String className = target.getClass().getName();
        String factory = NonSerializableFactory.class.getName();
        StringRefAddr addr = new StringRefAddr("nns", key);
        Reference memoryRef = new Reference(className, addr, factory, null);
        ctx.rebind(key, memoryRef);
    }

   /** A convience method that simplifies the process of rebinding a
    non-zerializable object into a JNDI context. This version binds the
    target object into the default IntitialContext using name path.

   @param name the name to use as JNDI path name. The key into the
    NonSerializableFactory map is obtained from the toString() value of name.
    The name parameter cannot be a 0 length name.
    Any subcontexts between the root and the name must exist.
   @param target the non-Serializable object to bind.
   @throws javax.naming.NamingException thrown on failure to rebind key into ctx.
   */
   public static synchronized void rebind(Name name, Object target) throws NamingException
   {
      rebind(name, target, false);
   }

   /** A convience method that simplifies the process of rebinding a
    non-zerializable object into a JNDI context. This version binds the
    target object into the default IntitialContext using name path.

   @param name the name to use as JNDI path name. The key into the
    NonSerializableFactory map is obtained from the toString() value of name.
    The name parameter cannot be a 0 length name.
   @param target the non-Serializable object to bind.
   @param createSubcontexts a flag indicating if subcontexts of name should
    be created if they do not already exist.
   @throws javax.naming.NamingException thrown on failure to rebind key into ctx.
   */
   public static synchronized void rebind(Name name, Object target,
      boolean createSubcontexts) throws NamingException
   {
       String key = name.toString();
       InitialContext ctx = new InitialContext();
       if( createSubcontexts == true && name.size() > 1 )
       {
          int size = name.size() - 1;
          createSubcontext(ctx, name.getPrefix(size));
       }
       rebind(ctx, key, target);
   }

// --- Begin ObjectFactory interface methods
    /** Transform the obj Reference bound into the JNDI namespace into the
    actual non-Serializable object.

    @param obj the object bound in the JNDI namespace. This must be an implementation
    of javax.naming.Reference with a javax.naming.RefAddr of type "nns" whose
    content is the String key used to location the non-Serializable object in the
    NonSerializableFactory map.
    @param name ignored.
    @param nameCtx ignored.
    @param env ignored.

    @return the non-Serializable object associated with the obj Reference if one
    exists, null if one does not.
    */
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable env)
        throws Exception
    {	// Get the nns value from the Reference obj and use it as the map key
        Reference ref = (Reference) obj;
        RefAddr addr = ref.get("nns");
        String key = (String) addr.getContent();
        return wrapperMap.get(key);
    }
// --- End ObjectFactory interface methods

    private static Context createSubcontext(Context ctx, Name name) throws NamingException
    {
        Context subctx = ctx;
        for (int pos = 0; pos < name.size(); pos++)
        {
            String ctxName = name.get(pos);
            try
            {
                subctx = (Context) ctx.lookup(ctxName);
            }
            catch (NameNotFoundException e)
            {
                subctx = ctx.createSubcontext(ctxName);
            }
            // The current subctx will be the ctx for the next name component
            ctx = subctx;
        }
        return subctx;
    }
}


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

package org.mobicents.slee.container.management.console.server.log;

import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;

import org.mobicents.slee.container.management.console.client.ManagementConsoleException;
import org.mobicents.slee.container.management.console.client.log.HandlerInfo;
import org.mobicents.slee.container.management.console.client.log.LogService;
import org.mobicents.slee.container.management.console.client.log.LoggerInfo;
import org.mobicents.slee.container.management.console.server.ManagementConsole;
import org.mobicents.slee.container.management.console.server.mbeans.SleeMBeanConnection;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * @author baranowb
 *
 */
public class LogServiceImpl extends RemoteServiceServlet implements LogService {

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

  private ManagementConsole managementConsole = ManagementConsole.getInstance();

  private SleeMBeanConnection sleeConnection = managementConsole.getSleeConnection();

  /*
   * (non-Javadoc)
   *
   * @see org.mobicents.slee.container.management.console.client.log.LogService#getLoggerNames()
   */
  public List getLoggerNames() throws ManagementConsoleException {

    return sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().getLoggerNames(null);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.mobicents.slee.container.management.console.client.log.LogService#activateLogger(java.lang.String)
   */
  public void setLoggerLevel(String loggerName, String level) throws ManagementConsoleException {

    sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().setLoggerLevel(loggerName, level);

  }

  public String resetLoggerLevel(String loggerName) throws ManagementConsoleException {
    // This is called when logger is activated.
    sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().addLogger(loggerName, Level.OFF);
    sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().resetLoggerLevel(loggerName);
    return sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().getDefaultLoggerLevel();
  }

  /*
   * (non-Javadoc)
   *
   * @see org.mobicents.slee.container.management.console.client.log.LogService#fetchLoggerInfo(java.lang.String)
   */
  public LoggerInfo fetchLoggerInfo(String loggerName) throws ManagementConsoleException {

    if (!sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().getLoggerNames(null).contains(loggerName))
      sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().addLogger(loggerName, Level.OFF);
    int handlerNum = sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().numberOfHandlers(loggerName);

    String _name = loggerName;
    String _level = sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().getLoggerLevel(loggerName);
    boolean _parent = sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().getUseParentHandlersFlag(loggerName);
    String _filter = sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().getLoggerFilterClassName(loggerName);
    HandlerInfo[] hInfos = new HandlerInfo[handlerNum];

    for (int i = 0; i < handlerNum; i++) {
      String _formatterClass = sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().getGenericHandlerFormatterClassName(loggerName, i);
      String _filterClass = sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().getGenericHandlerFilterClassName(loggerName, i);
      String _h_level = sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().getGenericHandlerLevel(loggerName, i);
      String _h_name = sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().getHandlerName(loggerName, i);
      String _h_className = sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().getHandlerClassName(loggerName, i);
      // Add fetch for other options
      HandlerInfo hi = new HandlerInfo(i, (_h_name == null ? "" : _h_name), _filterClass, _formatterClass, _h_className, _h_level, new HashMap());
      hInfos[i] = hi;
    }

    return new LoggerInfo(_parent, _name, _filter, _level, hInfos);

  }

  public void removeHandlerAtIndex(String loggerName, int index) throws ManagementConsoleException {

    sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().removeHandler(loggerName, index);

  }

  /*
   * (non-Javadoc)
   *
   * @see org.mobicents.slee.container.management.console.client.log.LogService#getUseParentHandlers(java.lang.String)
   */
  public boolean getUseParentHandlers(String loggerName) throws ManagementConsoleException {

    return sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().getUseParentHandlersFlag(loggerName);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.mobicents.slee.container.management.console.client.log.LogService#setUseParentHandlers(java.lang.String, boolean)
   */
  public void setUseParentHandlers(String loggerName, boolean value) throws ManagementConsoleException {

    sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().setUseParentHandlersFlag(loggerName, value);

  }

  public void addSocketHandler(String loggerName, String handlerLevel, String handlerName, String formaterClassName, String filterClassName, String host,
      int port) throws ManagementConsoleException {
    sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils()
        .addSocketHandler(loggerName, handlerLevel, handlerName, formaterClassName, filterClassName, host, port);

  }

  public void addNotificationHandler(String loggerName, int numberOfEntries, String level, String formaterClassName, String filterClassName)
      throws ManagementConsoleException {
    sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils()
        .addNotificationHandler(loggerName, numberOfEntries, level, formaterClassName, filterClassName);

  }

  public int getDefaultNotificationInterval() throws ManagementConsoleException {

    return sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().getDefaultNotificationInterval();
  }

  public void addHandler(String loggerName, String handlerName, String handlerClassName, String formaterClass, String filterClass,
      String[] constructorParameters, String[] paramValues) throws ManagementConsoleException {
    sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils()
        .addHandler(loggerName, handlerName, handlerClassName, formaterClass, filterClass, constructorParameters, paramValues);

  }

  public void setLoggerFilterClassName(String loggerName, String className, String[] constructorParameters, String[] paramValues)
      throws ManagementConsoleException {
    sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils()
        .setLoggerFilterClassName(loggerName, className, constructorParameters, paramValues);
  }

  public void setDefaultLoggerLevel(String l) throws ManagementConsoleException {
    sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().setDefaultLoggerLevel(l);

  }

  public void setDefaultHandlerLevel(String l) throws ManagementConsoleException {
    sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().setDefaultHandlerLevel(l);

  }

  public void addLogger(String name, String level) throws ManagementConsoleException {
    sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().addLogger(name, level);

  }

  public void clearLoggers(String name) throws ManagementConsoleException {

    sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().clearLoggers(name);

  }

  public void reReadConf(String uri) throws ManagementConsoleException {
    sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().reReadConf(uri);

  }

  public void setDefaultNotificationInterval(int numberOfEntries) throws ManagementConsoleException {
    sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().setDefaultNotificationInterval(numberOfEntries);

  }

  public String getDefaultHandlerLevel() throws ManagementConsoleException {
    return sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().getDefaultHandlerLevel();
  }

  public String getDefaultLoggerLevel() throws ManagementConsoleException {
    return sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().getDefaultLoggerLevel();
  }

  public String getLoggerLevel(String fullName) throws ManagementConsoleException {
    return sleeConnection.getSleeManagementMBeanUtils().getLogManagementMBeanUtils().getLoggerLevel(fullName);
  }

}