/*
 * JBoss, Home of Professional Open Source
 * Copyright XXXX, Red Hat Middleware LLC, and individual contributors as indicated
 * by the @authors tag. All rights reserved.
 * See the copyright.txt in the distribution for a full listing
 * of individual contributors.
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU General Public License, v. 2.0.
 * This program is distributed in the hope that it will be useful, but WITHOUT A
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License,
 * v. 2.0 along with this distribution; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */
package org.mobicents.tools.twiddle.jslee;

import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;

import java.io.PrintWriter;
import java.util.Arrays;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.slee.ComponentID;
import javax.slee.facilities.Level;
import javax.slee.facilities.TraceLevel;
import javax.slee.management.NotificationSource;

import org.jboss.console.twiddle.command.CommandContext;
import org.jboss.console.twiddle.command.CommandException;
import org.jboss.logging.Logger;
import org.mobicents.tools.twiddle.AbstractSleeCommand;
import org.mobicents.tools.twiddle.Utils;
import org.mobicents.tools.twiddle.op.AbstractOperation;

/**
 * Trace command class.
 *
 * @author baranowb
 *
 */
@SuppressWarnings("deprecation")
public class TraceCommand extends AbstractSleeCommand {

	public TraceCommand() {
		super("trace", "This command performs operations on JSLEE TraceMBean.");
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.slee.tools.twiddle.AbstractSleeCommand#displayHelp()
	 */
	@Override
	public void displayHelp() {
		PrintWriter out = context.getWriter();

		out.println(desc);
		out.println();
		out.println("usage: " + name + " <-operation[[arg] | [--option[=arg]]*]>");
		out.println();
		out.println("operation:");
		out.println("    -a, --tracers-used             Lists tracer names for which Tracer objects have been requested by the");
		out.println("                                   notification source identified by the NotificationSource argument.");
		out.println("                                   Requires notification source as argument.");
		out.println("    -f, --tracers-set              List tracer names for which a trace filter level has been");
		out.println("                                   set for the notification source identified by the NotificationSource parameter.");
		out.println("                                   Requires notification source as argument.");
		out.println("    -s, --set-level                Sets Tracer or Trace level. Depending on options:");
		out.println("                                   --set-level supports following options:");
		out.println("               --cid               Determines SLEE 1.0 component ID. This option excludes \"--nsrc\". It MUST be used in conjunction with --level.");
		out.println("               --nsrc              Determines SLEE 1.1 NotificationSource of tracer affected. This option excludes \"--cid\". It MUST be used in conjunction with --level.");
		out.println("               --name              Determines SLEE 1.1 Tracer name affected. It MUST be used in conjunction wtih --nsrc.");
		out.println("               --level             Determines level of trace (or tracer). It MUST be used with either \"--nsrc\" or \"--cid\"");
		out.println("    -u, --un-set-level             Unsets Tracer level. Depending on options. Option \"--cid\" excludes \"--nsrc\".");
		out.println("               --nsrc              Determines SLEE 1.1 NotificationSource of tracer affected. It MUST be used in conjunction with --name.");
		out.println("               --name              Determines SLEE 1.1 Tracer name affected. It MUST be used in conjunction with --nsrc.");
		out.println("    -g, --get-level                Gets Trace or Tracer level. Depending on options. Option \"--cid\"  excludes \"--nsrc\".");
		out.println("               --cid               Determines SLEE 1.0 component ID. This option excludes \"--nsrc\".");
		out.println("               --nsrc              Determines SLEE 1.1 NotificationSource of tracer affected. It MUST be used in conjunction with --name.");
		out.println("               --name              Determines SLEE 1.1 Tracer name affected. It MUST be used in conjunction wtih --nsrc.");
		out.println("");
		out.println("arg:");
		out.println("");
		out.println("    NotificationSource:    ProfileTableNotification[table=xxx]");
		out.println("    Level             :    [SEVERE|WARNING|INFO|CONFIG|FINE|FINER|FINEST]");
		out.println("");

		out.println("Examples: ");
		out.println("");
		out.println("     1. List used tracers:");
		out.println("" + name + " -aProfileTableNotification[table=xxx]");
		out.println("");
		out.println("     2. Set level of tracer:");
		out.println("" + name + " -s --cid=SbbID[name=LocationSbb,vendor=org.mobicents,version=1.2] --level=SEVERE");
		out.println("");
		out.println("     3. Set level of tracer:");
		out.println("" + name + " -s --nsrc=SbbNotification[service=ServiceID[name=SIP Registrar Service,vendor=org.mobicents,version=1.2],sbb=SbbID[name=LocationSbb,vendor=org.mobicents,version=1.2]] --level=SEVERE --name=error.tracer");
		out.flush();

	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.slee.tools.twiddle.AbstractSleeCommand#getBeanOName()
	 */
	@Override
	public ObjectName getBeanOName() throws MalformedObjectNameException, NullPointerException {
		return new ObjectName(Utils.SLEE_TRACE);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.mobicents.slee.tools.twiddle.AbstractSleeCommand#processArguments
	 * (java.lang.String[])
	 */
	@Override
	protected void processArguments(String[] args) throws CommandException {
		String sopts = ":a:f:sug";

		LongOpt[] lopts = {
				new LongOpt("tracers-used", LongOpt.REQUIRED_ARGUMENT, null, 'a'),
				new LongOpt("tracers-set", LongOpt.REQUIRED_ARGUMENT, null, 'f'),
				new LongOpt("set-level", LongOpt.NO_ARGUMENT, null, 's'),
					new LongOpt("cid", LongOpt.REQUIRED_ARGUMENT, null, SetLevelOperation.cid),
					new LongOpt("nsrc", LongOpt.REQUIRED_ARGUMENT, null, SetLevelOperation.nsrc),
					new LongOpt("name", LongOpt.REQUIRED_ARGUMENT, null, SetLevelOperation.name),
					new LongOpt("level", LongOpt.REQUIRED_ARGUMENT, null, SetLevelOperation.level),
				new LongOpt("un-set-level", LongOpt.NO_ARGUMENT, null, 'u'),
					new LongOpt("nsrc", LongOpt.REQUIRED_ARGUMENT, null, UnsetLevelOperation.nsrc),
					new LongOpt("name", LongOpt.REQUIRED_ARGUMENT, null, UnsetLevelOperation.name),
				new LongOpt("get-level", LongOpt.NO_ARGUMENT, null, 'g'),
					new LongOpt("cid", LongOpt.REQUIRED_ARGUMENT, null, GetLevelOperation.cid),
					new LongOpt("nsrc", LongOpt.REQUIRED_ARGUMENT, null, GetLevelOperation.nsrc),
					new LongOpt("name", LongOpt.REQUIRED_ARGUMENT, null, GetLevelOperation.name), };

		Getopt getopt = new Getopt(null, args, sopts, lopts);
		// getopt.setOpterr(false);

		int code;
		while ((code = getopt.getopt()) != -1) {
			switch (code) {
			case ':':
				throw new CommandException("Option requires an argument: " + args[getopt.getOptind() - 1]);

			case '?':
				throw new CommandException("Invalid (or ambiguous) option: " + args[getopt.getOptind() - 1]);

			case 'a':

				super.operation = new GetTracersUsedOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);
				break;

			case 'f':

				super.operation = new GetTracersSetOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);
				break;
			case 's':

				super.operation = new SetLevelOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);
				break;
			case 'u':

				super.operation = new UnsetLevelOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);
				break;
			case 'g':

				super.operation = new GetLevelOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);
				break;
			default:
				throw new CommandException("Command: \"" + getName() + "\", found unexpected opt: " + args[getopt.getOptind() - 1]);

			}
		}

	}

	private class GetTracersUsedOperation extends AbstractOperation {

		private static final String OPERATION_getTracersUsed = "getTracersUsed";

		public GetTracersUsedOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			this.operationName = OPERATION_getTracersUsed;
		}

		@Override
		public void buildOperation(Getopt opts, String[] args) throws CommandException {
			String optArg = opts.getOptarg();
			if (optArg.contains(";")) {
				throw new CommandException("Option does not support array argument: " + args[opts.getOptind() - 1]);

			} else {
				try {
					addArg(optArg, NotificationSource.class, true);
				} catch (Exception e) {
					throw new CommandException("Failed to parse NotificationSource: \"" + optArg + "\"", e);
				}
			}

		}

	}

	private class GetTracersSetOperation extends AbstractOperation {

		private static final String OPERATION_getTracersSet = "getTracersSet";

		public GetTracersSetOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			this.operationName = OPERATION_getTracersSet;
		}

		@Override
		public void buildOperation(Getopt opts, String[] args) throws CommandException {
			String optArg = opts.getOptarg();
			if (optArg.contains(";")) {
				throw new CommandException("Option does not support array argument: " + args[opts.getOptind() - 1]);

			} else {
				try {
					addArg(optArg, NotificationSource.class, true);
				} catch (Exception e) {
					throw new CommandException("Failed to parse NotificationSource: \"" + optArg + "\"", e);
				}
			}

		}

	}

	private class SetLevelOperation extends AbstractOperation {

		public static final char cid = 'z';
		public static final char nsrc = 'x';
		public static final char name = 'v';
		public static final char level = 'b';

		private static final String OPERATION_setTraceLevel = "setTraceLevel";
		private String stringCID;

		private String stringNSRC;
		private String stringName; //TODO: allow ansence of name, to set default level?

		private String stringLevel;

		public SetLevelOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			this.operationName = OPERATION_setTraceLevel;
		}

		@Override
		public void buildOperation(Getopt opts, String[] args) throws CommandException {
			// tricky
			int code;
			while ((code = opts.getopt()) != -1) {
				switch (code) {
					case ':':
						throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

					case '?':
						throw new CommandException("Invalid (or ambiguous) option: " + args[opts.getOptind() - 1]);

					case cid:
						stringCID = opts.getOptarg();
						break;
					case nsrc:
						stringNSRC = opts.getOptarg();
						break;
					case name:
						stringName = opts.getOptarg();
						break;
					case level:
						stringLevel = opts.getOptarg();
						break;
					default:
						throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
								+ "\", found unexpected opt: " + args[opts.getOptind() - 1]);

				}
			}

			if ((stringCID == null && stringNSRC == null) || (stringNSRC != null && stringCID != null)) {
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", expects either \"--nsrc\" or \"--cid\" to be present");
			}

			if (stringCID != null) {
				// its 1.0
				if (stringLevel == null) {
					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
							+ "\", expects  \"--level\" to be present");
				}
				try {
					addArg(stringCID, ComponentID.class, true);
				} catch (Exception e) {
					throw new CommandException("Failed to parse ComponentID: \"" + stringCID + "\"", e);
				}
				try {
					addArg(stringLevel, Level.class, true);
				} catch (Exception e) {
					throw new CommandException("Failed to parse Level: \"" + stringLevel + "\"", e);
				}
			} else {

				if (stringLevel == null) {
					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
							+ "\", expects  \"--level\" to be present");
				}
				if (stringName == null) {
					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
							+ "\", expects  \"--name\" to be present");
				}

				try {
					addArg(stringNSRC, NotificationSource.class, true);
				} catch (Exception e) {
					throw new CommandException("Failed to parse NotificationSource: \"" + stringNSRC + "\"", e);
				}
				try {
					addArg(stringName, String.class, false);
				} catch (Exception e) {
					throw new CommandException("Failed to parse Name: \"" + stringName + "\"", e);
				}
				try {
					addArg(stringLevel, TraceLevel.class, true);
				} catch (Exception e) {
					throw new CommandException("Failed to parse TraceLevel: \"" + stringLevel + "\"", e);
				}
			}

		}

	}

	private class GetLevelOperation extends AbstractOperation {

		public static final char cid = 'z';
		public static final char nsrc = 'x';
		public static final char name = 'v';
		private static final String OPERATION_getTraceLevel = "getTraceLevel";
		private String stringCID;

		private String stringNSRC;
		private String stringName;

		public GetLevelOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			this.operationName = OPERATION_getTraceLevel;
		}

		@Override
		public void buildOperation(Getopt opts, String[] args) throws CommandException {
			// tricky
			int code;
			while ((code = opts.getopt()) != -1) {
				switch (code) {
					case ':':
						throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

					case '?':
						throw new CommandException("Invalid (or ambiguous) option: " + args[opts.getOptind() - 1]);

					case cid:
						stringCID = opts.getOptarg();
						break;
					case nsrc:
						stringNSRC = opts.getOptarg();
						break;
					case name:
						stringName = opts.getOptarg();
						break;

					default:
						throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
								+ "\", found unexpected opt: " + args[opts.getOptind() - 1]);

				}
			}

			if ((stringCID == null && stringNSRC == null) || (stringNSRC != null && stringCID != null)) {
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", expects either \"--nsrc\" or \"--cid\" to be present");
			}

			if (stringCID != null) {
				// its 1.0

				try {
					addArg(stringCID, ComponentID.class, true);
				} catch (Exception e) {
					throw new CommandException("Failed to parse ComponentID: \"" + stringCID + "\"", e);
				}

			} else {

				if (stringName == null) {
					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
							+ "\", expects  \"--name\" to be present");
				}

				try {
					addArg(stringNSRC, NotificationSource.class, true);
				} catch (Exception e) {
					throw new CommandException("Failed to parse NotificationSource: \"" + stringNSRC + "\"", e);
				}
				try {
					addArg(stringName, String.class, false);
				} catch (Exception e) {
					throw new CommandException("Failed to parse Name: \"" + stringName + "\"", e);
				}

			}
		}

	}

	private class UnsetLevelOperation extends AbstractOperation {

		public static final char nsrc = 'x';
		public static final char name = 'v';

		private String stringNSRC;
		private String stringName;
		private static final String OPERATION_unsetTraceLevel = "unsetTraceLevel";
		public UnsetLevelOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			this.operationName = OPERATION_unsetTraceLevel;
		}

		@Override
		public void buildOperation(Getopt opts, String[] args) throws CommandException {
			// tricky
			int code;
			while ((code = opts.getopt()) != -1) {
				switch (code) {
					case ':':
						throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

					case '?':
						throw new CommandException("Invalid (or ambiguous) option: " + args[opts.getOptind() - 1]);

					case nsrc:
						stringNSRC = opts.getOptarg();
						break;
					case name:
						stringName = opts.getOptarg();
						break;

					default:
						throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
								+ "\", found unexpected opt: " + args[opts.getOptind() - 1]);

				}
			}

			if (stringNSRC == null) {
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", expects \"--nsrc\" to be present");
			}
			if (stringName == null) {
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", expects \"--name\" to be present");
			}

			try {
				addArg(stringNSRC, NotificationSource.class, true);
			} catch (Exception e) {
				throw new CommandException("Failed to parse NotificationSource: \"" + stringNSRC + "\"", e);
			}
			try {
				addArg(stringName, String.class, false);
			} catch (Exception e) {
				throw new CommandException("Failed to parse Name: \"" + stringName + "\"", e);
			}
		}

	}
}


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

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

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

import javax.slee.ActivityContextInterface;
import javax.slee.FactoryException;
import javax.slee.TransactionRequiredLocalException;
import javax.slee.UnrecognizedActivityException;
import javax.slee.profile.ProfileTableActivity;
import javax.slee.profile.ProfileTableActivityContextInterfaceFactory;
import javax.slee.profile.UnrecognizedProfileTableNameException;

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.management.ProfileManagementImpl;
import org.mobicents.slee.container.profile.ProfileTableActivityContextHandle;
import org.mobicents.slee.container.profile.ProfileTableImpl;

/**
 * Implmenetation of profile table activity context interface factory.
 *
 * @author M. Ranganathan
 * @author Ivelin Ivanov
 * @author martins
 */
public class ProfileTableActivityContextInterfaceFactoryImpl implements
		ProfileTableActivityContextInterfaceFactory {

	public static String JNDI_NAME = "profiletableactivitycontextinterfacefactory";

	private final SleeContainer serviceContainer;
	private ProfileManagementImpl profileManagementImpl;

	/**
	 *
	 */
	public ProfileTableActivityContextInterfaceFactoryImpl(SleeContainer serviceContainer, ProfileManagementImpl profileManagementImpl) {
		this.serviceContainer = serviceContainer;
		this.profileManagementImpl = profileManagementImpl;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.slee.profile.ProfileTableActivityContextInterfaceFactory#getActivityContextInterface(javax.slee.profile.ProfileTableActivity)
	 */
	public ActivityContextInterface getActivityContextInterface(
			ProfileTableActivity profileTableActivity)
			throws NullPointerException, TransactionRequiredLocalException,
			UnrecognizedActivityException, FactoryException {
		if (profileTableActivity == null
				|| profileTableActivity.getProfileTableName() == null) {

			throw new NullPointerException("null profile table activity");

		}

		serviceContainer.getTransactionManager().mandateTransaction();
		ProfileTableImpl profileTableImpl = null;
		try {
			// check if this is an assigned profile table
			// name.
			profileTableImpl = profileManagementImpl.getProfileTable(profileTableActivity.getProfileTableName());
		} catch (UnrecognizedProfileTableNameException e) {
			throw new UnrecognizedActivityException(profileTableActivity.getProfileTableName(),e);
		}

        ActivityContext ac = profileTableImpl.getActivityContext();
        if (ac == null) {
        	throw new UnrecognizedActivityException("No resource for: "+profileTableActivity.getProfileTableName(),profileTableActivity);
        }

		return ac.getActivityContextInterface();

	}
}


/*
 * 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.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.management.ListenerNotFoundException;
import javax.management.MBeanNotificationInfo;
import javax.management.NotCompliantMBeanException;
import javax.management.NotificationBroadcaster;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.StandardMBean;
import javax.slee.InvalidStateException;
import javax.slee.management.ManagementException;
import javax.slee.management.NotificationSource;
import javax.slee.management.ProfileTableNotification;
import javax.slee.management.ResourceAdaptorEntityNotification;
import javax.slee.management.SbbNotification;
import javax.slee.management.SubsystemNotification;
import javax.slee.usage.UsageMBean;
import javax.slee.usage.UsageNotification;

import org.mobicents.slee.runtime.usage.AbstractUsageParameterSet;

public class UsageMBeanImpl extends StandardMBean implements UsageMBean,
		NotificationBroadcaster {

	private static final MBeanNotificationInfo[] notificationInfo = initNotificationInfo();

	/**
	 * Initiates the notification info for usage mbeans
	 * @return
	 */
	private static MBeanNotificationInfo[] initNotificationInfo() {
		String[] notificationTypes = new String[] {
				ProfileTableNotification.USAGE_NOTIFICATION_TYPE,
				ResourceAdaptorEntityNotification.USAGE_NOTIFICATION_TYPE,
				SbbNotification.USAGE_NOTIFICATION_TYPE,
				SubsystemNotification.USAGE_NOTIFICATION_TYPE
				};
		return new MBeanNotificationInfo[] { new MBeanNotificationInfo(
				notificationTypes, UsageNotification.class.getName(),
				"JAIN SLEE 1.1 Usage MBean Notification") };

	}

	private AbstractUsageParameterSet usageParameterSet;
	private UsageMBeanImplParent parent;
	private final NotificationSource notificationSource;
	private ObjectName objectName;

	public UsageMBeanImpl(Class<?> mbeanInterface, NotificationSource notificationSource) throws NotCompliantMBeanException,
			ClassNotFoundException {
		super(mbeanInterface);
		this.notificationSource = notificationSource;
	}

	public void setParent(UsageMBeanImplParent parent) {
		this.parent = parent;
	}

	public ObjectName getObjectName() {
		return objectName;
	}

	public void setObjectName(ObjectName objectName) {
		this.objectName = objectName;
	}

	public void setUsageParameter(
			AbstractUsageParameterSet usageParameterSet) {
		this.usageParameterSet = usageParameterSet;
	}

	public AbstractUsageParameterSet getUsageParameter() {
		return usageParameterSet;
	}

	public void close() throws InvalidStateException, ManagementException {
		if (listeners.size() != 0) {
			throw new InvalidStateException(
					"Could not close Usage MBean listeners still attached!");
		}
	}

	public NotificationSource getNotificationSource()
			throws ManagementException {
		return notificationSource;
	}

	public ObjectName getUsageNotificationManagerMBean()
			throws ManagementException {
		UsageNotificationManagerMBeanImpl notificationManager = parent.getUsageNotificationManagerMBean(notificationSource);
		return notificationManager != null ? notificationManager.getObjectName() : null;
	}

	public String getUsageParameterSet() throws ManagementException {
		return usageParameterSet.getParameterSetName();
	}

	public void resetAllUsageParameters() throws ManagementException {
		usageParameterSet.reset();
	}

	// --- NOTIFICATION BROADCASTER IMPL

	private final Map<NotificationListener, ListenerFilterHandbackTriplet> listeners = new ConcurrentHashMap<NotificationListener, ListenerFilterHandbackTriplet>();

	public void addNotificationListener(NotificationListener listener,
			NotificationFilter filter, Object handback)
			throws IllegalArgumentException {
		if (listener == null) {
			throw new IllegalArgumentException("null listener");
		} else {
			this.listeners.put(listener, new ListenerFilterHandbackTriplet(
					listener, filter, handback));
		}
	}

	/*
	 * (non-Javadoc)
	 * @see javax.management.NotificationBroadcaster#getNotificationInfo()
	 */
	public MBeanNotificationInfo[] getNotificationInfo() {
		return notificationInfo;
	}

	public void removeNotificationListener(NotificationListener listener)
			throws ListenerNotFoundException {
		ListenerFilterHandbackTriplet triplet = listeners.remove(listener);
		if (triplet == null) {
			throw new ListenerNotFoundException();
		}
	}

	/**
	 * Send the notification.
	 *
	 * @param value
	 * @param seqno
	 * @param usageParameterSetName
	 * @param usageParameterName
	 * @param isCounter
	 */
	public void sendUsageNotification(long value, long seqno,
			String usageParameterSetName, String usageParameterName,
			boolean isCounter) {
		UsageNotificationManagerMBeanImpl notificationManager = parent
				.getUsageNotificationManagerMBean(notificationSource);
		if (notificationManager == null
				|| notificationManager
						.getNotificationsEnabled(usageParameterName)) {
			// if the notification manager is null we consider the notification
			// can be sent
			UsageNotification notification = createUsageNotification(value,
					seqno, usageParameterSetName, usageParameterName, isCounter);
			for (ListenerFilterHandbackTriplet triplet : listeners.values()) {
				if (triplet.notificationFilter == null
						|| triplet.notificationFilter
								.isNotificationEnabled(notification)) {
					triplet.notificationListener.handleNotification(
							notification, triplet.handbackObject);
				}
			}
		}
	}

	/**
	 * Creates an instance of an {@link UsageNotification} for the specified
	 * args. This operation is exposed to allow it be overriden by
	 * {@link SbbUsageMBean} impl.
	 *
	 * @param value
	 * @param seqno
	 * @param usageParameterSetName
	 * @param usageParameterName
	 * @param isCounter
	 * @return
	 */
	protected UsageNotification createUsageNotification(long value, long seqno,
			String usageParameterSetName, String usageParameterName,
			boolean isCounter) {
		return new UsageNotification(notificationSource
				.getUsageNotificationType(), this, notificationSource,
				usageParameterSetName, usageParameterName, isCounter, value,
				seqno, System.currentTimeMillis());
	}

	static class ListenerFilterHandbackTriplet {

		NotificationListener notificationListener;

		NotificationFilter notificationFilter;

		Object handbackObject;

		public ListenerFilterHandbackTriplet(NotificationListener listener,
				NotificationFilter notificationFilter, Object handbackObject) {
			this.notificationListener = listener;
			this.notificationFilter = notificationFilter;
			this.handbackObject = handbackObject;
		}

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

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

}


/*
 * 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:00:45:05 2009-02-04

 * Project: restcomm-jainslee-server-core

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

import java.util.Set;

import javax.slee.ComponentID;
import javax.slee.EventTypeID;
import javax.slee.management.ComponentDescriptor;
import javax.slee.management.DependencyException;
import javax.slee.management.DeploymentException;
import javax.slee.management.LibraryID;
import javax.slee.resource.ResourceAdaptorTypeID;

import org.mobicents.slee.container.component.deployment.jaxb.descriptors.ResourceAdaptorTypeDescriptorImpl;
import org.mobicents.slee.container.component.ratype.ResourceAdaptorTypeComponent;

/**
 * Start time:00:45:05 2009-02-04

 * Project: restcomm-jainslee-server-core

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

	/**
	 * the ratype descriptor
	 */
	private final ResourceAdaptorTypeDescriptorImpl descriptor;

	/**
	 * the aci factory interface
	 */
	private Class<?> activityContextInterfaceFactoryInterface;

	/**
	 * the aci factory concrete class, generated by SLEE
	 */
	private Class<?> activityContextInterfaceFactoryConcreteClass;
	  /**
	   * Resource adaptor SBB interface
	   */
	private Class<?> resourceAdaptorSBBInterface = null;

	/**
	 * the JAIN SLEE specs descriptor
	 */
	private javax.slee.resource.ResourceAdaptorTypeDescriptor specsDescriptor = null;

	/**
	 * the instance of the aci factory for this ra type
	 */
	private Object activityContextInterfaceFactory;

	/**
	 *
	 * @param descriptor
	 */
	public ResourceAdaptorTypeComponentImpl(
			ResourceAdaptorTypeDescriptorImpl descriptor) {
		this.descriptor = descriptor;
	}

	/**
	 * Retrieves the ratype descriptor
	 * @return
	 */
	public ResourceAdaptorTypeDescriptorImpl getDescriptor() {
		return descriptor;
	}

	/**
	 * Retrieves the ratype id
	 * @return
	 */
	public ResourceAdaptorTypeID getResourceAdaptorTypeID() {
		return descriptor.getResourceAdaptorTypeID();
	}

	/**
	 * Retrieves the aci factory concrete class, generated by SLEE
	 * @return
	 */
	public Class<?> getActivityContextInterfaceFactoryConcreteClass() {
		return activityContextInterfaceFactoryConcreteClass;
	}

	/**
	 * Retrieves the aci factory interface
	 * @return
	 */
	public Class<?> getActivityContextInterfaceFactoryInterface() {
		return activityContextInterfaceFactoryInterface;
	}

	/**
	 * Sets the aci factory concrete class, generated by SLEE
	 * @param activityContextInterfaceFactoryConcreteClass
	 */
	public void setActivityContextInterfaceFactoryConcreteClass(
			Class<?> activityContextInterfaceFactoryConcreteClass) {
		this.activityContextInterfaceFactoryConcreteClass = activityContextInterfaceFactoryConcreteClass;
	}

	/**
	 * Sets the aci factory interface
	 * @param activityContextInterfaceFactoryInterface
	 */
	public void setActivityContextInterfaceFactoryInterface(
			Class<?> activityContextInterfaceFactoryInterface) {
		this.activityContextInterfaceFactoryInterface = activityContextInterfaceFactoryInterface;
	}

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

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

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

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

	@Override
	public boolean validate() throws DependencyException, DeploymentException {
		// FIXME use validator when available
		return true;
	}

	public Class<?> getResourceAdaptorSBBInterface() {
		return resourceAdaptorSBBInterface;
	}

	public void setResourceAdaptorSBBInterface(Class<?> resourceAdaptorSBBInterface) {
		this.resourceAdaptorSBBInterface = resourceAdaptorSBBInterface;
	}

	/**
	 * Retrieves the instance of the aci factory for this ra type
	 * @return
	 */
	public Object getActivityContextInterfaceFactory() {
		return activityContextInterfaceFactory;
	}

	/**
	 * Sets the instance of the aci factory for this ra type
	 * @param activityContextInterfaceFactory
	 */
	public void setActivityContextInterfaceFactory(
			Object activityContextInterfaceFactory) {
		this.activityContextInterfaceFactory = activityContextInterfaceFactory;
	}

	/**
	 *  Retrieves the JAIN SLEE specs descriptor
	 * @return
	 */
	public javax.slee.resource.ResourceAdaptorTypeDescriptor getSpecsDescriptor() {
		if (specsDescriptor == null) {
			final LibraryID[] libraryIDs = descriptor.getLibraryRefs().toArray(new LibraryID[descriptor.getLibraryRefs().size()]);
			final String[] activityTypes = descriptor.getActivityTypes().toArray(new String[descriptor.getActivityTypes().size()]);
			final EventTypeID[] eventTypes = descriptor.getEventTypeRefs().toArray(new EventTypeID[descriptor.getEventTypeRefs().size()]);
			String raInterface = descriptor.getResourceAdaptorInterface() == null ? null : descriptor.getResourceAdaptorInterface();
			specsDescriptor = new javax.slee.resource.ResourceAdaptorTypeDescriptor(getResourceAdaptorTypeID(),getDeployableUnit().getDeployableUnitID(),getDeploymentUnitSource(),libraryIDs,activityTypes,raInterface,eventTypes);
		}
		return specsDescriptor;
	}

	@Override
	public ComponentDescriptor getComponentDescriptor() {
		return getSpecsDescriptor();
	}
	@Override
	public void processSecurityPermissions() throws DeploymentException {
		//Do nothing?

	}

	@Override
	public void undeployed() {
		super.undeployed();
		specsDescriptor = null;
		activityContextInterfaceFactory = null;
		activityContextInterfaceFactoryConcreteClass = null;
		activityContextInterfaceFactoryInterface = null;
		resourceAdaptorSBBInterface = null;
	}
}


/*
 * JBoss, Home of Professional Open Source
 * Copyright XXXX, Red Hat Middleware LLC, and individual contributors as indicated
 * by the @authors tag. All rights reserved.
 * See the copyright.txt in the distribution for a full listing
 * of individual contributors.
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU General Public License, v. 2.0.
 * This program is distributed in the hope that it will be useful, but WITHOUT A
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License,
 * v. 2.0 along with this distribution; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */
package org.mobicents.tools.twiddle.jslee;

import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;

import java.io.PrintWriter;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.slee.profile.ProfileSpecificationID;

import org.jboss.console.twiddle.command.CommandContext;
import org.jboss.console.twiddle.command.CommandException;
import org.jboss.logging.Logger;
import org.mobicents.tools.twiddle.AbstractSleeCommand;
import org.mobicents.tools.twiddle.Utils;
import org.mobicents.tools.twiddle.op.AbstractOperation;

/**
 * Command which accesses Profile MBean.
 * @author baranowb
 *
 */
public class ProfileCommand extends AbstractSleeCommand {

	/**
	 */
	public ProfileCommand() {
		super("profile",  "This command performs operations on JSLEE ProfileProvisioningMBean." );
	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.tools.twiddle.AbstractSleeCommand#displayHelp()
	 */
	@Override
	public void displayHelp() {
		PrintWriter out = context.getWriter();

		out.println(desc);
		out.println();
		out.println("usage: " + name + " <-operation[[arg] | [--option[=arg]]*]>");
		out.println();
		out.println("operation:");
		out.println("    -l, --list                     Lists components based on passed option:");
		out.println("            --table                Lists profile table names, optionally it takes ProfileSpecificationID as argument, ");
		out.println("                                   if so, names are listed only for tables which ProfileSpecificationID matches.");
		out.println("            --profile              Lists profile IDs by table name,");
		out.println("                                   requires profile table name as argument.");
		out.println("    -c, --create                   Creates component based on passed options. Supported are two sets [ \"--table-name\" & \"--profile-name\" | \"--table-name\" & \"--profile-spec\" ]");
		out.println("            --profile-name         Indicates profile name to be created. It is used in conjunction with \"--table-name\" to create profile in table.");
		out.println("            --table-name           Indicates profile table name. It requires either \"--profile-name\" or \"--profile-spec\".");
		out.println("            --profile-spec         Indicates ProfileSpecification ID used to craete table.");
		out.println("    -r, --remove                   Removes component based on passed options. Requires atleast \"--table-name\" option. Following options are supported:");
		out.println("            --table-name           Indicates table name to be removed. If \"--profile-name\" is also used, only profile is removed from table.");
		out.println("            --profile-name         Indicates profile name of profile to be removed. It is used in conjunction with \"--table-name\".");
		out.println("    -n, --rename                   Renames profile table, based on options. Both are required. Supported options are:");
		out.println("            --current-name         Sets current name of profile table.");
		out.println("            --new-name             Sets new name for profile table.");
		//its weird, other MBeans define methods like getXXXUsage or something...
		out.println("    -g, --get                      Fetches information regarding profiles and profile tables based on option, exactly one must be present. Supported options:");
		out.println("            --profile-spec         Retrieves ProfileSpecification ID for given table name,");
		out.println("                                   requires profile table name as argument.");
		//out.println("            --profile              Retrieves ObjectName of default profile for given table name.");
		//out.println("                                   Requires profile table name as argument. It can be used in conjunction with \"--profile-name\" ");
		//out.println("                                   to get ObjectName for specific profile. Side effect of this call is registration of MBean with return ObjectName");
		//out.println("            --profile-name         Specifies profile name for \"--profile\" option. ObjectName returned by this call identifies bean for specific profile.");
		//out.println("                                   Requires profile name as argument.");
		//TODO: usage for table.
		out.println("arg:");
		out.println("Examples: ");
		out.println("");
		out.println("     1. Get specification ID for table:");
		out.println("" + name + " -g --profile-spec=CallControl");
		out.println("");
		out.println("     2. Rename profile table");
		out.println("" + name + " -n --curent-name=CallControl --new-name=OldCCTable");
		out.println("");
		out.println("     3. List all tables present:");
		out.println("" + name + " -l --table");
		out.println("");
		out.println("     4. List all tables present for specific ProfileSpecificationID");
		out.println("" + name + " -l --table=ProfileSpecificationID[name=CallControlProfileCMP,vendor=org.mobicents,version=0.1]");
		out.println("");
		out.println("     5. Create table for specification:");
		out.println("" + name + " -c --table-name=NewCallControl --profile-spec=ProfileSpecificationID[name=CallControlProfileCMP,vendor=org.mobicents,version=0.1]");
		out.println("");
		out.println("     6. Create profile in table:");
		out.println("" + name + " -c --table-name=NewCallControl --profile-name=newuser");
		out.flush();

	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.tools.twiddle.AbstractSleeCommand#processArguments(java.lang.String[])
	 */
	@Override
	protected void processArguments(String[] args) throws CommandException {
		String sopts = ":lcrng";

		LongOpt[] lopts = {
				new LongOpt("list", LongOpt.NO_ARGUMENT, null, 'l'),
					new LongOpt("table", LongOpt.OPTIONAL_ARGUMENT, null, ListOperation.table),
					new LongOpt("profile", LongOpt.REQUIRED_ARGUMENT, null, ListOperation.profile),
				new LongOpt("create", LongOpt.NO_ARGUMENT, null, 'c'),
					//those are also for remove
					new LongOpt("profile-name", LongOpt.REQUIRED_ARGUMENT, null, CreateOperation.profile_name),
					new LongOpt("table-name", LongOpt.REQUIRED_ARGUMENT, null, CreateOperation.table_name),
					new LongOpt("profile-spec", LongOpt.REQUIRED_ARGUMENT, null, CreateOperation.profile_spec),
				new LongOpt("remove", LongOpt.NO_ARGUMENT, null, 'r'),
					//covered above
				new LongOpt("rename", LongOpt.NO_ARGUMENT, null, 'n'),
					new LongOpt("current-name", LongOpt.REQUIRED_ARGUMENT, null, RenameOperation.current_name),
					new LongOpt("new-name", LongOpt.REQUIRED_ARGUMENT, null, RenameOperation.new_name),
				new LongOpt("get", LongOpt.NO_ARGUMENT, null, 'g'),
					//new LongOpt("profile-name", LongOpt.REQUIRED_ARGUMENT, null, GetOperation.profile_name),
					new LongOpt("profile-spec", LongOpt.REQUIRED_ARGUMENT, null, GetOperation.profile_spec),
					//new LongOpt("profile", LongOpt.REQUIRED_ARGUMENT, null, GetOperation.profile),
				};

		Getopt getopt = new Getopt(null, args, sopts, lopts);
		getopt.setOpterr(false);

		int code;
		while ((code = getopt.getopt()) != -1) {
			switch (code) {
			case ':':
				throw new CommandException("Option requires an argument: " + args[getopt.getOptind() - 1]);

			case '?':
				throw new CommandException("Invalid (or ambiguous) option: " + args[getopt.getOptind() - 1]);

			case 'l':

				super.operation = new ListOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);

				break;
			case 'c':

				super.operation = new CreateOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);

				break;
			case 'r':

				super.operation = new RemoveOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);

				break;
			case 'n':

				super.operation = new RenameOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);

				break;
			case 'g':

				super.operation = new GetOperation(super.context, super.log, this);
				super.operation.buildOperation(getopt, args);

				break;

			default:
				throw new CommandException("Command: \"" + getName() + "\", found unexpected opt: " + args[getopt.getOptind() - 1]);

			}
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.mobicents.slee.tools.twiddle.AbstractSleeCommand#getBeanOName()
	 */
	@Override
	public ObjectName getBeanOName() throws MalformedObjectNameException, NullPointerException {
		return new ObjectName(Utils.SLEE_PROFILE_PROVISIONING);
	}

	private class ListOperation extends AbstractOperation {
		public static final char table = 'o';
		public static final char profile = 'p';

		private static final String OPERATION_getProfileTables = "getProfileTables";
		private static final String OPERATION_getProfiles = "getProfiles";

		public ListOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			// operation is not set. its used to determine if more options were
			// passed.
		}

		@Override
		public void buildOperation(Getopt opts, String[] args) throws CommandException {
			int code;
			String optArg;
			while ((code = opts.getopt()) != -1) {
				if (super.operationName != null) {
					throw new CommandException("Command: \"" + sleeCommand.getName() + "\", expects either \"--table\" or \"--profile\"!");
				}
				switch (code) {
				case ':':
					throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

				case '?':
					throw new CommandException("Invalid (or ambiguous) option: " + args[opts.getOptind() - 1]);

				case table:

					super.operationName = OPERATION_getProfileTables;
					optArg = opts.getOptarg();

					if (optArg != null) {
						// it must be ProfileSpecificationID
						try {
							addArg(optArg, ProfileSpecificationID.class, true);
						} catch (Exception e) {
							throw new CommandException("Failed to parse ProfileSpecificationID: \"" + optArg + "\"", e);
						}
					}
					break;
				case profile:

					super.operationName = OPERATION_getProfiles;
					optArg = opts.getOptarg();
					addArg(optArg, String.class, false); // table name
					break;

				default:
					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
							+ "\", found unexpected opt: " + args[opts.getOptind() - 1]);

				}
				if (super.operationName == null) {
					throw new CommandException("Command: \"" + sleeCommand.getName() + "\", expects either \"--table\" or \"--profile\"!");
				}

			}

		}
	}

	private class CreateOperation extends AbstractOperation {
		public static final char table_name = 'b';
		public static final char profile_name = 'v';
		public static final char profile_spec = 'm';

		private static final String OPERATION_createProfile = "createProfile";
		private static final String OPERATION_createProfileTable = "createProfileTable";

		private String stringTableName;
		private String stringProfileName;
		private String stringProfileSpec;

		public CreateOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			// operation is not set. its used to determine if more options were
			// passed.
		}

		@Override
		public void buildOperation(Getopt opts, String[] args) throws CommandException {
			int code;
			while ((code = opts.getopt()) != -1) {
				switch (code) {
				case ':':
					throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

				case '?':
					throw new CommandException("Invalid (or ambiguous) option: " + args[opts.getOptind() - 1]);

				case table_name:

					this.stringTableName = opts.getOptarg();

					break;
				case profile_name:

					this.stringProfileName = opts.getOptarg();

					break;
				case profile_spec:

					this.stringProfileSpec = opts.getOptarg();

					break;

				default:
					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
							+ "\", found unexpected opt: " + args[opts.getOptind() - 1]);

				}

			}

			if ((this.stringProfileSpec == null && this.stringProfileName == null)) {
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", expects either \"--profile-name\" or \"--profile-spec\" to be present");
			}
			if ((this.stringProfileSpec != null && this.stringProfileName != null)) {
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", expects either \"--profile-name\" or \"--profile-spec\" to be present");
			}
			if (this.stringTableName == null) {
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", expects \"--profile-table\" to be present");
			}
			if (this.stringProfileName != null) {
				// create profile
				super.operationName = OPERATION_createProfile;
				super.addArg(this.stringTableName, String.class, false);
				super.addArg(this.stringProfileName, String.class, false);
			} else {
				super.operationName = OPERATION_createProfileTable;
				try {
					super.addArg(this.stringProfileSpec, ProfileSpecificationID.class, true);
				} catch (Exception e) {
					throw new CommandException("Failed to parse ProfileSpecificationID: \"" + stringProfileSpec + "\"", e);
				}
				super.addArg(this.stringTableName, String.class, false);
			}

		}

		@Override
		protected String prepareResultText() {
			//FIXME: is this ok ?
			if(super.operationName.equals(OPERATION_createProfile))
			{
				return "Profile created: "+super.operationResult;
			}else
			{
				return "Profile Table created: "+super.operationResult; //??
			}
		}

	}

	private class RemoveOperation extends AbstractOperation {
		public static final char table_name = 'b';
		public static final char profile_name = 'v';

		private static final String OPERATION_removeProfile = "removeProfile";
		private static final String OPERATION_removeProfileTable = "removeProfileTable";

		private String stringTableName;
		private String stringProfileName;

		public RemoveOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			// TODO Auto-generated constructor stub
		}

		@Override
		public void buildOperation(Getopt opts, String[] args) throws CommandException {
			int code;

			while ((code = opts.getopt()) != -1) {
				switch (code) {
				case ':':
					throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

				case '?':
					throw new CommandException("Invalid (or ambiguous) option: " + args[opts.getOptind() - 1]);

				case table_name:

					this.stringTableName = opts.getOptarg();
					break;
				case profile_name:

					this.stringProfileName = opts.getOptarg();
					break;

				default:
					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
							+ "\", found unexpected opt: " + args[opts.getOptind() - 1]);

				}

			}
			if (this.stringTableName == null) {
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", expects \"--profile-table\" to be present");
			}
			super.addArg(this.stringTableName, String.class, false);
			if (this.stringProfileName == null) {
				super.operationName = OPERATION_removeProfileTable;
			} else {
				super.operationName = OPERATION_removeProfile;
				super.addArg(this.stringProfileName, String.class, false);
			}
		}

		@Override
		protected String prepareResultText() {
			//FIXME: is this ok ?
			if(super.operationName.equals(OPERATION_removeProfile))
			{
				return "Profile removed.";
			}else
			{
				return "Profile Table removed."; //??
			}
		}

	}

	private class RenameOperation extends AbstractOperation {
		public static final char current_name = 'k';
		public static final char new_name = 'j';

		private static final String OPERATION_renameProfileTable = "renameProfileTable";

		private String stringCurrentTableName;
		private String stringNewTableName;

		public RenameOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			super.operationName = OPERATION_renameProfileTable;
		}

		@Override
		public void buildOperation(Getopt opts, String[] args) throws CommandException {
			int code;

			while ((code = opts.getopt()) != -1) {
				switch (code) {
				case ':':
					throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

				case '?':
					throw new CommandException("Invalid (or ambiguous) option: " + args[opts.getOptind() - 1]);

				case current_name:

					this.stringCurrentTableName = opts.getOptarg();
					break;
				case new_name:

					this.stringNewTableName = opts.getOptarg();
					break;

				default:
					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
							+ "\", found unexpected opt: " + args[opts.getOptind() - 1]);

				}
			}
			if (this.stringCurrentTableName == null && this.stringNewTableName == null) {
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", expects both \"--current-name\" and \"--new-spec\" to be present");
			}
			super.addArg(this.stringCurrentTableName, String.class, false);
			super.addArg(this.stringNewTableName, String.class, false);

		}

		@Override
		protected String prepareResultText() {
			//FIXME: is this ok ?
			return "Profile table renamed.";
		}
	}

	private class GetOperation extends AbstractOperation {
		public static final char profile_name = 'v';
		public static final char profile_spec = 'm';
		public static final char profile = 'x';

		private static final String OPERATION_getDefaultProfile = "getDefaultProfile";
		private static final String OPERATION_getProfile = "getProfile";
		private static final String OPERATION_getProfileSpecification = "getProfileSpecification";

		// tricky.. ech
		private String stringProfileSpec_TableName; // holds table name for
		// getProfileSpecification(String
		// tableName); .. others
		// similar
		private String stringProfile_TableName;
		private String stringProfileName_Name;

		public GetOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
			super(context, log, sleeCommand);
			// TODO Auto-generated constructor stub
		}

		@Override
		public void buildOperation(Getopt opts, String[] args) throws CommandException {
			int code;

			while ((code = opts.getopt()) != -1) {
				switch (code) {
				case ':':
					throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);

				case '?':
					throw new CommandException("Invalid (or ambiguous) option: " + args[opts.getOptind() - 1]);

				case profile_name:

					this.stringProfileName_Name = opts.getOptarg();
					break;
				case profile_spec:

					this.stringProfileSpec_TableName = opts.getOptarg();
					break;
				case profile:

					this.stringProfile_TableName = opts.getOptarg();
					break;

				default:
					throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
							+ "\", found unexpected opt: " + args[opts.getOptind() - 1]);

				}

			}

			if ((this.stringProfileSpec_TableName == null && this.stringProfile_TableName == null)
					|| (this.stringProfileSpec_TableName != null && this.stringProfile_TableName != null)) {
				throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
						+ "\", expects either \"--profile\" or \"--profile-spec\" to be present");
			}
			if (this.stringProfileSpec_TableName != null) {
				super.operationName = OPERATION_getProfileSpecification;
				super.addArg(stringProfileSpec_TableName, String.class, false);
			} else {
				// its get other stuff.
				if (this.stringProfileName_Name == null) {
					// default
					super.operationName = OPERATION_getDefaultProfile;
					super.addArg(stringProfile_TableName, String.class, false);
				} else {
					super.operationName = OPERATION_getProfile;
					super.addArg(stringProfile_TableName, String.class, false);
					super.addArg(stringProfileName_Name, String.class, false);
				}
			}

		}
	}
}


/*
 * 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 java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.FileChannel;

import org.mobicents.slee.container.management.jmx.MobicentsServiceMBeanSupport;

public class DeploymentManagerMBeanImpl extends MobicentsServiceMBeanSupport implements DeploymentManagerMBeanImplMBean {

  private File tempDeployDir;
  private File deployDir;
  private File farmDeployDir;
  private final SleeContainerDeployerImpl sleeContainerDeployer;

  public DeploymentManagerMBeanImpl(SleeContainerDeployerImpl sleeContainerDeployer) {
    //this.tempDeployDir = createTempDUJarsDeploymentRoot();
    //this.deployDir = new File(ServerConfigLocator.locate().getServerHomeDir() + File.separator + "deploy");
    //this.farmDeployDir = new File(ServerConfigLocator.locate().getServerHomeDir() + File.separator + "farm");
    this.sleeContainerDeployer = sleeContainerDeployer;
  }

  /*
   * (non-Javadoc)
   * @see org.mobicents.slee.container.deployment.jboss.DeploymentManagerMBean#showStatus()
   */
  public String showStatus() {
    return sleeContainerDeployer.getDeploymentManager().showStatus();
  }

  /*
   * (non-Javadoc)
   * @see org.mobicents.slee.container.deployment.jboss.DeploymentManagerMBean#persistentInstall(java.net.URL)
   */
  public void persistentInstall(URL deployableUnitURL) throws DeploymentException {
    try {
      doPersistentInstall(deployableUnitURL, deployDir);
    }
    catch (Exception e) {
      throw new DeploymentException(e);
    }
  }

  /*
   * (non-Javadoc)
   * @see org.mobicents.slee.container.deployment.jboss.DeploymentManagerMBean#persistentUninstall(java.net.URL)
   */
  public void persistentUninstall(URL deployableUnitURL) throws DeploymentException {
    try {
      // All we really care is for the filename
      String fullPath = deployableUnitURL.getFile();
      String filename = fullPath.substring(fullPath.lastIndexOf('/') + 1);

      // Here's what we want to delete
      String filePath = deployDir + File.separator + filename;

      // Delete it
      if(!new File(filePath).delete()) {
        throw new DeploymentException("Failed to delete " + filePath);
      }
    }
    catch (Exception e) {
      throw new DeploymentException(e);
    }
  }

  /*
   * (non-Javadoc)
   * @see org.mobicents.slee.container.deployment.jboss.DeploymentManagerMBean#clusterInstall(java.net.URL)
   */
  public void clusterInstall(URL deployableUnitURL) throws DeploymentException {
    try {
      doPersistentInstall(deployableUnitURL, farmDeployDir);
    }
    catch (Exception e) {
      throw new DeploymentException(e);
    }
  }

  /*
   * (non-Javadoc)
   * @see org.mobicents.slee.container.deployment.jboss.DeploymentManagerMBean#clusterUninstall(java.net.URL)
   */
  public void clusterUninstall(URL deployableUnitURL) throws DeploymentException {
    try {
      // All we really care is for the filename
      String fullPath = deployableUnitURL.getFile();
      String filename = fullPath.substring(fullPath.lastIndexOf('/') + 1);

      // Here's what we want to delete
      String filePath = farmDeployDir + File.separator + filename;

      // Delete it
      if(!new File(filePath).delete()) {
        throw new DeploymentException("Failed to delete " + filePath);
      }
    }
    catch (Exception e) {
      throw new DeploymentException(e);
    }
  }

  /**
   *
   * @param deployableUnitURL
   * @param destinationDirectory
   * @throws Exception
   */
  private void doPersistentInstall(URL deployableUnitURL, File destinationDirectory) throws Exception {
    if(!destinationDirectory.exists()) {
      throw new IllegalArgumentException("Deploy folder " + destinationDirectory + " doesn't exist. Aborting.");
    }
    File tempFile = new File(deployableUnitURL.getFile());

    // If it's remote, we need to download it first to a local temporary folder
    if(deployableUnitURL.getProtocol().startsWith("http")) {
      tempFile = this.downloadRemoteDU(deployableUnitURL, tempDeployDir);
      deployableUnitURL = tempFile.toURI().toURL();
    }

    // Copy the file to deploy folder
    copyLocalFile(tempFile, new File(destinationDirectory + File.separator + tempFile.getName()));
  }

  /**
   * Downloads a remote DU to a local folder
   *
   * @param duURL URL where the DU can be fetched from
   * @param deploymentRoot the location where it will be saved to
   * @return a File related to the downloaded DU
   * @throws Exception
   */
  private File downloadRemoteDU(URL duURL, File deploymentRoot) throws Exception {
    InputStream in = null;
    OutputStream out = null;

    try {
      // Get the filename out of the URL
      String filename = new File(duURL.getPath()).getName();

      // Prepare for creating the file at deploy folder
      File tempFile = new File(deploymentRoot, filename);

      out = new BufferedOutputStream(new FileOutputStream(tempFile));
      URLConnection conn = duURL.openConnection();
      in = conn.getInputStream();

      // Get the data
      byte[] buffer = new byte[1024];
      int numRead;
      while ((numRead = in.read(buffer)) != -1) {
        out.write(buffer, 0, numRead);
      }

      // Done! Successful.
      return tempFile;
    }
    finally {
      // Do the clean up.
      try {
        if (in != null) {
          in.close();
          in = null;
        }
        if (out != null) {
          out.close();
          out = null;
        }
      }
      catch (IOException ioe) {
        // Shouldn't happen, let's ignore.
      }
    }
  }

  /**
   * Copies a file from a location to another, using NIO FileChannel.
   *
   * @param sourceFile the source file
   * @param destFile the destination file
   * @throws IOException if it's not possible to copy the file
   */
  private void copyLocalFile(File sourceFile, File destFile) throws IOException {
    if(!destFile.exists()) {
      destFile.createNewFile();
    }

    FileChannel source = null;
    FileChannel destination = null;
    try {
      source = new FileInputStream(sourceFile).getChannel();
      destination = new FileOutputStream(destFile).getChannel();
      destination.transferFrom(source, 0, source.size());
    }
    finally {
      if(source != null) {
        source.close();
      }
      if(destination != null) {
        destination.close();
      }
    }
  }

  /**
   * Initializes the temporary deploy folder, if necessary.
   *
   * @return a File object pointing to the temporary deploy folder
   */
  private File createTempDUJarsDeploymentRoot() {
    /*
	  File tempDeploymentRootDir = ServerConfigLocator.locate().getServerTempDeployDir();
    if (!tempDeploymentRootDir.exists()) {
      if (!tempDeploymentRootDir.mkdirs()) {
        throw new RuntimeException("Failed to create temp deployment dir: " + tempDeploymentRootDir);
      }
    }
    return tempDeploymentRootDir;
    */
	return null;
  }
}


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

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

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingDeque;

import javax.slee.ComponentID;
import javax.slee.InvalidStateException;
import javax.slee.management.DependencyException;
import javax.slee.management.ResourceAdaptorEntityAlreadyExistsException;
import javax.slee.management.UnrecognizedLinkNameException;

import org.jboss.logging.Logger;
import org.mobicents.slee.container.component.ComponentRepository;
import org.mobicents.slee.container.deployment.jboss.action.ActivateResourceAdaptorEntityAction;
import org.mobicents.slee.container.deployment.jboss.action.CreateResourceAdaptorEntityAction;
import org.mobicents.slee.container.deployment.jboss.action.DeactivateResourceAdaptorEntityAction;
import org.mobicents.slee.container.deployment.jboss.action.DeactivateServiceAction;
import org.mobicents.slee.container.deployment.jboss.action.ManagementAction;
import org.mobicents.slee.container.deployment.jboss.action.RemoveResourceAdaptorEntityAction;
import org.mobicents.slee.container.deployment.jboss.action.UnbindLinkNameAction;
import org.mobicents.slee.container.management.ResourceManagement;

/**
 * This class represents the Manager responsible for executing deployment actions
 * and for controlling dependencies and monitoring new deployments using the deployer.
 *
 * @author Alexandre Mendonça
 * @author martins
 * @version 1.0
 */
public class DeploymentManager {

  // The Logger.
  private static Logger logger = Logger.getLogger(DeploymentManager.class);

  // The DUs waiting to be installed.
  private Collection<DeployableUnit> waitingForInstallDUs = new ConcurrentLinkedQueue<DeployableUnit>();

  // The DUs waiting for being uninstalled.
  private Collection<DeployableUnit> waitingForUninstallDUs = new ConcurrentLinkedQueue<DeployableUnit>();

  // The DUs waiting for being uninstalled.
  private LinkedBlockingDeque<DeployableUnit> deployedDUs = new LinkedBlockingDeque<DeployableUnit>();

  // The components already deployed to SLEE
  private Collection<String> deployedComponents = new ConcurrentLinkedQueue<String>();

  private ConcurrentHashMap<DeployableUnit, Collection<Class<? extends ManagementAction>>> actionsToAvoidByDU = new ConcurrentHashMap<DeployableUnit, Collection<Class<? extends ManagementAction>>>();

  public long waitTimeBetweenOperations = 250;

  private final SleeContainerDeployerImpl sleeContainerDeployer;

  public DeploymentManager(SleeContainerDeployerImpl sleeContainerDeployer) {
	this.sleeContainerDeployer = sleeContainerDeployer;
  }

  /**
   * Updates the list of components already deployed to SLEE.
   */
  public void updateDeployedComponents() {
    try {
      // Get the SLEE Component Repo
      ComponentRepository componentRepository = sleeContainerDeployer.getSleeContainer().getComponentRepository();

      // First we'll put the components in a temp Collection
      ConcurrentLinkedQueue<String> newDeployedComponents = new ConcurrentLinkedQueue<String>();

      // Get the deployed Profile Specifications
      for (ComponentID componentID: componentRepository.getProfileSpecificationIDs()) {
        newDeployedComponents.add(componentID.toString());
      }

      // Get the deployed Event Types
      for (ComponentID componentID: componentRepository.getEventComponentIDs()) {
        newDeployedComponents.add(componentID.toString());
      }

      // Get the deployed Resource Adaptor Types
      for (ComponentID componentID: componentRepository.getResourceAdaptorTypeIDs()) {
        newDeployedComponents.add(componentID.toString());
      }

      // Get the deployed Resource Adaptors
      for (ComponentID componentID: componentRepository.getResourceAdaptorIDs()) {
        newDeployedComponents.add(componentID.toString());
      }

      // Get the deployed Service Building Blocks (SBBs)
      for (ComponentID componentID: componentRepository.getSbbIDs()) {
        newDeployedComponents.add(componentID.toString());
      }

      // Get the deployed Services
      for (ComponentID componentID: componentRepository.getServiceIDs()) {
        newDeployedComponents.add(componentID.toString());
      }

      // Get the deployed Libraries
      for (ComponentID componentID: componentRepository.getLibraryIDs()) {
        newDeployedComponents.add(componentID.toString());
      }

      ResourceManagement resourceManagement = sleeContainerDeployer.getSleeContainer().getResourceManagement();

      // Get the existing Resource Adaptor Entity links
      String[] entityNames = resourceManagement.getResourceAdaptorEntities();

      for (String entityName : entityNames) {
        newDeployedComponents.addAll(Arrays.asList(resourceManagement.getLinkNames(entityName)));
      }

      // All good.. Make the temp the good one.
      deployedComponents = newDeployedComponents;
    }
    catch (Exception e) {
      logger.warn("Failure while updating deployed components.", e);
    }
  }

  /**
   * Method for installing a Deployable Unit into SLEE.
   * @param du the Deployable Unit to install.
   * @throws Exception
   */
  public void installDeployableUnit(DeployableUnit du) throws Exception {

    // Update the deployed components from SLEE
    updateDeployedComponents();

    // Check if the DU is ready to be installed
    if (du.isReadyToInstall(true)) {
      // Get and Run the actions needed for installing this DU
      sciAction(du.getInstallActions(), du);

      // Set the DU as installed
      du.setInstalled(true);

      // Add the DU to the installed list
      deployedDUs.add(du);

      // Update the deployed components from SLEE
      updateDeployedComponents();

      // Go through the remaining DUs waiting for installation
      Iterator<DeployableUnit> duIt = waitingForInstallDUs.iterator();

      while (duIt.hasNext()) {
        DeployableUnit waitingDU = duIt.next();

        // If it is ready for installation, follow the same procedure
        if (waitingDU.isReadyToInstall(false)) {
          // Get and Run the actions needed for installing this DU
          sciAction(waitingDU.getInstallActions(), waitingDU);

          // Set the DU as installed
          waitingDU.setInstalled(true);

          // Add the DU to the installed list
          deployedDUs.add(waitingDU);

          // Update the deployed components from SLEE
          updateDeployedComponents();

          // Remove the DU from the waiting list.
          waitingForInstallDUs.remove(waitingDU);

          // Let's start all over.. :)
          duIt = waitingForInstallDUs.iterator();
        }
      }
    }
    else {
      logger.warn("Unable to INSTALL " + du.getDeploymentInfoShortName() + " right now. Waiting for dependencies to be resolved.");

      // The DU can't be installed now, let's wait...
      waitingForInstallDUs.add(du);
    }
  }

  /**
   * Method for uninstalling a Deployable Unit into SLEE.
   * @param du the Deployable Unit to install.
   * @throws Exception
   */
  public void uninstallDeployableUnit(DeployableUnit du) throws Exception {

    // Update the deployed components from SLEE
    updateDeployedComponents();

    // It isn't installed?
    if (!du.isInstalled()) {
      // Then it should be in the waiting list... remove and we're done.
      if (waitingForInstallDUs.remove(du)) {
        logger.info(du.getDeploymentInfoShortName() + " wasn't deployed. Removing from waiting list.");
      }
    }
    // Check if DU components are still present
    else if (!du.areComponentsStillPresent()) {
      logger.info(du.getDeploymentInfoShortName() + " components already removed. Removing DU info.");

      // Process internals of undeployment...
      processInternalUndeploy(du);
    }
    // Check if the DU is ready to be uninstalled
    else if (du.isReadyToUninstall()) {
      // Get and Run the actions needed for uninstalling this DU
      sciAction(du.getUninstallActions(), du);

      // Process internals of undeployment...
      processInternalUndeploy(du);
    }
    else {
      // Have we been her already? If so, don't flood user with log messages...
      if (!waitingForUninstallDUs.contains(du)) {
        // Add it to the waiting list.
        waitingForUninstallDUs.add(du);
        logger.warn("Unable to UNINSTALL " + du.getDeploymentInfoShortName() + " right now. Waiting for dependents to be removed.");
      }
      throw new DependencyException("Unable to undeploy "+du.getDeploymentInfoShortName());
    }
  }

  /**
   * Sets the DU as not installed and remove it from waiting list if present there.
   * Also, tries to undeploy DU's waiting for dependencies to be removed.
   *
   * @param du the DeployableUnit that was just removed
   * @throws Exception
   */
  private void processInternalUndeploy(DeployableUnit du) throws Exception {
    // Set the DU as not installed
    du.setInstalled(false);

    // Remove if it was present in waiting list
    waitingForUninstallDUs.remove(du);

    // Update the deployed components from SLEE
    updateDeployedComponents();

    // Go through the remaining DUs waiting for uninstallation
    Iterator<DeployableUnit> duIt = waitingForUninstallDUs.iterator();

    while (duIt.hasNext()) {
      DeployableUnit waitingDU = duIt.next();

      // If it is ready for being uninstalled, follow the same procedure
      if (waitingDU.isReadyToUninstall()) {
        // Schedule removal
        sleeContainerDeployer.getSleeSubDeployer().stop(waitingDU.getURL(), waitingDU.getDeploymentInfoShortName());

        // Remove the DU from the waiting list. If it fails, will go back.
        waitingForUninstallDUs.remove(waitingDU);

        // Let's start all over.. :)
        duIt = waitingForUninstallDUs.iterator();
      }
    }
  }

  /**
   * Method for performing the actions needed for (un)deployment.
   * @param actions the array of strings containing the actions to perform.
   * @param du the DeployableUnit from where the actions are being performed.
   * @throws Exception
   */
  private void sciAction(Collection<ManagementAction> actions, DeployableUnit du)
  throws Exception {

    // For each action, get the params..
    for (ManagementAction action : actions) {

      // Shall we skip this action?
      if (actionsToAvoidByDU.get(du) != null && actionsToAvoidByDU.get(du).remove(action)) {
        // Clean if it was the last one.
        if (actionsToAvoidByDU.get(du).size() == 0) {
          actionsToAvoidByDU.remove(du);
        }
        continue;
      }

      if (logger.isTraceEnabled()) {
        logger.trace("Invoking " + action);
      }

      // We are isolating each action, so it won't affect the whole proccess
      try {
        // Invoke it.
        action.invoke();
        // We need to wait for service/entity to deactivate...
        /*if(action instanceof DeactivateServiceAction) {
          waitForServiceDeactivation((DeactivateServiceAction) action);
        }
        else if (action instanceof DeactivateResourceAdaptorEntityAction) {
          waitForResourceAdaptorEntityDeactivation((DeactivateResourceAdaptorEntityAction) action);
        }*/
      }
      catch (Exception e) {
        // We might expect some exceptions...
        if (e.getCause() instanceof ResourceAdaptorEntityAlreadyExistsException || (e.getCause() instanceof InvalidStateException
            && action instanceof ActivateResourceAdaptorEntityAction)) {
          Class<? extends ManagementAction> actionToAvoid = null;

          // If the activate/create failed then we don't want to deactivate/remove
          if (action instanceof ActivateResourceAdaptorEntityAction) {
            actionToAvoid = DeactivateResourceAdaptorEntityAction.class;
          }
          else if (action instanceof CreateResourceAdaptorEntityAction) {
            actionToAvoid = RemoveResourceAdaptorEntityAction.class;
          }

          Collection<Class<? extends ManagementAction>> actionsToAvoid;
          if ((actionsToAvoid = actionsToAvoidByDU.get(du)) == null) {
            actionsToAvoid = new ArrayList<Class<? extends ManagementAction>>();

            // Add it to the list of actions to skip on undeploy
            actionsToAvoid.add(actionToAvoid);

            // And put it to the map
            actionsToAvoidByDU.put(du, actionsToAvoid);
          }
          else {
            // Add it to the list of actions to skip on undeploy
            actionsToAvoid.add(actionToAvoid);
          }

          logger.warn(e.getCause().getMessage());
        }
        else if (e.getCause() instanceof InvalidStateException && action instanceof DeactivateServiceAction) {
          logger.info("Delaying uninstall due to service deactivation not complete.");
        }
        else if (e.getCause() instanceof InvalidStateException && action instanceof DeactivateResourceAdaptorEntityAction) {
          // ignore this... someone has already deactivated the link.
        }
        else if (e.getCause() instanceof UnrecognizedLinkNameException && action instanceof UnbindLinkNameAction) {
          // ignore this... someone has already removed the link.
        }
        else if (action.getType() == ManagementAction.Type.DEPLOY_MANAGEMENT) {
          logger.error("Failure invoking '" + action, e);
        }
        else {
          throw e;
        }
      }

      // Wait a little while just to make sure it finishes
      Thread.sleep(waitTimeBetweenOperations);
    }
  }

  /**
   * Getter for the Deployed Components collection.
   * @return a Collection of Strings with the deployed components IDs.
   */
  public Collection<String> getDeployedComponents() {
    return deployedComponents;
  }

  public Collection<DeployableUnit> getWaitingForInstallDUs() {
	return waitingForInstallDUs;
  }

  /**
   * Method for showing current status of the Deployment Manager.
   * @return a HTML string with the status.
   */
  public String showStatus() {
    // Update the currently deployed components.
    updateDeployedComponents();

    String output = "";

    output += "
Deployable Units Waiting For Install:
";
    for (DeployableUnit waitingDU : waitingForInstallDUs) {
      output += "+-- " + waitingDU.getDeploymentInfoShortName() + "
";
      for (String dependency : waitingDU.getExternalDependencies()) {
        if (!deployedComponents.contains(dependency))
          dependency += " MISSING!";

        output += "  +-- depends on " + dependency + "
";
      }
    }

    output += "
Deployable Units Waiting For Uninstall:
";
    for (DeployableUnit waitingDU : waitingForUninstallDUs) {
      output += "+-- " + waitingDU.getDeploymentInfoShortName() + "
";
    }

    return output;
  }

  /**
   * Callback for {@link SleeStateJMXMonitor}, to learn when SLEE is stopping.
   */
  public void sleeShutdown() {
	  logger.info("Undeploying all Deployable Units due to SLEE shutdown");
	  // undeploy each DU in reverse order
	  while(!deployedDUs.isEmpty()) {
		  DeployableUnit du = deployedDUs.removeLast();
		  try {
			  uninstallDeployableUnit(du);
		  }
		  catch (Exception e) {
			  logger.error("Failed to uninstall DU, in SLEE shutdown",e);
		  }
	  }
  }

  /*
  private boolean waitForServiceDeactivation(DeactivateServiceAction action) throws InterruptedException, NullPointerException, UnrecognizedServiceException, ManagementException {

    long waited = 0;

    final ServiceManagement serviceManagement = sleeContainerDeployer.getSleeContainer().getServiceManagement();

    ServiceState ss = serviceManagement.getState(action.getServiceID());

    if(logger.isTraceEnabled()) {
		logger.trace(action.getServiceID() + " Initial State [" + ss.toString() + "].");
    }

    double maxWaitTime = 60 * 1000 * MobicentsManagement.entitiesRemovalDelay;

    while(!ss.isInactive() && waited <= maxWaitTime) {
      ss = serviceManagement.getState(action.getServiceID());

      if(logger.isTraceEnabled()) {
    	  logger.trace(action.getServiceID() + " State [" + ss.toString() + "]. Waiting more " + waitTimeBetweenOperations + "ms. Waited a total of " + waited + "ms." );
      }

      Thread.sleep(waitTimeBetweenOperations);
      waited += waitTimeBetweenOperations;
    }

    return ss.isInactive();
  }

  private boolean waitForResourceAdaptorEntityDeactivation(DeactivateResourceAdaptorEntityAction action) throws InterruptedException, NullPointerException, UnrecognizedResourceAdaptorEntityException {

    long waited = 0;

    final ResourceManagement resourceManagement = sleeContainerDeployer.getSleeContainer().getResourceManagement();

    ResourceAdaptorEntityState raes = resourceManagement.getState(action.getRaEntity());

    if(logger.isTraceEnabled()) {
		logger.trace(action.getRaEntity() + " RA Entity Initial State [" + raes.toString() + "].");
    }

    double maxWaitTime = 60 * 1000 * MobicentsManagement.entitiesRemovalDelay;

    while(!raes.isInactive() && waited <= maxWaitTime) {

      raes = resourceManagement.getState(action.getRaEntity());

      if(logger.isTraceEnabled()) {
		logger.trace(action.getRaEntity() + " RA Entity State [" + raes.toString() + "]. Waiting more " + waitTimeBetweenOperations + "ms. Waited a total of " + waited + "ms." );
      }

      Thread.sleep(waitTimeBetweenOperations);
      waited += waitTimeBetweenOperations;
    }

    return raes.isInactive();
  }
 */

}


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

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Filter;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.SimpleFormatter;

import org.apache.log4j.Logger;

/**
 * This filter is used to convert java.util.logging messages from the JUL
 * to Log4J messages.
 *
 * @author Stan Silvert
 * @author Pete Muir
 * @author Alexandre Mendonca
 */
public class MobicentsLogFilter implements Filter
{

  // cache Logger instances.  Logger.getLogger() is known to be slow.
  // See http://www.qos.ch/logging/thinkAgain.jsp
  private Map<String, Logger> loggerCache = new HashMap<String, Logger>();

  private Formatter formatter = new SimpleFormatter();

  /**
   * If the message should be logged, convert the JDK 1.4
   * LogRecord to a Log4J message.
   *
   * @return false because JDK 1.4 logging should not happen
   *         if this filter is active.
   */
  public boolean isLoggable(LogRecord record)
  {

    Logger logger = getLogger(record);

    if (record.getThrown() != null)
    {
      logWithThrowable(logger, record);
    }
    else
    {
      logWithoutThrowable(logger, record);
    }

    return false;
  }

  private void logWithThrowable(Logger logger, LogRecord record)
  {
    int loggedLevel = record.getLevel().intValue();
    Object message = formatter.formatMessage(record);
    Throwable throwable = record.getThrown();

    if (loggedLevel == Level.SEVERE.intValue())
    {
      logger.error(message, throwable);
      return;
    }

    if (loggedLevel == Level.WARNING.intValue())
    {
      logger.warn(message, throwable);
      return;
    }

    if ((loggedLevel == Level.INFO.intValue()) ||
        (loggedLevel == Level.CONFIG.intValue()))
    {
      logger.info(message, throwable);
      return;
    }

    if (loggedLevel == Level.FINE.intValue())
    {
      logger.debug(message, throwable);
      return;
    }

    if ((loggedLevel == Level.FINER.intValue()) ||
        (loggedLevel == Level.FINEST.intValue()))
    {
      logger.trace(message, throwable);
      return;
    }

    logger.info(message, throwable);
  }

  private void logWithoutThrowable(Logger logger, LogRecord record)
  {
    int loggedLevel = record.getLevel().intValue();
    Object message = formatter.formatMessage(record);

    if (loggedLevel == Level.SEVERE.intValue())
    {
      logger.error(message);
      return;
    }

    if (loggedLevel == Level.WARNING.intValue())
    {
      logger.warn(message);
      return;
    }

    if ((loggedLevel == Level.INFO.intValue()) ||
        (loggedLevel == Level.CONFIG.intValue()))
    {
      logger.info(message);
      return;
    }

    if (loggedLevel == Level.FINE.intValue())
    {
      logger.debug(message);
      return;
    }

    if ((loggedLevel == Level.FINER.intValue()) ||
        (loggedLevel == Level.FINEST.intValue()))
    {
      logger.trace(message);
      return;
    }

    logger.info(message);
  }

  // get the Log4J logger corresponding to the java.util.logger.LogRecord
  private Logger getLogger(LogRecord record)
  {
    String loggerName = record.getLoggerName();
    Logger logger = loggerCache.get(loggerName);
    if (logger == null)
    {
      logger = Logger.getLogger(loggerName);
      loggerCache.put(loggerName, logger);
    }

    return logger;
  }
}