package javax.slee.management;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.rmi.MarshalledObject;
import javax.management.Notification;
import javax.slee.facilities.AlarmLevel;
import javax.slee.facilities.Level;

/**
 * Notifications of this type are emitted by an {@link AlarmMBean} to indicate that
 * some component or subsystem in the SLEE is experiencing a problem.  Typically, a
 * SLEE component uses the {@link javax.slee.facilities.AlarmFacility AlarmFacility}
 * to manage alarms.
 *

 * Alarm notifications contain a {@link NotificationSource} object that can be used
 * to obtain more information about the object that raised the alarm.  The type of
 * an alarm notification can be used to infer the type of the notification source
 * object contained in the notification:
 *

 *
if {@link #getType()} == {@link javax.slee.management.SbbNotification#ALARM_NOTIFICATION_TYPE}
 *       then the type of the notification source object is {@link javax.slee.management.SbbNotification}.
 *
if {@link #getType()} == {@link javax.slee.management.ResourceAdaptorEntityNotification#ALARM_NOTIFICATION_TYPE}
 *       then the type of the notification source object is {@link javax.slee.management.ResourceAdaptorEntityNotification}.
 *
if {@link #getType()} == {@link javax.slee.management.ProfileTableNotification#ALARM_NOTIFICATION_TYPE}
 *       then the type of the notification source object is {@link javax.slee.management.ProfileTableNotification}.
 *
if {@link #getType()} == {@link javax.slee.management.SubsystemNotification#ALARM_NOTIFICATION_TYPE}
 *       then the type of the notification source object is {@link javax.slee.management.SubsystemNotification}.
 *

 *

 * As of SLEE 1.1, serialization of this class has been modified to take into account cause
 * Throwable objects that may not be deserializable client-side due to classloader
 * issues.  For example, if the cause of an alarm is an object of a custom exception
 * class included in the deployable unit of a component, a generic client may not have
 * that class available in its classpath or be able to load it via Java's remote class loading
 * mechanisms (eg. the codebase URL could be a file:// URL on a different host
 * that cannot be resolved on the client host).  Serialization of an AlarmNotification
 * object containing a cause now includes the stack trace of that cause in the serialization
 * stream.  If the cause Throwable cannot be later deserialized with the
 * AlarmNotification object, a generic java.lang.Exception
 * with a message containing the original stack trace is returned as the alarm's cause
 * instead.
 */
public final class AlarmNotification extends Notification implements VendorExtensions {
    /**
     * Create an AlarmNotification to notify listeners of a alarm.
     * @param alarmMBean the AlarmMBean object that is emitting
     *        this notification.
     * @param alarmType the type of the alarm being generated. Typically a management client
     *        should be able to infer the type of the alarmSource object by
     *        inspecting this type.
     * @param alarmSource an object that identifies the object that generated the alarm, for
     *        example an {@link javax.slee.SbbID}.
     * @param alarmLevel the alarm level.
     * @param message the alarm message.
     * @param cause an optional cause for the alarm.
     * @param sequenceNumber the notification sequence number within the source
     *        AlarmMBean object.
     * @param timestamp the time (in ms since January 1, 1970 UTC) that the alarm was generated.
     * @throws NullPointerException if notificationSource, alarmType,
     *        alarmLevel, or message is null.
     * @throws IllegalArgumentException if alarmLevel ==  {@link Level#OFF}.
     * @deprecated Alarm notifications have been expanded with new attributes to take advantage
     *        of the new features provided by the SLEE specification.  The
     *        {@link #AlarmNotification(String,AlarmMBean,String,NotificationSource,String,String,AlarmLevel,String,Throwable,long,long)}
     *        constructor should be used instead of this constructor.
     */
    public AlarmNotification(AlarmMBean alarmMBean, String alarmType, Object alarmSource, Level alarmLevel, String message, Throwable cause, long sequenceNumber, long timestamp) throws NullPointerException, IllegalArgumentException {
        super(AlarmMBean.ALARM_NOTIFICATION_TYPE, alarmMBean, sequenceNumber, timestamp, message);

        if (alarmMBean == null) throw new NullPointerException("alarmMBean is null");
        if (alarmType == null) throw new NullPointerException("alarmType is null");
        if (alarmLevel == null) throw new NullPointerException("alarmLevel is null");
        if (message == null) throw new NullPointerException("message is null");

        if (alarmLevel.isOff()) throw new IllegalArgumentException("alarmLevel cannot be Level.OFF");

        this.alarmType = alarmType;
        this.alarmSource = alarmSource;
        this.level_10 = alarmLevel;
        this.cause = cause;

        // forward compatibility
        this.alarmID = null;
        this.notificationSource = null;
        this.instanceID = null;
        this.level_11 = null;
    }

    /**
     * Create an AlarmNotification to notify listeners of an alarm.
     * @param type the JMX type of the notification.  The type of the notification
     *        is typically obtained from the NotificationSource parameter
     *        when this notification object is created, and can be used by notification
     *        listeners to infer the type of the NotificationSource and
     *        hence obtain further information about the source of the notification.
     * @param alarmMBean the AlarmMBean object that is emitting this
     *        notification.
     * @param alarmID the unique alarm identifier for the alarm.
     * @param notificationSource the component or subsystem in the SLEE that raised
     *        the alarm.
     * @param alarmType an identifier specifying the type of the alarm.
     * @param instanceID an identifier specifying the particular instance of the
     *        alarm type that is occurring.
     * @param alarmLevel the alarm level of the notification.  This could be {@link AlarmLevel#CLEAR}
     *        if the alarm has been cleared.
     * @param message the alarm message.
     * @param cause an optional cause for the alarm notification.
     * @param sequenceNumber the notification sequence number within the source
     *        AlarmMBean object.
     * @param timestamp the time (in ms since January 1, 1970 UTC) that the alarm was raised,
     *        updated, or cleared.
     * @throws NullPointerException if type, alarmMBean,
     *        alarmID, notificationSource, alarmType,
     *        instanceID, alarmLevel, or message
     *        is null.
     * @since SLEE 1.1
     */
    public AlarmNotification(String type, AlarmMBean alarmMBean, String alarmID, NotificationSource notificationSource, String alarmType, String instanceID, AlarmLevel alarmLevel, String message, Throwable cause, long sequenceNumber, long timestamp) throws NullPointerException {
        super(type, alarmMBean, sequenceNumber, timestamp, message);

        if (type == null) throw new NullPointerException("type is null");
        if (alarmMBean == null) throw new NullPointerException("alarmMBean is null");
        if (alarmID == null) throw new NullPointerException("alarmID is null");
        if (notificationSource == null) throw new NullPointerException("notificationSource is null");
        if (alarmType == null) throw new NullPointerException("alarmType is null");
        if (instanceID == null) throw new NullPointerException("instanceID is null");
        if (alarmLevel == null) throw new NullPointerException("alarmLevel is null");
        if (message == null) throw new NullPointerException("message is null");

        this.alarmID = alarmID;
        this.notificationSource = notificationSource;
        this.alarmType = alarmType;
        this.instanceID = instanceID;
        this.level_11 = alarmLevel;
        this.cause = cause;

        // backward compatibility
        this.alarmSource = notificationSource;
        this.level_10 = Level.INFO;
    }

    /**
     * Get the unique alarm identifier of the alarm.
     * @return the alarm identifier of the alarm.  Returns null for
     *        SLEE 1.0-compliant notifications.
     * @since SLEE 1.1
     */
    public String getAlarmID() {
        return alarmID;
    }

    /**
     * Get the object that identifies the component or subsystem in the SLEE that
     * raised the alarm.
     * @return the notification source.  Returns null for SLEE 1.0-compliant
     *        notifications.
     * @since SLEE 1.1
     */
    public NotificationSource getNotificationSource() {
        return notificationSource;
    }

    /**
     * Get the type of the alarm.
     * @return the alarm type.
     */
    public String getAlarmType() {
        return alarmType;
    }

    /**
     * Get the object that identifies the source of the alarm.
     * @return the alarm source.  Returns the value of {@link #getNotificationSource()}
     *        for SLEE 1.1-compliant notifications.
     * @deprecated Replaced with {@link #getNotificationSource()}.
     */
    public Object getAlarmSource() {
        return alarmSource;
    }

    /**
     * Get the instance identifier of the alarm type.
     * @return the instance identifier.  Returns null for SLEE 1.0-compliant
     *        notifications.
     * @since SLEE 1.1
     */
    public String getInstanceID() {
        return instanceID;
    }

    /**
     * Get the alarm level of the alarm.
     * @return the alarm level.  Returns {@link Level#INFO} for SLEE 1.1-compliant notifications.
     * @deprecated Trace and alarm levels have been split into different classes.
     *       Replaced with {@link #getAlarmLevel}.
     */
    public Level getLevel() {
        return level_10;
    }

    /**
     * Get the alarm level of the alarm notification.
     * @return the alarm level.  Returns null for SLEE 1.0-compliant
     *        notifications.
     * @since SLEE 1.1
     */
    public AlarmLevel getAlarmLevel() {
        return level_11;
    }

    /**
     * Get the cause for the alarm.
     *

     * For SLEE 1.1-compliant notifications, this method returns the cause provided
     * when the alarm was raised.  For SLEE 1.0-compliant notifications, this method
     * returns the cause provided when the alarm notification was generated.
     * @return the cause of this alarm, or null if no cause was
     *        provided.
     */
    public Throwable getCause() {
        return cause;
    }

    /**
     * Enable the serialization of vendor-specific data for objects of this class.
     * This method is typically used by a SLEE implementation that wants to export
     * vendor-specific data with objects of this class to management clients.
     *

     * By default, any vendor-specific data included in an object of this class will
     * not be included in the serialization stream when the object is serialized.
     * Invoking this method changes this behavior so that vendor-specific data is
     * included in the serialization stream when an object of this class is serialized.
     *

     * This method should only be invoked if the vendor-specific data is serializable
     * via standard Java serialization means.
     * @since SLEE 1.1
     * @see #disableVendorDataSerialization
     * @see #setVendorData
     */
    public static void enableVendorDataSerialization() {
        vendorDataSerializationEnabled = true;
    }

    /**
     * Disable the serialization of vendor-specific data for objects of this class.
     *

     * If the serialization of vendor-specific data for objects of this class has
     * been enabled via the {@link #enableVendorDataSerialization} method, this
     * method disables that behavior again.
     * @since SLEE 1.1
     */
    public static void disableVendorDataSerialization() {
        vendorDataSerializationEnabled = false;
    }

    /**
     * Enable the deserialization of vendor-specific data for objects of this class.
     * This method is typically used by a management client that wants to obtain any
     * vendor-specific data included in the serialization stream of objects of this
     * class.
     *

     * By default, any vendor-specific data included in the serialization stream of
     * objects of this class is discarded upon deserialization.  Invoking this method
     * changes that behavior so that the vendor-specific data is also deserialized
     * when an object of this class is deserialized.  A management client that enables
     * the deserialization of vendor-specific data must ensure that any necessary
     * classes required to deserialize that data is available in the relevant
     * classloader.
     * @since SLEE 1.1
     * @see #disableVendorDataDeserialization
     * @see #getVendorData
     */
    public static void enableVendorDataDeserialization() {
        vendorDataDeserializationEnabled = true;
    }

    /**
     * Disable the deserialization of vendor-specific data for objects of this class.
     *

     * If the deserialization of vendor-specific data for objects of this class has
     * been enabled via the {@link #enableVendorDataDeserialization} method, this
     * method disables that behavior again.
     * @since SLEE 1.1
     */
    public static void disableVendorDataDeserialization() {
        vendorDataDeserializationEnabled = false;
    }

    /**
     * Set the vendor-specific data.
     * @param vendorData the vendor-specific data.
     * @since SLEE 1.1
     */
    public void setVendorData(Object vendorData) {
        this.vendorData = vendorData;
    }

    /**
     * Get the vendor-specific data.
     * @return the vendor-specific data.
     * @since SLEE 1.1
     */
    public Object getVendorData() {
        return vendorData;
    }

    /**
     * Compare this notification for equality with another object.
     *

     * For backwards compatibility, this method performs either a SLEE 1.0-based comparison or
     * a SLEE 1.1-based comparison based on the state of this notification object.  If this
     * notification contains a non-null alarm source reference, a SLEE 1.0-based comparison
     * is performed, using the SLEE 1.0 alarm levels.  Otherwise, a SLEE 1.1-based comparison
     * is performed using the SLEE 1.1 alarm levels.
     *

     * The SLEE 1.0-based comparison considers two notifications to be equal if obj
     * is an instance of this class and the alarm type, alarm source, SLEE 1.0 alarm level, and
     * message attributes of obj are the same as the corresponding attributes of
     * this.
     *

     * The SLEE 1.1-based comparison considers two notifications to be equal if obj
     * if an instance of this class and the alarm identifier, notification source, alarm type,
     * alarm instance ID, SLEE 1.1 alarm level, and message attributes of obj are
     * the same as the corresponding attributes of this.
     *

     * Note that a SLEE 1.0-compliant alarm notification can never be equal to a SLEE 1.1-compliant
     * alarm notification.
     * @param obj the object to compare this with.
     * @return true if obj is equal to this according to
     *        the rules specified above, false otherwise.
     */
    public boolean equals(Object obj) {
        if (obj == this) return true;
        if (!(obj instanceof AlarmNotification)) return false;

        AlarmNotification that = (AlarmNotification)obj;
        if (this.notificationSource == null) {
            // SLEE 1.0
            // is 'that' a SLEE 1.0 notification?
            if (that.notificationSource != null) return false;

            return (this.alarmType.equals(that.alarmType))
                && (this.alarmSource.equals(that.alarmSource))
                && (this.level_10.equals(that.level_10))
                && (this.getMessage().equals(that.getMessage()));
        }
        else {
            // SLEE 1.1
            // is that a SLEE 1.1 notification?
            if (that.notificationSource == null) return false;

            return (this.alarmID.equals(that.alarmID))
                && (this.notificationSource.equals(that.notificationSource))
                && (this.alarmType.equals(that.alarmType))
                && (this.instanceID.equals(that.instanceID))
                && (this.level_11.equals(that.level_11))
                && (this.getMessage().equals(that.getMessage()));
        }
    }

    /**
     * Get a hash code value for this notification.  For SLEE 1.1-compliant alarm
     * notifications this is the hash code of the unique alarm identifier.  For
     * SLEE 1.0-compliant notifications this is the hash code of the notification's
     * message.
     * @return a hash code for this notification.
     */
    public int hashCode() {
        return (this.level_10 != null) ? getMessage().hashCode() : alarmID.hashCode();
    }

    /**
     * Get a string representation for this notification.
     * @return a string representation for this notification.
     */
    public String toString() {
        StringBuffer buf = new StringBuffer();
        buf.append("AlarmNotification[");
        if (notificationSource == null) {
            // generate a SLEE 1.0 message
            buf.append("type=").append(getType()).
                append(",timestamp=").append(getTimeStamp()).
                append(",alarmType=").append(alarmType).
                append(",source=").append(alarmSource).
                append(",level=").append(level_10).
                append(",message=").append(getMessage()).
                append(",cause=").append(cause);
        }
        else {
            // generate a SLEE 1.1 message
            buf.append("type=").append(getType()).
                append(",id=").append(alarmID).
                append(",source=").append(notificationSource).
                append(",alarmType=").append(alarmType).
                append(",instanceID=").append(instanceID).
                append(",level=").append(level_11).
                append(",message=").append(getMessage()).
                append(",cause=").append(cause).
                append(",timestamp=").append(getTimeStamp());
        }
        if (vendorData != null) buf.append(",vendor data=").append(vendorData);
        buf.append("]");
        return buf.toString();
    }

    // special handling of serialization
    private void writeObject(ObjectOutputStream out) throws IOException {
        VendorExtensionUtils.writeObject(out, vendorDataSerializationEnabled ? vendorData : null);

        if (cause != null) {
            out.writeBoolean(true);
            // serialize the cause inside a marshalled object to isolate
            // the serialized data for it in the stream
            out.writeObject(new MarshalledObject(cause));

            // serialize a text form of the stack trace
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            cause.printStackTrace(pw);
            pw.flush();
            out.writeUTF(sw.getBuffer().toString());
        }
        else {
            out.writeBoolean(false);
        }
    }

    // special handling of deserialization
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        vendorData = VendorExtensionUtils.readObject(in,vendorDataDeserializationEnabled);

        if (in.readBoolean()) {
            // attempt to deserialize the cause
            try {
                cause = (Throwable)((MarshalledObject)in.readObject()).get();
            }
            catch (ClassNotFoundException cnfe) {
                // must have been a class not in standard classloaders and not remotely loadable
                // do nothing now, we'll replace it with the string version included next in the stream
            }
            String causeString = in.readUTF();
            if (cause == null) {
                // replace the cause with a generic exception
                // that includes the original stack trace in its message
                cause = new Exception("Undeserializable cause, original cause stack trace follows: " + causeString);
            }
        }
    }

    private final String alarmID;
    private final NotificationSource notificationSource;
    private final String alarmType;
    private final String instanceID;
    private final Object alarmSource;
    private final Level level_10;
    private final AlarmLevel level_11;
    private transient Throwable cause;

    private static volatile boolean vendorDataSerializationEnabled = false;
    private static volatile boolean vendorDataDeserializationEnabled = false;
    private transient Object vendorData;
}


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

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

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

import java.util.Collection;

import javax.slee.TransactionRolledbackLocalException;
import javax.slee.facilities.FacilityException;
import javax.slee.profile.AttributeNotIndexedException;
import javax.slee.profile.AttributeTypeMismatchException;
import javax.slee.profile.ProfileFacility;
import javax.slee.profile.ProfileID;
import javax.slee.profile.ProfileTable;
import javax.slee.profile.ProfileTableActivity;
import javax.slee.profile.UnrecognizedAttributeException;
import javax.slee.profile.UnrecognizedProfileTableNameException;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.management.ProfileManagementImpl;
import org.mobicents.slee.container.profile.ProfileTableImpl;
import org.mobicents.slee.container.transaction.SleeTransactionManager;

/**
 * JNDI Location java:comp/env/slee/facilities/profile
 *
 * @author baranowb - Bartosz Baranowski
 *
 *
 * @author  Alexandre Mendonca
 *
 */
public class ProfileFacilityImpl implements ProfileFacility {

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

	public static final String JNDI_NAME = "profile";

	private final ProfileManagementImpl profileManagement;

	/**
     *
     */
	public ProfileFacilityImpl(ProfileManagementImpl profileManagement) {
		this.profileManagement = profileManagement;
	}

	/**
	 * Get a ProfileTable object for a profile table. The object returned by
	 * this method may be safely typecast to the Profile Table Interface defined
	 * by the profile specification of the profile table if the SBB has the
	 * appropriate classes in its classloader to do so, for example by declaring
	 * a profile-spec-ref in its deployment descriptor for the profile
	 * specification of the Profile Table.
	 *
	 * This method is a non-transactional method.
	 *
	 * @param profileTableName
	 *            - the name of the profile table.
	 * @return a ProfileTable object for the profile table.
	 * @throws java.lang.NullPointerException
	 *             - if profileTableName is null.
	 * @throws UnrecognizedProfileTableNameException
	 *             - if a profile table with the specified name does not exist.
	 * @throws FacilityException
	 *             - if the ProfileTable object could not be obtained due to a
	 *             system-level-failure.
	 */
	public ProfileTable getProfileTable(String profileTableName)
			throws NullPointerException, UnrecognizedProfileTableNameException,
			FacilityException {

		if (logger.isTraceEnabled()) {
			logger.trace("getProfileTable( profileTableName = "
					+ profileTableName + " )");
		}

		final SleeTransactionManager sleeTransactionManager = profileManagement.getSleeContainer()
				.getTransactionManager();
		boolean terminateTx = sleeTransactionManager.requireTransaction();
		try {
			return profileManagement.getProfileTable(profileTableName);
		} catch (NullPointerException e) {
			throw e;
		} catch (UnrecognizedProfileTableNameException e) {
			throw e;
		} catch (Throwable e) {
			throw new FacilityException("Failed to obtain profile table.", e);
		} finally {
			// never rollback
			try {
				sleeTransactionManager.requireTransactionEnd(terminateTx,false);
			} catch (Throwable e) {
				throw new FacilityException(e.getMessage(),e);
			}
		}

	}

	/**
	 * Get a collection of ProfileID objects that identify all the profiles
	 * contained in the specified profile table. The collection returned is
	 * immutable. Any attempt to modify it, either directly or indirectly, will
	 * result in a java.lang.UnsupportedOperationException being thrown.
	 *
	 * Note: A profile identifier for the profile table's default profile will
	 * not be included in the collection returned by this method as the default
	 * profile has no such identifier.
	 *
	 * This method is a required transactional method.
	 *
	 * @deprecated
	 * @param profileTableName
	 *            - the name of the profile table.
	 * @return a read-only collection of ProfileID objects identifying the
	 *         profiles contained in the specified profile table.
	 * @throws java.lang.NullPointerException
	 *             - if profileTableName is null.
	 * @throws UnrecognizedProfileTableNameException
	 *             - if a profile table with the specified name does not exist.
	 * @throws TransactionRolledbackLocalException
	 *             - if this method was invoked without a valid transaction
	 *             context and the transaction started by this method failed to
	 *             commit.
	 * @throws FacilityException
	 *             - if the profile identifies could not be obtained due to a
	 *             system-level failure.
	 */
	public Collection<ProfileID> getProfiles(String profileTableName)
			throws NullPointerException, UnrecognizedProfileTableNameException,
			TransactionRolledbackLocalException, FacilityException {

		if (logger.isTraceEnabled()) {
			logger.trace("getProfiles( profileTableName = "
					+ profileTableName + " )");
		}

		profileManagement.getSleeContainer().getTransactionManager().mandateTransaction();

		try {
			return profileManagement.getProfileTable(
							profileTableName).getProfiles();
		} catch (NullPointerException e) {
			throw e;
		} catch (UnrecognizedProfileTableNameException e) {
			throw e;
		} catch (Throwable e) {
			throw new FacilityException(e.getMessage(), e);
		}
	}

	/**
	 * Get a ProfileTableActivity object for a profile table.
	 *
	 * This method is a required transactional method.
	 *
	 * @param profileTableName
	 *            - the name of the profile table.
	 * @return a ProfileTableActivity object for the profile table.
	 * @throws java.lang.NullPointerException
	 *             - if profileTableName is null.
	 * @throws UnrecognizedProfileTableNameException
	 *             - if a profile table with the specified name does not exist.
	 * @throws TransactionRolledbackLocalException
	 *             - if this method was invoked without a valid transaction
	 *             context and the transaction started by this method failed to
	 *             commit.
	 * @throws FacilityException
	 *             - if the activity could not be obtained due to a system-level
	 *             failure. This exception is also thrown if the method is
	 *             invoked on a ProfileFacility object provided to a resource
	 *             adaptor via its ResourceAdaptorContext.
	 */
	public ProfileTableActivity getProfileTableActivity(String profileTableName)
			throws NullPointerException, UnrecognizedProfileTableNameException,
			TransactionRolledbackLocalException, FacilityException {

		if (logger.isTraceEnabled()) {
			logger.trace("getProfileTableActivity( profileTableName = "
					+ profileTableName + " )");
		}

		final SleeTransactionManager sleeTransactionManager = profileManagement.getSleeContainer()
				.getTransactionManager();
		boolean terminateTx = sleeTransactionManager.requireTransaction();
		try {
			return profileManagement.getProfileTable(profileTableName).getActivity();
		} catch (NullPointerException e) {
			throw e;
		} catch (UnrecognizedProfileTableNameException e) {
			throw e;
		} catch (Throwable e) {
			throw new FacilityException("Failed to obtain profile table.", e);
		} finally {
			// never rollback
			try {
				sleeTransactionManager.requireTransactionEnd(terminateTx,false);
			} catch (Throwable e) {
				throw new FacilityException(e.getMessage(),e);
			}
		}
	}

	/**
	 * Get a ProfileID object that identifies the profile contained in the
	 * specified profile table, where the specified profile attribute is set to
	 * the specified value. In the case of a profile attribute of an array type,
	 * the type of the specified value must be the base component type of the
	 * array, not the array type itself, and the SLEE will return the profile
	 * identifier of any profile that contains the value within the array.
	 *
	 * Note: The profile table's default profile is not considered when
	 * determining matching profiles as it has no profile identifier that can be
	 * returned by this method.
	 *
	 * This method is a required transactional method.
	 *
	 * This method can only be invoked against profile tables created from SLEE
	 * 1.0 profile specifications. Attempting to invoke it on a profile table
	 * created from a SLEE 1.1 profile specification causes a FacilityException
	 * to be thrown.
	 *
	 * @deprecated
	 * @param profileTableName
	 *            - the name of the profile table.
	 * @param attributeName
	 *            - the name of the profile's attribute to check.
	 * @param attributeValue
	 *            - the value to compare the attribute with. Returns: the
	 *            profile identifier for the first matching profile, or null if
	 *            no matching profile was found.
	 * @throws java.lang.NullPointerException
	 *             - if any attribute is null.
	 * @throws UnrecognizedProfileTableNameException
	 *             - if a profile table with the specified name does not exist.
	 * @throws UnrecognizedAttributeException
	 *             - if an attribute with the specified name is not defined in
	 *             the profile specification for the specified profile table.
	 * @throws AttributeNotIndexedException
	 *             - if the specified attribute is not indexed in the profile
	 *             specification for the specified profile table.
	 * @throws AttributeTypeMismatchException
	 *             - if the type of the supplied attribute value does not match
	 *             the type of the specified indexed attribute.
	 * @throws TransactionRolledbackLocalException
	 *             - if this method was invoked without a valid transaction
	 *             context and the transaction started by this method failed to
	 *             commit.
	 * @throws FacilityException
	 *             - if the profile identifier could not be obtained due to a
	 *             system-level failure.
	 */
	public ProfileID getProfileByIndexedAttribute(
			java.lang.String profileTableName, java.lang.String attributeName,
			java.lang.Object attributeValue) throws NullPointerException,
			UnrecognizedProfileTableNameException,
			UnrecognizedAttributeException, AttributeNotIndexedException,
			AttributeTypeMismatchException,
			TransactionRolledbackLocalException, FacilityException {

		if (logger.isTraceEnabled()) {
			logger.trace("getProfileByIndexedAttribute( profileTableName = "
					+ profileTableName + " , attributeName = " + attributeName
					+ " , attributeValue = " + attributeValue + " )");
		}

		profileManagement.getSleeContainer().getTransactionManager().mandateTransaction();

		try {
			ProfileTableImpl profileTable = profileManagement.getProfileTable(
							profileTableName);
			if (profileTable.getProfileSpecificationComponent().isSlee11()) {
				throw new FacilityException(
						"JAIN SLEE 1.1 Specs forbidden the usage of this method on SLEE 1.1 Profile Tables");
			}
			Collection<ProfileID> profileIDs = profileTable.getProfilesByAttribute(attributeName,attributeValue,false);
			if (profileIDs.isEmpty()) {
				return null;
			}
			else {
				return profileIDs.iterator().next();
			}
		} catch (NullPointerException e) {
			throw e;
		} catch (UnrecognizedProfileTableNameException e) {
			throw e;
		} catch (UnrecognizedAttributeException e) {
			throw e;
		} catch (AttributeNotIndexedException e) {
			throw e;
		} catch (AttributeTypeMismatchException e) {
			throw e;
		} catch (Throwable e) {
			throw new FacilityException(e.getMessage(), e);
		}
	}

	/**
	 * Get a collection of ProfileID objects that identify the profiles
	 * contained in the specified profile table where the specified profile
	 * attribute is set to the specified value. In the case of a profile
	 * attribute of an array type, the type of the specified value must be the
	 * base component type of the array, not the array type itself, and the SLEE
	 * will return the profile identifier of any profile that contains the value
	 * within the array.
	 *
	 * The collection returned is immutable. Any attempt to modify it, either
	 * directly or indirectly, will result in a
	 * java.lang.UnsupportedOperationException being thrown.
	 *
	 * Note: The profile table's default profile is not considered when
	 * determining matching profiles as it has no profile identifier that can be
	 * included in the collection returned by this method.
	 *
	 * This method is a required transactional method.
	 *
	 * This method can only be invoked against profile tables created from SLEE
	 * 1.0 profile specifications. Attempting to invoke it on a profile table
	 * created from a SLEE 1.1 profile specification causes a FacilityException
	 * to be thrown.
	 *
	 * @deprecated
	 * @param profileTableName
	 *            - the name of the profile table.
	 * @param attributeName
	 *            - the name of the profile's attribute to check.
	 * @param attributeValue
	 *            - the value to compare the attribute with.
	 * @return a read-only collection of ProfileID objects identifying the
	 *         profiles contained in the specified profile table, where the
	 *         specified attribute of each profile equals the specified value.
	 * @throw java.lang.NullPointerException - if any argument is null.
	 * @throw UnrecognizedProfileTableNameException - if a profile table with
	 *        the specified name does not exist.
	 * @throw UnrecognizedAttributeException - if an attribute with the
	 *        specified name is not defined in the profile specification for the
	 *        specified profile table.
	 * @throw AttributeNotIndexedException - if the specified attribute is not
	 *        indexed in the profile specification for the specified profile
	 *        table.
	 * @throw AttributeTypeMismatchException - if the type of the supplied
	 *        attribute value does not match the type of the specified indexed
	 *        attribute.
	 * @throw TransactionRolledbackLocalException - if this method was invoked
	 *        without a valid transaction context and the transaction started by
	 *        this method failed to commit.
	 * @throw FacilityException - if the profile identifiers could not be
	 *        obtained due to a system-level failure.
	 */
	public Collection<ProfileID> getProfilesByIndexedAttribute(
			java.lang.String profileTableName, java.lang.String attributeName,
			java.lang.Object attributeValue)
			throws java.lang.NullPointerException,
			UnrecognizedProfileTableNameException,
			UnrecognizedAttributeException, AttributeNotIndexedException,
			AttributeTypeMismatchException,
			TransactionRolledbackLocalException, FacilityException {

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

		profileManagement.getSleeContainer().getTransactionManager().mandateTransaction();

		try {
			ProfileTableImpl profileTable = profileManagement.getProfileTable(
							profileTableName);
			if (profileTable.getProfileSpecificationComponent().isSlee11()) {
				throw new FacilityException(
						"JAIN SLEE 1.1 Specs forbidden the usage of this method on SLEE 1.1 Profile Tables");
			}
			return profileTable.getProfilesByAttribute(attributeName,attributeValue,false);
		} catch (NullPointerException e) {
			throw e;
		} catch (UnrecognizedProfileTableNameException e) {
			throw e;
		} catch (UnrecognizedAttributeException e) {
			throw e;
		} catch (AttributeNotIndexedException e) {
			throw e;
		} catch (AttributeTypeMismatchException e) {
			throw e;
		} catch (Throwable e) {
			throw new FacilityException(e.getMessage(), e);
		}
	}

}


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

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

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

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

import org.mobicents.slee.container.component.deployment.jaxb.descriptors.common.MSecurityPermissions;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.profile.MProfileSpec;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.profile.MProfileSpecJar;
import org.mobicents.slee.container.component.profile.ProfileSpecificationDescriptorFactory;

/**
 * Factory to build {@link ProfileSpecificationDescriptorImpl} objects.
 *
 * @author  Alexandre Mendonca
 * @author  Bartosz Baranowski
 */
public class ProfileSpecificationDescriptorFactoryImpl extends AbstractDescriptorFactory implements ProfileSpecificationDescriptorFactory {

  /*
   * (non-Javadoc)
   * @see org.mobicents.slee.core.component.profile.ProfileSpecificationDescriptorFactory#parse(java.io.InputStream)
   */
  public List<ProfileSpecificationDescriptorImpl> parse(InputStream inputStream) throws DeploymentException
  {
    Object jaxbPojo = buildJAXBPojo(inputStream);

    List<ProfileSpecificationDescriptorImpl> result = new ArrayList<ProfileSpecificationDescriptorImpl>();

    boolean isSlee11 = false;
    MProfileSpecJar mProfileSpecJar = null;
    if (jaxbPojo instanceof org.mobicents.slee.container.component.deployment.jaxb.slee.profile.ProfileSpecJar)
    {
      mProfileSpecJar = new MProfileSpecJar((org.mobicents.slee.container.component.deployment.jaxb.slee.profile.ProfileSpecJar)jaxbPojo);
    }
    else if (jaxbPojo instanceof org.mobicents.slee.container.component.deployment.jaxb.slee11.profile.ProfileSpecJar)
    {
      mProfileSpecJar = new MProfileSpecJar((org.mobicents.slee.container.component.deployment.jaxb.slee11.profile.ProfileSpecJar)jaxbPojo);
      isSlee11 = true;
    }
    else {
      throw new SLEEException("unexpected class of jaxb pojo built: "+(jaxbPojo != null ? jaxbPojo.getClass() : null));
    }

    MSecurityPermissions securityPermissions = mProfileSpecJar.getSecurityPermissions();
    for (MProfileSpec mProfileSpec : mProfileSpecJar.getProfileSpec())
    {
      result.add(new ProfileSpecificationDescriptorImpl(mProfileSpec, securityPermissions, isSlee11));
    }

    return result;
  }
}


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

import java.beans.PropertyEditor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.Attribute;

import org.jboss.console.twiddle.command.CommandContext;
import org.jboss.console.twiddle.command.CommandException;
import org.jboss.logging.Logger;
import org.jboss.util.propertyeditor.PropertyEditors;
import org.mobicents.tools.twiddle.AbstractSleeCommand;

import gnu.getopt.Getopt;

/**
 * Class which handles different aspects of building jmx call.
 * @author baranowb
 *
 */
public abstract class AbstractOperation {
	//editors
	public static final String CID_SEPARATOR = ";";

	protected Object operationResult;
	protected AbstractSleeCommand sleeCommand;
	protected String operationName;
	// string rep of parameter and prop editors for those.
	protected ArrayList<Object> opArguments = new ArrayList<Object>();
	protected ArrayList<String> opSignature = new ArrayList<String>();

	// context and logger from Command, its not a good way, but....
	protected CommandContext context;
	protected Logger log;

	protected AbstractOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
		super();
		this.context = context;
		this.log = log;
		this.sleeCommand = sleeCommand;
	}

	/**
	 * @return the operationName
	 */
	public String getOperationName() {
		return operationName;
	}

	/**
	 * @return the opArguments
	 */
	public ArrayList<Object> getOpArguments() {
		return opArguments;
	}

	/**
	 * @return the opSignature
	 */
	public ArrayList<String> getOpSignature() {
		return opSignature;
	}

	/**
	 * Each operation should create this method. Its specific to command.
	 * Ususally it will just to opts.getOptarg(); but in case of more
	 * complicated ops, it will do more.
	 *
	 * @param opts
	 * @param args
	 */
	public abstract void buildOperation(Getopt opts,String[] args) throws CommandException;

	/**
	 * Method to display result of operation.
	 */
	public void displayResult() {
		//default impl of display;
		if (!context.isQuiet()) {
			// Translate the result to text
			String resultText = prepareResultText();

			// render results to out
			PrintWriter out = context.getWriter();
			out.println(resultText);
			out.flush();
		}
	}

	protected String prepareResultText() {
		String resultText = null;

		if (operationResult != null) {
            try {
                if (operationResult instanceof Collection) {
                    //convert to array?
                    Collection c = (Collection) operationResult;
                    Object[] arrayO = c.toArray();
                    operationResult = arrayO;
                }

                //here we may have array as result, dont want that, we will handle how its displayed.
                if (operationResult.getClass().isArray()) {
                    if (!operationResult.getClass().getComponentType().isPrimitive()) {
                        Object[] resultArray = (Object[]) operationResult;
                        Class memberClass = resultArray.getClass().getComponentType(); // get type of array stored classes.
                        PropertyEditor editor = PropertyEditors.getEditor(memberClass);
                        resultText = unfoldArray("", resultArray, editor);
                    } else {
                        // array of primitives
                        switch (operationResult.getClass().getComponentType().getCanonicalName()) {
                            case "byte": {
                                resultText = Arrays.toString((byte[])operationResult);
                                break; }
                            case "short": {
                                resultText = Arrays.toString((short[])operationResult);
                                break; }
                            case "int": {
                                resultText = Arrays.toString((int[])operationResult);
                                break; }
                            case "long": {
                                resultText = Arrays.toString((long[])operationResult);
                                break; }
                            case "float": {
                                resultText = Arrays.toString((float[])operationResult);
                                break; }
                            case "double": {
                                resultText = Arrays.toString((double[])operationResult);
                                break; }
                            case "boolean": {
                                resultText = Arrays.toString((boolean[])operationResult);
                                break; }
                            case "char": {
                                resultText = Arrays.toString((char[])operationResult);
                                break; }
                            default: {
                                resultText = "'failed'";
                                break; }
                        }

                    }
                } else {
                    PropertyEditor editor = PropertyEditors.getEditor(operationResult.getClass());
                    editor.setValue(operationResult);
                    resultText = editor.getAsText();
                }
            } catch (RuntimeException e) {
                // No property editor found or some conversion problem
                //TODO: add something more sophisticated here
                log.debug("No editor found: ", e);
                //fallback op
                if (operationResult.getClass().isArray()) {
                    //TODO: this is not readable, but result can be passed into another invocation
                    Object[] arrayResult = (Object[]) operationResult;
                    resultText = unfoldArray("", arrayResult, null);
                } else {
                    resultText = operationResult.toString();
                }
            }

            log.debug("Converted result: " + resultText);

		} else {
			resultText = "'success'";
		}
		return resultText;
	}

	/**
	 * Default implementation.
	 * @param prefix
	 * @param array
	 * @return
	 */
	protected String unfoldArray(String prefix, Object[] array, PropertyEditor editor)
	{
		//StringBuffer sb = new StringBuffer("\n");
        StringBuffer sb = new StringBuffer("[");
		for (int index = 0; index<array.length; index++) {
			if (editor != null) {
				editor.setValue(array[index]);
				sb.append(editor.getAsText());
			} else {
				sb.append(array[index].toString());
			}

            if (index < array.length-1) {
                sb.append(CID_SEPARATOR);
                //sb.append("\n");
            }
		}
		sb.append("]");

		return sb.toString();
	}

	protected void addArg(Object arg, Class<? extends Object> argClass, boolean usPE) throws CommandException {
		if (usPE) {
			PropertyEditor pe = PropertyEditors.getEditor(argClass);
			if (pe == null) {
				throw new CommandException("There is no property editor for: " + argClass);
			}

			pe.setAsText((String) arg);
			opArguments.add(pe.getValue());
		} else {
			opArguments.add(arg);
		}
		opSignature.add(argClass.getName());

	}

	protected void addArg(Object arg, String argClass, boolean usPE) throws CommandException {
		if (usPE) {
			try{
				PropertyEditor pe = PropertyEditors.getEditor(argClass);
				if (pe == null) {
					throw new CommandException("There is no property editor for: " + argClass);
				}
				if(arg!=null)
				{
					pe.setAsText((String) arg);
					opArguments.add(pe.getValue());
				}else
				{
					opArguments.add(null);
				}
			}catch(ClassNotFoundException cnfe)
			{
				throw new CommandException("Failed to locate class.",cnfe);
			}
		} else {
			opArguments.add(arg);
		}

		opSignature.add(argClass);
	}

	public void invoke() throws CommandException {
		try {
			ObjectName on = sleeCommand.getBeanOName();

			MBeanServerConnection conn = context.getServer();
			Object[] parms = getOpArguments().toArray();
			String[] sig = new String[getOpSignature().size()];
			sig = getOpSignature().toArray(sig);

			MBeanInfo mbeanInfo = conn.getMBeanInfo(on);
			if (isOperation(mbeanInfo, this.operationName)) {
				// we have operation
				operationResult = conn.invoke(on, this.operationName, parms, sig);
			} else {
				// check if we have attribute setter/getter
				String attributeName;
				if (this.operationName.substring(0, 3).equals("set")) {
					attributeName = this.operationName.substring(3);
					if (isAttribute(mbeanInfo, attributeName)) {
						// we have attribute setter
						Attribute attr = new Attribute(attributeName, opArguments.get(0));
						conn.setAttribute(on, attr);
                        operationResult = null; // success
					} else {
						throw new CommandException("Failed to invoke \"" + this.operationName + "\"." +
								" Attribute \"" + attributeName + "\" is not existing.");
					}
				} else if (this.operationName.substring(0, 3).equals("get")) {
					attributeName = this.operationName.substring(3);
					if (isAttribute(mbeanInfo, attributeName)) {
						// we have attribute getter
						operationResult = conn.getAttribute(on, this.operationName.substring(3));
					} else {
						throw new CommandException("Failed to invoke \"" + this.operationName + "\"." +
								" Attribute \"" + attributeName + "\" is not existing.");
					}
				} else {
                    throw new CommandException("Failed to invoke \"" + this.operationName + "\"." +
                            " It is not MBean operation or attribute.");
                }
			}

			displayResult();

		} catch (Exception e) {
			//add handle error here?
			throw new CommandException("Failed to invoke \"" + this.operationName + "\" due to: ", e);
		}
	}

	private boolean isAttribute(MBeanInfo mbeanInfo, String attrName) {
		for (MBeanAttributeInfo attrInfo : mbeanInfo.getAttributes()) {
			if (attrInfo.getName().equals(attrName)) {
				return true;
			}
		}
		return false;
	}

	private boolean isOperation(MBeanInfo mbeanInfo, String operName) {
		for (MBeanOperationInfo operInfo : mbeanInfo.getOperations()) {
			if (operInfo.getName().equals(operName)) {
				return true;
			}
		}
		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.
 */

package org.mobicents.slee.container.congestion;

import org.infinispan.remoting.transport.Address;

import javax.slee.management.NotificationSource;

public class CongestionControlNotification implements NotificationSource {

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

	public static final String ALARM_NOTIFICATION_TYPE = "org.mobicents.slee.management.alarm.congestion";

    public static final String TRACE_NOTIFICATION_TYPE = "org.mobicents.slee.management.trace.congestion";

    public static final String USAGE_NOTIFICATION_TYPE = "org.mobicents.slee.management.usage.congestion";

    private final String localAddress;

    public CongestionControlNotification(Address localAddress) {
		this.localAddress = localAddress == null ? "localhost" : localAddress.toString();
	}

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

        	return ((CongestionControlNotification)obj).localAddress.equals(localAddress);
        }
        else {
        	return false;
        }
    }

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

    /*
     * (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    public String toString() {
        return new StringBuilder("CongestionControlNotification[localAddress=").append(localAddress).append(']').toString();
    }

    /*
     * (non-Javadoc)
     * @see javax.slee.management.NotificationSource#compareTo(java.lang.Object)
     */
	public int compareTo(Object obj) {
    	if (obj == this) return 0;
        if (obj == null) throw new NullPointerException();
        if (obj.getClass() == this.getClass()) {
            return ((CongestionControlNotification) obj).localAddress.compareTo(this.localAddress);
        }
        else {
            return -1;
        }
    }

    /*
     * (non-Javadoc)
     * @see javax.slee.management.NotificationSource#getAlarmNotificationType()
     */
	public String getAlarmNotificationType() {
		return ALARM_NOTIFICATION_TYPE;
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.NotificationSource#getTraceNotificationType()
	 */
	public String getTraceNotificationType() {
		return TRACE_NOTIFICATION_TYPE;
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.NotificationSource#getUsageNotificationType()
	 */
	public String getUsageNotificationType() {
		return USAGE_NOTIFICATION_TYPE;
	}

	/**
	 *
	 * @return
	 */
	public String getLocalAddress() {
		return localAddress;
	}
}


package javax.slee.management;

import java.util.HashMap;
import java.util.Iterator;
import javax.management.Notification;
import javax.management.NotificationFilter;

/**
 * A notification filter that suppresses equivalent {@link AlarmNotification}s
 * that occur during a specified period of time.  Only the first of a series of
 * equivalent alarm notifications is allowed through this filter.  When the
 * specified period of time elapses after the first notification, the cycle restarts
 * and a subsequent equivalent alarm notification is allowed through.
 *

 * Alarm notification equivalence is tested using the {@link AlarmNotification#equals}
 * method.
 *

 * Notifications that are not instances of {@link AlarmNotification} are suppressed
 * by this filter.
 *

 * Note: This filter implementation does not use threads to clear stale timeouts.
 * Instead, stale timeouts are cleared on each invocation of {@link #isNotificationEnabled
 * isNotificationEnabled}.  Methods in this class are also thread-safe.
 */
public class AlarmDuplicateFilter implements NotificationFilter {
    /**
     * Create an AlarmDuplicateFilter.
     * @param period the period (measured in ms) during which duplicate alarm
     *        notifications will be discarded.
     */
    public AlarmDuplicateFilter(long period) {
        this.period = period;
    }

    /**
     * Determine whether the specified notification should be delivered to notification
     * listeners using this notification filter.
     * @param notification the notification to be sent.
     * @return true if the notification should be delivered to notification
     *        listeners, false otherwise.  This method always returns
     *        false if notification is not an instance of
     *        {@link AlarmNotification}.
     */
    public boolean isNotificationEnabled(Notification notification) {
        if (!(notification instanceof AlarmNotification)) return false;

        synchronized (knownAlarms) {
            clearStaleTimeouts();

            if (knownAlarms.containsKey(notification)) return false;

            // we've not seen this alarm before, or the period has expired since
            // the first notification
            knownAlarms.put(notification, new Long(System.currentTimeMillis()));
            return true;
        }
    }

    // private

    private void clearStaleTimeouts() {
        Iterator iterator = knownAlarms.values().iterator();
        long currentTime = System.currentTimeMillis();
        while (iterator.hasNext()) {
            Long firstSeenTime = (Long)iterator.next();
            // if period has expired remove reference to the notification
            if ((firstSeenTime.longValue() + period) < currentTime) {
                iterator.remove();
            }
        }
    }

    private final long period;
    private final HashMap knownAlarms = new HashMap();
}


package javax.slee.usage;

import javax.management.Notification;
import javax.management.NotificationFilter;
import javax.slee.SbbID;
import javax.slee.ServiceID;
import javax.slee.management.NotificationSource;

/**
 * A notification filter that only allows through {@link UsageNotification}s where the
 * notification source usage parameter name match specified values, and the value of the
 * usage parameter has crossed a specified threshold (in either the positive or negative
 * direction).
 *

 * Each time a usage notification is seen for the specified usage parameter, the current
 * value of the usage parameter is stored.  If the previous value and the current value
 * lie on opposite sides of the threshold, the notification is passed to notification
 * listeners.  If the previous value was equal to the threshold value, the notification
 * is only passed to notification listeners if the direction on the real axis from the
 * previous value to the current value is the same as the approach made to the threshold
 * value.
 *

 * For example, if the threshold value is set to 10, and three usage notifications with
 * the values 9, 10, and 9 respectively are generated by the SLEE, this notification
 * filter would not pass any of the usage notifications to notification listeners as the
 * threshold has not been crossed.  However if three usage notifications with the values
 * 9, 10, and 11 respectively are generated by the SLEE, this notification filter would
 * pass only the last usage notification to notification listeners, as this represents
 * the point when the threshold has been crossed.
 *

 * In any other situation where the threshold value is not crossed, the notification is
 * suppressed.
 *

 * If the notification contains usage information for some other notification source or
 * usage parameter, it is also suppressed.
 *

 * Notifications that are not instances of {@link UsageNotification} are also suppressed
 * by this filter.
 */
public class UsageThresholdFilter implements NotificationFilter {
    /**
     * Create a UsageThresholdFilter.  A filter created using this constructor will
     * only allow SLEE 1.0-compliant usage notifications to pass through where they otherwise
     * satisfy the filtering criteria.
     * @param service the component identifier of the Service whose usage parameter
     *        should be monitored.
     * @param sbb the component identifier of the SBB whose usage parameter should be
     *        monitored.
     * @param paramName the name of a usage parameter defined by the SBB.
     * @param threshold the threshold value.
     * @throws NullPointerException if service, sbb, or
     *        paramName is null.
     * @deprecated Replaced with {@link #UsageThresholdFilter(NotificationSource, String, long)}
     *        as usage collecting has been expanded to include SLEE components other than SBBs.
     */
    public UsageThresholdFilter(ServiceID service, SbbID sbb, String paramName, long threshold) throws NullPointerException {
        if (service == null) throw new NullPointerException("service is null");
        if (sbb == null) throw new NullPointerException("sbb is null");
        if (paramName == null) throw new NullPointerException("paramName is null");

        this.service = service;
        this.sbb = sbb;
        this.paramName = paramName;
        this.threshold = threshold;

        // forward compatibiltiy
        this.notificationSource = null;
    }

    /**
     * Create a UsageThresholdFilter.  A filter created using this constructor will
     * only allow SLEE 1.1-compliant usage notifications to pass through where they otherwise
     * satisfy the filtering criteria.
     * @param notificationSource the notification source whose usage parameter should be
     *        monitored.
     * @param paramName the name of a usage parameter defined by the SBB.
     * @param threshold the threshold value.
     * @throws NullPointerException if notificationSource or paramName
     *        is null.
     */
    public UsageThresholdFilter(NotificationSource notificationSource, String paramName, long threshold) throws NullPointerException {
        if (notificationSource == null) throw new NullPointerException("notificationSource is null");
        if (paramName == null) throw new NullPointerException("paramName is null");

        this.notificationSource = notificationSource;
        this.paramName = paramName;
        this.threshold = threshold;

        // backward compatibiltiy
        this.service = null;
        this.sbb = null;
    }

    /**
     * Determine whether the specified notification should be delivered to notification
     * listeners using this notification filter.
     * @param notification the notification to be sent.
     * @return true if the notification should be delivered to notification
     *        listeners, false otherwise.  This method always returns
     *        false if notification is not an instance of
     *        {@link UsageNotification}.
     */
    public boolean isNotificationEnabled(Notification notification) {
        if (!(notification instanceof UsageNotification)) return false;

        UsageNotification usageNotification = (UsageNotification)notification;
        if (service != null) {
            // SLEE 1.0 comparison
            if (!service.equals(usageNotification.getService())) return false;
            if (!sbb.equals(usageNotification.getSbb())) return false;
        }
        else {
            // SLEE 1.1 comparison
            if (!notificationSource.equals(usageNotification.getNotificationSource())) return false;
        }
        if (!usageNotification.getUsageParameterName().equals(paramName)) return false;

        long current = usageNotification.getValue();
        try {
            return (previous != threshold)
                ? ((previous < threshold && current > threshold) ||  // crossed +ve dir
                   (previous > threshold && current < threshold))    // crossed -ve dir
                : (getDirection(previous, current) == lastDir);      // crossed in last dir
        }
        finally {
            if (previous != current) {
                lastDir = getDirection(previous, current);
                previous = current;
            }
        }
    }

    /**
     * Get the axial direction of movement from x to y.
     * @return 1 if x<y, -1 if x>y, or 0 if x==y.
     */
    private int getDirection(long x, long y) {
        return x == y ? 0 : (x < y ? 1 : -1);
    }

    private final ServiceID service;
    private final SbbID sbb;
    private final NotificationSource notificationSource;
    private final String paramName;
    private final long threshold;
    private long previous = 0;
    private long lastDir = 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.resource;

import javax.slee.Address;
import javax.slee.SLEEException;
import javax.slee.resource.ActivityHandle;
import javax.slee.resource.ActivityIsEndingException;
import javax.slee.resource.FireEventException;
import javax.slee.resource.FireableEventType;
import javax.slee.resource.ReceivableService;
import javax.slee.resource.UnrecognizedActivityHandleException;

import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.transaction.SleeTransaction;

/**
 *
 * @author martins
 *
 */
public class SleeEndpointFireEventNotTransactedExecutor extends
		SleeEndpointOperationNotTransactedExecutor {

	/**
	 *
	 * @param sleeContainer
	 * @param sleeEndpoint
	 */
	public SleeEndpointFireEventNotTransactedExecutor(
			SleeContainer sleeContainer, SleeEndpointImpl sleeEndpoint) {
		super(sleeContainer, sleeEndpoint);
	}

	/**
	 * Executes a non transacted fire event operation.
	 *
	 * @param realHandle
	 * @param refHandle
	 * @param eventType
	 * @param event
	 * @param address
	 * @param receivableService
	 * @param eventFlags
	 * @throws ActivityIsEndingException
	 * @throws FireEventException
	 * @throws SLEEException
	 * @throws UnrecognizedActivityHandleException
	 */
	void execute(final ActivityHandle realHandle, final ActivityHandle refHandle,
			final FireableEventType eventType, final Object event,
			final Address address, final ReceivableService receivableService,
			final int eventFlags) throws ActivityIsEndingException,
			FireEventException, SLEEException,
			UnrecognizedActivityHandleException {

		final SleeTransaction tx = super.suspendTransaction();
		try {
			sleeEndpoint._fireEvent(realHandle, refHandle, eventType, event, address,
					receivableService, eventFlags,tx);
		} finally {
			if (tx != null) {
				super.resumeTransaction(tx);
			}
		}
	}
}


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

import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

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

import javax.slee.SLEEException;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.component.ClassPool;
import org.mobicents.slee.container.component.profile.ProfileAttribute;
import org.mobicents.slee.container.component.profile.ProfileSpecificationComponent;
import org.mobicents.slee.container.deployment.profile.ClassGeneratorUtils;
import org.mobicents.slee.container.profile.entity.ProfileEntityFactory;
import org.mobicents.slee.container.security.Utility;
import org.mobicents.slee.container.util.ObjectCloner;

/**
 *
 * Generates the concrete profile entity factory class for a profile spec
 * @author martins
 */
public class ConcreteProfileEntityFactoryGenerator {

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

  private final ProfileSpecificationComponent profileComponent;
  private final Class<?> profileEntityClass;
  private final Map<String, Class<?>> profileEntityAttributeArrayValueClasses;

  public ConcreteProfileEntityFactoryGenerator(ProfileSpecificationComponent profileComponent, Class<?> profileEntityClass, Map<String, Class<?>> profileEntityAttributeArrayValueClasses) {
	  this.profileComponent = profileComponent;
	  this.profileEntityClass = profileEntityClass;
	  this.profileEntityAttributeArrayValueClasses = profileEntityAttributeArrayValueClasses;
  }

  /*
   * Generates the profile entity factory class
   */
  public Class<?> generateClass() {

	  CtClass ctClass = null;

	  try {

		  ClassPool classPool = profileComponent.getClassPool();
		  Collection<ProfileAttribute> profileAttributes = profileComponent.getProfileAttributes().values();

		  String className = profileEntityClass.getName() + "F";

		  ctClass = classPool.makeClass(className);

		  CtClass profileEntityFactoryClass = classPool.get(ProfileEntityFactory.class.getName());
		  CtClass[] interfaces = new CtClass[] { profileEntityFactoryClass };
		  ctClass.setInterfaces(interfaces);

		  // copy newInstance method from interface and generate body
		  CtMethod newInstanceMethod = profileEntityFactoryClass.getDeclaredMethod("newInstance");
		  CtMethod newInstanceMethodCopy = CtNewMethod.copy(newInstanceMethod, ctClass, null);
		  String newInstanceMethodCopyBody =
			  "{ "+
			  	profileEntityClass.getName()+" profileEntity = new "+profileEntityClass.getName()+"();" +
			  	" profileEntity.setTableName($1); " +
			  	" profileEntity.setProfileName($2); " +
			  	" return profileEntity; " +
			  "}";
		  if (logger.isTraceEnabled()) {
			  logger.trace( "\nAdding method named "+newInstanceMethodCopy.getName()+" with body "+newInstanceMethodCopy+" , into class " + className );
		  }
		  newInstanceMethodCopy.setBody(newInstanceMethodCopyBody);
		  ctClass.addMethod(newInstanceMethodCopy);

		  // copy copyAttributes method from interface and generate body
		  CtMethod copyAttributesMethod = profileEntityFactoryClass.getDeclaredMethod("copyAttributes");
		  CtMethod copyAttributesMethodCopy = CtNewMethod.copy(copyAttributesMethod, ctClass, null);
		  // body header
		  String copyAttributesMethodCopyBody =
			  "{ "+
			  	profileEntityClass.getName()+" newProfileEntity = ("+profileEntityClass.getName()+") $2; " +
			  	profileEntityClass.getName()+" oldProfileEntity = ("+profileEntityClass.getName()+") $1; ";
		  // process fields copy
		  String profileEntityAttributeArrayValueClassName = null;
		  if(System.getSecurityManager()==null)
		  {

		  for (ProfileAttribute profileAttribute : profileAttributes) {
			  String accessorMethodSufix = ClassGeneratorUtils.getPojoCmpAccessorSufix(profileAttribute.getName());
			  if (profileAttribute.isArray()) {
				  profileEntityAttributeArrayValueClassName = profileEntityAttributeArrayValueClasses.get(profileAttribute.getName()).getName();
				  copyAttributesMethodCopyBody +=
					  "if (oldProfileEntity.get"+accessorMethodSufix+"() != null) { " +
					  // if the target list already exists then empty it so elements get deleted, otherwise create new
					  List.class.getName() + " new"+ profileAttribute.getName() + " = newProfileEntity.get"+accessorMethodSufix+"(); " +
					  "if (new"+profileAttribute.getName()+" == null) { new"+ profileAttribute.getName() + " = new " + LinkedList.class.getName() + "(); } else { new"+profileAttribute.getName()+".clear(); } " +
					  // extract list to copy
					  List.class.getName() + " old"+ profileAttribute.getName() + " = oldProfileEntity.get" + accessorMethodSufix + "(); " +
					  // iterate each list element
					  "for ("+Iterator.class.getName()+" i = old"+profileAttribute.getName()+".iterator(); i.hasNext();) { " +
					  profileEntityAttributeArrayValueClassName+" oldArrayValue = ("+profileEntityAttributeArrayValueClassName+") i.next(); " +
					  profileEntityAttributeArrayValueClassName+" newArrayValue = new "+profileEntityAttributeArrayValueClassName+"(); " +
					  // link to profile entity
					  "newArrayValue.setOwner( newProfileEntity ); " +
					  // copy fields
					  "newArrayValue.setString( oldArrayValue.getString() ); " +
					  "newArrayValue.setSerializable( ("+Serializable.class.getName()+") "+ObjectCloner.class.getName()+".makeDeepCopy(oldArrayValue.getSerializable()) ); " +
					  "new"+profileAttribute.getName()+".add(newArrayValue); " +
					  "} " +
					  "newProfileEntity.set"+accessorMethodSufix+"(new"+profileAttribute.getName()+"); };";
			  }
			  else {
				  if (profileAttribute.isPrimitive()) {
					  // just copy value
					  copyAttributesMethodCopyBody +=
						  " newProfileEntity.set"+accessorMethodSufix+"(oldProfileEntity.get"+accessorMethodSufix+"()); ";
				  }
				  else {
					// just copy value but do a deep copy
					  copyAttributesMethodCopyBody +=
						  " if (oldProfileEntity.get"+accessorMethodSufix+"() != null) { newProfileEntity.set"+accessorMethodSufix+"(("+profileAttribute.getType().getName()+")"+ObjectCloner.class.getName()+".makeDeepCopy(oldProfileEntity.get"+accessorMethodSufix+"())); }; ";
				  }
			  }
		  }
		  }else
		  {
			  for (ProfileAttribute profileAttribute : profileAttributes) {
			  	  String accessorMethodSufix = ClassGeneratorUtils.getPojoCmpAccessorSufix(profileAttribute.getName());
			  		  if (profileAttribute.isArray()) {
			  		  profileEntityAttributeArrayValueClassName = profileEntityAttributeArrayValueClasses.get(profileAttribute.getName()).getName();
			  		  copyAttributesMethodCopyBody +=
			  						  "if ("+Utility.class.getName()+".makeSafeProxyCall(oldProfileEntity,\"get"+accessorMethodSufix+"\",null,null) != null) {" +
			  						  		"" +
			  						  // if the target list already exists then empty it so elements get deleted, otherwise create new
			  						  List.class.getName() + " new"+ profileAttribute.getName() + " = newProfileEntity.get"+accessorMethodSufix+"(); " +
			  						  "if (new"+profileAttribute.getName()+" == null) { new"+ profileAttribute.getName() + " = new " + LinkedList.class.getName() + "(); } else { new"+profileAttribute.getName()+".clear(); } " +
			  						  // extract list to copy
			  						  //List.class.getName() + " old"+ profileAttribute.getName() + " = oldProfileEntity.get" + accessorMethodSufix + "(); " +
			  						  List.class.getName() + " old"+ profileAttribute.getName() + " = ("+List.class.getName()+")"+Utility.class.getName()+".makeSafeProxyCall(oldProfileEntity,\"get"+accessorMethodSufix+"\",null,null);"+
			  						  // iterate each list element
			  						  Iterator.class.getName()+" i = "+Utility.class.getName()+".makeSafeProxyCall(old"+profileAttribute.getName()+",\"iterator\",null,null);"+
			  						  "for (; "+Utility.class.getName()+".evaluateNext(i);) { " +
			  						  profileEntityAttributeArrayValueClassName+" oldArrayValue = ("+profileEntityAttributeArrayValueClassName+") i.next();"+
			  						  profileEntityAttributeArrayValueClassName+" newArrayValue = new "+profileEntityAttributeArrayValueClassName+"(); " +
			  						  // link to profile entity
			  						  "newArrayValue.setOwner( newProfileEntity ); " +
			  						  // copy fields
			  					  "newArrayValue.setString( oldArrayValue.getString() ); " +
			  						  "newArrayValue.setSerializable( ("+Serializable.class.getName()+") "+ObjectCloner.class.getName()+".makeDeepCopy(oldArrayValue.getSerializable()) ); " +
			  						  "new"+profileAttribute.getName()+".add(newArrayValue); " +
			  						  "} " +
			  						  //"newProfileEntity.set"+accessorMethodSufix+"(new"+profileAttribute.getName()+"); };";
			  						  Utility.class.getName()+".makeSafeProxyCall(newProfileEntity,\"set"+accessorMethodSufix+"\",new Class[]{"+Utility.class.getName()+".getReturnType(oldProfileEntity,\"get"+accessorMethodSufix+"\")},new Object[]{new"+profileAttribute.getName()+"});}";
			  				  }
			  				  else {
			  					  if (profileAttribute.isPrimitive()) {
			  						  // just copy value
			  						  //copyAttributesMethodCopyBody +=
			  						  //	  " newProfileEntity.set"+accessorMethodSufix+"(oldProfileEntity.get"+accessorMethodSufix+"()); ";
			  						  copyAttributesMethodCopyBody +="Object value = "+Utility.class.getName()+".makeSafeProxyCall(oldProfileEntity,\"get"+accessorMethodSufix+"\",null,null);";
			  						  copyAttributesMethodCopyBody +=Utility.class.getName()+".makeSafeProxyCall(newProfileEntity,\"set"+accessorMethodSufix+"\",new Class[]{"+Utility.class.getName()+".getReturnType(oldProfileEntity,\"get"+accessorMethodSufix+"\")},new Object[]{value});";
			  					  }
			  					  else {
			  						// just copy value but do a deep copy
			  						  copyAttributesMethodCopyBody +=
			  							  "if ("+Utility.class.getName()+".makeSafeProxyCall(oldProfileEntity,\"get"+accessorMethodSufix+"\",null,null) != null)  "
			  							  		+"{ Object value = "+Utility.class.getName()+".makeSafeProxyCall(oldProfileEntity,\"get"+accessorMethodSufix+"\",null,null);"

			  							  			//+"newProfileEntity.set"+accessorMethodSufix+"(("+profileAttribute.getType().getName()+")"+ObjectCloner.class.getName()+".makeDeepCopy(value)); }; "
			  							  		+Utility.class.getName()+".makeSafeProxyCall(newProfileEntity,\"set"+accessorMethodSufix+"\",new Class[]{"+Utility.class.getName()+".getReturnType(oldProfileEntity,\"get"+accessorMethodSufix+"\")},new Object[]{"+ObjectCloner.class.getName()+".makeDeepCopy(value)});"
			  							  			+"}";
			  					  }
			  				  }
			  			  }
			  		  }
		  // body footer
		  copyAttributesMethodCopyBody += " }";
		  if (logger.isTraceEnabled()) {
			  logger.trace( "\nAdding method named "+copyAttributesMethodCopy.getName()+" with body "+copyAttributesMethodCopyBody+" , into class " + className );
		  }
		  copyAttributesMethodCopy.setBody(copyAttributesMethodCopyBody);
		  ctClass.addMethod(copyAttributesMethodCopy);

      String deployDir = profileComponent.getDeploymentDir().getAbsolutePath();

      // write class
      if (logger.isTraceEnabled()) {
		  logger.trace( "Writing ProfileEntityFactory generated class ( "+ctClass.getName()+" ) to: " + deployDir );
      }
      ctClass.writeFile( deployDir );
      return Thread.currentThread().getContextClassLoader().loadClass(className);

    } catch (Throwable e) {
    	throw new SLEEException(e.getMessage(),e);
    }

    finally {

    	if (ctClass != null) {
    		try {
    			ctClass.defrost();
    		}
    		catch (Throwable e) {
				logger.error(e.getMessage(),e);
			}
    	}

    }

  }

}


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

package org.mobicents.slee.runtime.facilities;

import org.infinispan.tree.Fqn;
import org.infinispan.tree.Node;
import org.restcomm.cache.CacheData;
import org.restcomm.cache.FqnWrapper;
import org.restcomm.cluster.MobicentsCluster;

import javax.slee.facilities.NameAlreadyBoundException;
import javax.slee.facilities.NameNotBoundException;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * Proxy object for ac naming facility data management through JBoss Cache
 *
 * @author martins
 *
 */

public class ActivityContextNamingFacilityCacheData extends CacheData {

	/**
	 * the name of the cache node that holds all data
	 */
	public static final String CACHE_NODE_NAME = "aci-names";

	private static final Boolean CACHE_NODE_MAP_KEY = Boolean.TRUE;

	/**
	 *
	 * @param cluster
	 */
	public ActivityContextNamingFacilityCacheData(MobicentsCluster cluster) {
		super(FqnWrapper.fromElementsWrapper(CACHE_NODE_NAME),
				cluster.getMobicentsCache());
	}

	/**
	 * Binds the specified aci name with the specified activity context handle
	 * @param ach
	 * @param name
	 * @throws NameAlreadyBoundException
	 */
	public void bindName(Object ach, String name)
			throws NameAlreadyBoundException {
		final Node node = getNode();
		if (node.hasChild(name)) {
			throw new NameAlreadyBoundException("name already bound");
		} else {
			node.addChild(Fqn.fromElements(name)).put(CACHE_NODE_MAP_KEY, ach);
		}
	}

	/**
	 * Unbinds the specified aci name with the specified activity context id
	 * @param name
	 * @return
	 * @throws NameNotBoundException
	 */
	public Object unbindName(String name) throws NameNotBoundException {
		final Node node = getNode();
		final Node childNode = node.getChild(name);
		if (childNode == null) {
			throw new NameNotBoundException("name not bound");
		} else {
			final Object ach = childNode.get(CACHE_NODE_MAP_KEY);
			node.removeChild(name);
			return ach;
		}
	}

	/**
	 * Lookup of the activity context id bound to the specified aci name
	 * @param name
	 * @return
	 */
	public Object lookupName(String name) {
		final Node childNode = getNode().getChild(name);
		if (childNode == null) {
			return null;
		} else {
			return childNode.get(CACHE_NODE_MAP_KEY);
		}
	}

	/**
	 * Retrieves a map of the bindings. Key is the aci name and Value is the activity context handle
	 * @return
	 */
	public Map getNameBindings() {

		Map result = new HashMap();
		Node childNode = null;
		Object name = null;
		for (Object obj : getNode().getChildren()) {
			childNode = (Node) obj;
			name = childNode.getFqn().getLastElement();
			result.put(name, childNode.get(CACHE_NODE_MAP_KEY));
		}
		return result;
	}
}


/*
 * 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 javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.NotificationBroadcasterSupport;
import javax.management.ObjectName;

import org.mobicents.slee.container.SleeContainer;

/**
 * @author martins
 *
 */
public abstract class MobicentsServiceMBeanSupport extends NotificationBroadcasterSupport implements MBeanRegistration {

	private ObjectName objectName;
	protected MBeanServer server;
	protected SleeContainer sleeContainer;

	/**
	 *
	 */
	public MobicentsServiceMBeanSupport() {
		this(null);
	}

	/**
	 *
	 */
	public MobicentsServiceMBeanSupport(SleeContainer sleeContainer) {
		this.sleeContainer = sleeContainer;
	}

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

	/**
	 *
	 * @return
	 */
	public ObjectName getObjectName() {
		return objectName;
	}

	/*
	 * (non-Javadoc)
	 * @see org.jboss.system.ServiceMBeanSupport#preRegister(javax.management.MBeanServer, javax.management.ObjectName)
	 */
	public ObjectName preRegister(MBeanServer mbs, ObjectName oname) throws Exception {
		this.objectName = oname;
		this.server = mbs;
		return oname;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.management.MBeanRegistration#postRegister(java.lang.Boolean)
	 */
	@Override
	public void postRegister(Boolean arg0) {

	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.management.MBeanRegistration#preDeregister()
	 */
	@Override
	public void preDeregister() throws Exception {

	}

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.management.MBeanRegistration#postDeregister()
	 */
	@Override
	public void postDeregister() {

	}

}


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

import java.util.Iterator;
import java.util.Set;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.activity.ActivityContext;
import org.mobicents.slee.container.component.sbb.EventEntryDescriptor;
import org.mobicents.slee.container.event.EventContext;
import org.mobicents.slee.container.management.jmx.EventRouterConfiguration;
import org.mobicents.slee.container.sbbentity.SbbEntity;
import org.mobicents.slee.container.sbbentity.SbbEntityID;
import org.mobicents.slee.runtime.eventrouter.EventRouterImpl;

/**
 *
 * Class that can be used to find, while delivering an event, the next sbb
 * entity to be processed.
 *
 * @author martins
 *
 */
public class NextSbbEntityFinder {

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

	static class Result {

		final SbbEntity sbbEntity;
		final boolean deliverEvent;

		Result(SbbEntity sbbEntity, boolean deliverEvent) {
			super();
			this.sbbEntity = sbbEntity;
			this.deliverEvent = deliverEvent;
		}
	}

	private final EventRouterConfiguration eventRouterConfiguration = ((EventRouterImpl) SleeContainer
			.lookupFromJndi().getEventRouter()).getConfiguration();

	/**
	 * Retrieves the next sbb entity to handle the event.
	 *
	 * @param ac
	 * @param sleeEvent
	 * @param sbbEntitiesThatHandledCurrentEvent
	 * @return Result that indicates the next sbb entity to handle the event,
	 *         note that sbb entities that are not entitled to *deliver* the
	 *         event (service id is set or the event is not defined in sbb
	 *         descriptor) will only be returned in case event is activity end
	 *         event.
	 */
	public Result next(ActivityContext ac,
			EventContext sleeEvent, Set<SbbEntityID> sbbEntitiesThatHandledCurrentEvent, SleeContainer sleeContainer) {

		SbbEntityID sbbEntityId = null;
		SbbEntity sbbEntity = null;
		EventEntryDescriptor mEventEntry = null;

		// get the highest priority sbb from sbb entities attached to AC
		for (Iterator<SbbEntityID> iter = ac.getSortedSbbAttachmentSet(sbbEntitiesThatHandledCurrentEvent).iterator(); iter
				.hasNext();) {
			sbbEntityId = iter.next();
			sbbEntity = sleeContainer.getSbbEntityFactory().getSbbEntity(sbbEntityId,true);
			if (sbbEntity == null) {
				// ignore, sbb entity has been removed
				continue;
			}
			if (eventRouterConfiguration.isConfirmSbbEntityAttachement() && !sbbEntity.isAttached(ac.getActivityContextHandle())) {
				// detached by a concurrent tx, see Issue 2313
				continue;
			}
			if (sleeEvent.getService() != null && !sleeEvent.getService().equals(sbbEntityId.getServiceID())) {
				if (!sleeEvent.isActivityEndEvent()) {
					continue;
				}
				else {
					return new Result(sbbEntity, false);
				}
			}
			// check event is allowed to be handled by the sbb
			mEventEntry = sbbEntity.getSbbComponent().getDescriptor().getEventEntries().get(sleeEvent.getEventTypeId());
			if (mEventEntry != null && mEventEntry.isReceived()) {
				return new Result(sbbEntity, true);
			} else {
				if (!sleeEvent.isActivityEndEvent()) {
					if (logger.isDebugEnabled()) {
						logger
						.debug("Event is not received by sbb descriptor of entity "
								+ sbbEntityId + ", will not deliver event to sbb entity ...");
					}
					continue;
				}
				else {
					return new Result(sbbEntity, false);
				}
			}
		}

		return null;

	}

}