/*
 * 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.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.slee.profile.query.And;
import javax.slee.profile.query.Equals;
import javax.slee.profile.query.GreaterThan;
import javax.slee.profile.query.GreaterThanOrEquals;
import javax.slee.profile.query.HasPrefix;
import javax.slee.profile.query.LessThan;
import javax.slee.profile.query.LessThanOrEquals;
import javax.slee.profile.query.LongestPrefixMatch;
import javax.slee.profile.query.Not;
import javax.slee.profile.query.NotEquals;
import javax.slee.profile.query.Or;
import javax.slee.profile.query.QueryExpression;
import javax.slee.profile.query.RangeMatch;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.component.profile.ProfileSpecificationComponent;
import org.mobicents.slee.container.component.profile.query.CompareDescriptor;
import org.mobicents.slee.container.component.profile.query.HasPrefixDescriptor;
import org.mobicents.slee.container.component.profile.query.LongestPrefixMatchDescriptor;
import org.mobicents.slee.container.component.profile.query.QueryDescriptor;
import org.mobicents.slee.container.component.profile.query.QueryExpressionDescriptor;
import org.mobicents.slee.container.component.profile.query.QueryExpressionType;
import org.mobicents.slee.container.component.profile.query.QueryOptionsDescriptor;
import org.mobicents.slee.container.component.profile.query.QueryParameterDescriptor;
import org.mobicents.slee.container.component.profile.query.RangeMatchDescriptor;

/**
 *
 * JPAQueryBuilder.java
 *
 * @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a>
 */
public class JPAQueryBuilder {

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

  private ProfileSpecificationComponent psc;

  public JPAQueryBuilder(ProfileSpecificationComponent psc)
  {
    this.psc = psc;
  }

  // ####################
  // #  STATIC QUERIES  #
  // ####################

  private static HashMap<String, QueryWrapper> queriesMap = new HashMap<String, QueryWrapper>();

  public void parseStaticQueries()
  {
    List<? extends QueryDescriptor> queries = this.psc.getDescriptor().getQueryElements();

    for(QueryDescriptor query : queries)
    {
      QueryOptionsDescriptor queryOptions = query.getQueryOptions();

      boolean queryIsReadOnly = false;
      long queryMaxMatches = -1;
      if(queryOptions != null)
      {
        queryIsReadOnly = query.getQueryOptions().isReadOnly();
        queryMaxMatches = query.getQueryOptions().getMaxMatches();
      }

      logger.info("Query :: Name[" + query.getName() + "], Options[" + (queryOptions == null ? "" : ("Read-Only[" + queryIsReadOnly + "], Max-Matches[" + queryMaxMatches + "]")) + "]" );

      HashMap<String, Integer> queryParameters = new HashMap<String, Integer>();

      int i = 0;
      for(QueryParameterDescriptor parameter : query.getQueryParameters())
      {
        i++;
        logger.info("Parameter :: Index[" + i + "], Name[" + parameter.getName() + "], Type[" + parameter.getType() + "]");
        queryParameters.put( parameter.getName(), i );
      }

      long s = System.currentTimeMillis();
      String sqlQuery = "SELECT " + (queryMaxMatches != -1 ? ("TOP " + queryMaxMatches) : "") + " * " + getExpression( query.getQueryExpression(), queryParameters, 0 );
      logger.info("Query :: SQL[" + sqlQuery + "]");
      long e = System.currentTimeMillis();
      logger.info("Query :: Parsed in " + (e-s) + "ms.");

      queriesMap.put( query.getName(), new QueryWrapper(sqlQuery, queryMaxMatches, queryIsReadOnly) );
    }
  }

  private String getExpression(QueryExpressionDescriptor expression, HashMap<String, Integer> queryParameters, int deepness)
  {
    return getExpression( expression, queryParameters, deepness, null );
  }

  private String getExpression(QueryExpressionDescriptor expression, HashMap<String, Integer> queryParameters, int deepness, String sqlQuery)
  {
    List<QueryExpressionDescriptor> expressions = new ArrayList<QueryExpressionDescriptor>();
    expressions.add(expression);
    return getExpression( expressions, queryParameters, deepness, sqlQuery );
  }

  private String getExpression(List<? extends QueryExpressionDescriptor> expressions, HashMap<String, Integer> queryParameters, int deepness, String sqlQuery)
  {
    if(sqlQuery == null || sqlQuery.length() == 0)
      sqlQuery = "FROM <CLASS> WHERE ";

    String prefix = "  ";

    for(int i = 0; i < deepness; i++)
      prefix += "  ";

    for(QueryExpressionDescriptor expression : expressions)
    {
      switch(expression.getType())
      {
      case And:
        logger.info( prefix + "+--> And" );
        sqlQuery += " ( ";
        sqlQuery = getExpression( expression.getAnd(), queryParameters, deepness+1, sqlQuery );
        sqlQuery = replaceLast( sqlQuery, getLogicalOperator(expression.getType()), " ) ");
        break;
      case Compare:
        CompareDescriptor compare = expression.getCompare();
        logger.info( prefix + "+--> Compare[" + compare.getAttributeName() + " " + compare.getOp() + " " + getNotNull(queryParameters, compare.getAttributeName(), compare.getParameter(), compare.getValue()) + "]" );
        sqlQuery += "C" + compare.getAttributeName() + getSQLOperator(compare.getOp()) + getNotNull(queryParameters, compare.getAttributeName(), compare.getParameter(), compare.getValue());
        break;
      case HasPrefix:
        HasPrefixDescriptor hasPrefix = expression.getHasPrefix();
        logger.info( prefix + "+--> HasPrefix[" + hasPrefix.getAttributeName() + " => " + getNotNull(queryParameters, hasPrefix.getAttributeName(), hasPrefix.getParameter(), hasPrefix.getValue()) + "]" );
        sqlQuery += "C" + hasPrefix.getAttributeName() + " LIKE CONCAT(" + getNotNull(queryParameters, hasPrefix.getAttributeName(), hasPrefix.getParameter(), hasPrefix.getValue()) + ", '%') ";
        break;
      case LongestPrefixMatch:
        LongestPrefixMatchDescriptor longestPrefixMatch = expression.getLongestPrefixMatch();
        logger.info( prefix + "+--> LongestPrefixMatch[" + longestPrefixMatch.getAttributeName() + " >=< " + getNotNull(queryParameters, longestPrefixMatch.getAttributeName(), longestPrefixMatch.getParameter(), longestPrefixMatch.getValue()) + "]" );
        sqlQuery += getNotNull(queryParameters, longestPrefixMatch.getAttributeName(), longestPrefixMatch.getParameter(), longestPrefixMatch.getValue()) + " LIKE CONCAT(" + "C" + longestPrefixMatch.getAttributeName() + ", '%')";
        break;
      case Not:
        logger.info( prefix + "+--> Not" );
        sqlQuery += " NOT ( ";
        sqlQuery = getExpression( expression.getNot(), queryParameters, deepness+1, sqlQuery );
        sqlQuery = replaceLast( sqlQuery, getLogicalOperator(expression.getType()), " ) ");
        break;
      case Or:
        logger.info( prefix + "+--> Or" );
        sqlQuery += " ( ";
        sqlQuery = getExpression( expression.getOr(), queryParameters, deepness+1, sqlQuery );
        sqlQuery = replaceLast( sqlQuery, getLogicalOperator(expression.getType()), " ) ");
        break;
      case RangeMatch:
    	RangeMatchDescriptor rangeMatch = expression.getRangeMatch();
        logger.info( prefix + "+--> RangeMatch[" + rangeMatch.getAttributeName() + " => (" + getNotNull(queryParameters, rangeMatch.getAttributeName(), rangeMatch.getFromParameter(), rangeMatch.getFromValue()) + " : " + getNotNull(queryParameters, rangeMatch.getAttributeName(), rangeMatch.getToParameter(), rangeMatch.getToValue()) + ") ]" );
        sqlQuery += "C" + rangeMatch.getAttributeName() + " >= " + getNotNull(queryParameters, rangeMatch.getAttributeName(), rangeMatch.getFromParameter(), rangeMatch.getFromValue()) + " AND " + "C" + rangeMatch.getAttributeName() + " <= " + getNotNull(queryParameters, rangeMatch.getAttributeName(), rangeMatch.getToParameter(), rangeMatch.getToValue());
        break;
      }

      sqlQuery += getLogicalOperator(expression.getParentType());
    }

    return sqlQuery;
  }

  private String getNotNull(HashMap<String, Integer> queryParameters, String attributeName, String...strings)
  {
    for(String s : strings)
      if( s != null)
      {
        if(queryParameters.containsKey(s))
        {
          return "?" + queryParameters.get(s);
        }
        else
        {
          Class<?> retType = Integer.class;

          try
          {
            retType = this.psc.getProfileCmpInterfaceClass().getMethod("get" + attributeName.replace(attributeName.charAt(0), Character.toUpperCase(attributeName.charAt(0)))).getReturnType();
          }
          catch ( Exception e ) {
            e.printStackTrace();
          }

          if(retType == String.class || retType == Character.class || retType == char.class)
          {
            return "'" + s + "'";
          }

          return s;
        }
      }

    return null;
  }

  private String getSQLOperator(String op)
  {
    // An op attribute.
    // This attribute identifies the binary operator to apply to the Profile attribute
    // value. It can be one of the following values: equals, not-equals, less-than,
    // less-than-or-equals, greater-than, or greater-than-or-equals. If the Java
    // type of the Profile attribute is boolean or java.lang.Boolean then only
    // the equals, or not-equals operator are allowed.

    String sqlOperator = null;

    if(op.equals("equals"))
    {
      sqlOperator = " = ";
    }
    else if(op.equals("not-equals"))
    {
      sqlOperator = " != ";
    }
    else if(op.equals("less-than"))
    {
      sqlOperator = " < ";
    }
    else if(op.equals("less-than-or-equals"))
    {
      sqlOperator = " <= ";
    }
    else if(op.equals("greater-than"))
    {
      sqlOperator = " > ";
    }
    else if(op.equals("greater-than-or-equals"))
    {
      sqlOperator = " >= ";
    }

    return sqlOperator;
  }

  private String getLogicalOperator(QueryExpressionType expType)
  {
    if (expType == null)
      return "";

    switch (expType)
    {
    case And:
      return " AND ";
    case Or:
      return " OR ";
    case Not:
      return " NOT ";
    default:
      return "";
    }
  }

  public static QueryWrapper getQuery(String queryName)
  {
    return queriesMap.get(queryName);
  }

  // #####################
  // #  DYNAMIC QUERIES  #
  // #####################

  public static QueryWrapper parseDynamicQuery(QueryExpression query)
  {
    ArrayList<Object> params = new ArrayList<Object>();

    long s = System.currentTimeMillis();
    String sqlQuery = "SELECT * " + parseDynamicQuery( query, 0, null, params );
    logger.info("Query :: SQL[" + sqlQuery + "]");
    long e = System.currentTimeMillis();
    logger.info("Query :: Parsed in " + (e-s) + "ms.");

    return new QueryWrapper( sqlQuery, params );
  }

  private static String parseDynamicQuery(QueryExpression query, int deepness, String sqlQuery, ArrayList<Object> params)
  {
    if(sqlQuery == null || sqlQuery.length() == 0)
      sqlQuery = "FROM <CLASS> WHERE ";

    String prefix = "  ";

    for(int i = 0; i < deepness; i++)
      prefix += "  ";

    if(query instanceof Equals)
    {
      Equals equals = (Equals)query;

      logger.info( prefix + "+--> Equals[" + equals.getAttributeName() + " = " + equals.getAttributeValue() + "]" );
      //sqlQuery += " C" + equals.getAttributeName() + " = " + escapeAttributeValue(equals.getAttributeValue()) + " ";
      params.add( equals.getAttributeValue() );
      sqlQuery += " C" + equals.getAttributeName() + " = ?" + params.size() + " ";
    }
    else if (query instanceof NotEquals)
    {
      NotEquals notEquals = (NotEquals)query;

      logger.info( prefix + "+--> NotEquals[" + notEquals.getAttributeName() + " != " + notEquals.getAttributeValue() + "]" );
      //sqlQuery += " C" + notEquals.getAttributeName() + " != " + escapeAttributeValue(notEquals.getAttributeValue()) + " ";
      params.add( notEquals.getAttributeValue() );
      sqlQuery += " C" + notEquals.getAttributeName() + " != ?" + params.size() + " ";
    }
    else if (query instanceof LessThan)
    {
      LessThan lessThan = (LessThan)query;

      logger.info( prefix + "+--> LessThan[" + lessThan.getAttributeName() + " < " + lessThan.getAttributeValue() + "]" );
      //sqlQuery += " C" + lessThan.getAttributeName() + " < " + escapeAttributeValue(lessThan.getAttributeValue()) + " ";
      params.add( lessThan.getAttributeValue() );
      sqlQuery += " C" + lessThan.getAttributeName() + " < ?" + params.size() + " ";
    }
    else if (query instanceof LessThanOrEquals)
    {
      LessThanOrEquals lessThanOrEquals = (LessThanOrEquals)query;

      logger.info( prefix + "+--> LessThanOrEquals[" + lessThanOrEquals.getAttributeName() + " <= " + lessThanOrEquals.getAttributeValue() + "]" );
      //sqlQuery += " C" + lessThanOrEquals.getAttributeName() + " <= " + escapeAttributeValue(lessThanOrEquals.getAttributeValue()) + " ";
      params.add( lessThanOrEquals.getAttributeValue() );
      sqlQuery += " C" + lessThanOrEquals.getAttributeName() + " <= ?" + params.size() + " ";
    }
    else if (query instanceof GreaterThan)
    {
      GreaterThan greaterThan = (GreaterThan)query;

      logger.info( prefix + "+--> GreaterThan[" + greaterThan.getAttributeName() + " > " + greaterThan.getAttributeValue() + "]" );
      //sqlQuery += " C" + greaterThan.getAttributeName() + " > " + escapeAttributeValue(greaterThan.getAttributeValue()) + " ";
      params.add( greaterThan.getAttributeValue() );
      sqlQuery += " C" + greaterThan.getAttributeName() + " > ?" + params.size() + " ";
    }
    else if (query instanceof GreaterThanOrEquals)
    {
      GreaterThanOrEquals greaterThanOrEquals = (GreaterThanOrEquals)query;

      logger.info( prefix + "+--> GreaterThanOrEquals[" + greaterThanOrEquals.getAttributeName() + " >= " + greaterThanOrEquals.getAttributeValue() + "]" );
      //sqlQuery += " C" + greaterThanOrEquals.getAttributeName() + " >= " + escapeAttributeValue(greaterThanOrEquals.getAttributeValue()) + " ";
      params.add( greaterThanOrEquals.getAttributeValue() );
      sqlQuery += " C" + greaterThanOrEquals.getAttributeName() + " >= ?" + params.size() + " ";
    }
    else if (query instanceof And)
    {
      logger.info( prefix + "+--> And" );
      And and = (And)query;
      sqlQuery += "(";
      for(QueryExpression subAnd : and.getExpressions())
      {
        sqlQuery = parseDynamicQuery( subAnd, deepness+1, sqlQuery, params );
        sqlQuery += " AND ";
      }
      sqlQuery = replaceLast(sqlQuery, " AND ", ")");
    }
    else if (query instanceof Or)
    {
      logger.info( prefix + "+--> Or" );
      Or or = (Or)query;
      sqlQuery += "(";
      for(QueryExpression subOr : or.getExpressions())
      {
        sqlQuery = parseDynamicQuery( subOr, deepness+1, sqlQuery, params );
        sqlQuery += " OR ";
      }
      sqlQuery = replaceLast(sqlQuery, " OR ", ")");
    }
    else if (query instanceof Not)
    {
      logger.info( prefix + "+--> Not" );
      Not not = (Not)query;
      sqlQuery += " NOT ( ";
      sqlQuery = parseDynamicQuery( not.getExpression(), deepness+1, sqlQuery, params );
      sqlQuery += ")";
    }
    else if (query instanceof LongestPrefixMatch)
    {
      LongestPrefixMatch longestPrefixMatch = (LongestPrefixMatch)query;

      logger.info( prefix + "+--> LongestPrefixMatch[" + longestPrefixMatch.getAttributeName() + " >=< " + longestPrefixMatch.getAttributeValue() + "]" );
      //sqlQuery += " " + escapeAttributeValue(longestPrefixMatch.getAttributeValue()) + " LIKE CONCAT(" + "C" + longestPrefixMatch.getAttributeName() + ", '%') ";
      params.add( longestPrefixMatch.getAttributeValue() );
      sqlQuery += " ?" + params.size() + " LIKE CONCAT(" + "C" + longestPrefixMatch.getAttributeName() + ", '%') ";
    }
    else if (query instanceof HasPrefix)
    {
      HasPrefix hasPrefix = (HasPrefix)query;

      logger.info( prefix + "+--> HasPrefix[" + hasPrefix.getAttributeName() + " << " + hasPrefix.getAttributeValue() + "]" );
      //sqlQuery += " C" + hasPrefix.getAttributeName() + " LIKE CONCAT(" + escapeAttributeValue(hasPrefix.getAttributeValue()) + ", '%') ";
      params.add( hasPrefix.getAttributeValue() );
      sqlQuery += " C" + hasPrefix.getAttributeName() + " LIKE CONCAT(" + "?" + params.size() + ", '%') ";
    }
    else if (query instanceof RangeMatch)
    {
      RangeMatch rangeMatch = (RangeMatch)query;

      logger.info( prefix + "+--> RangeMatch[" + rangeMatch.getAttributeName() + " > " + rangeMatch.getFromValue() + " && " + rangeMatch.getAttributeName() + " < " + rangeMatch.getToValue() + "]" );
      params.add( rangeMatch.getFromValue() );
      params.add( rangeMatch.getToValue() );
      sqlQuery += " C" + rangeMatch.getAttributeName() + " >= " + "?" + (params.size()-1) + " AND " + "C" + rangeMatch.getAttributeName() + " <= " + "?" + params.size() + " ";
    }

    return sqlQuery;
  }

  // ######################
  // # COMMON FOR QUERIES #
  // ######################

  private static String replaceLast(String sourceString, String toBeReplaced, String replacement)
  {
    StringBuilder x = new StringBuilder(sourceString);
    int liof = x.lastIndexOf(toBeReplaced);

    if(liof >= 0)
      x.replace(liof, liof+4, replacement);

    return new String(x);
  }

}


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

/**
 * Start time:19:32:15 2009-02-05

 * Project: restcomm-jainslee-server-core

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

import java.beans.Introspector;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.slee.ComponentID;
import javax.slee.usage.UnrecognizedUsageParameterSetNameException;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.component.ProfileSpecificationComponentImpl;
import org.mobicents.slee.container.component.ResourceAdaptorComponentImpl;
import org.mobicents.slee.container.component.SbbComponentImpl;
import org.mobicents.slee.container.component.UsageParameterDescriptor;

/**
 * Start time:19:32:15 2009-02-05

 * Project: restcomm-jainslee-server-core

 *
 * This class is place where common elements like usage parameter interface is
 * validated. In 1.1 specs its widely usable - ra, profiles, sbbs. In 1.0 only
 * sbbs have those.
 *
 * @author baranowb - Bartosz Baranowski
 *
 * @author  Alexandre Mendonca
 */
public class UsageInterfaceValidator {

	private final static String _INCREMENT_METHOD_PREFIX = "increment";
	private final static String _GET_METHOD_PREFIX = "get";
	private final static String _SAMPLE_METHOD_PREFIX = "sample";

	private final static Set<String> _FORBBIDEN_WORDS;

	static {

		Set<String> tmp = new HashSet<String>();

		tmp.add("static");
		tmp.add("final");
		tmp.add("protected");
		tmp.add("public");
		tmp.add("native");
		tmp.add("finally");
		tmp.add("throw");
		tmp.add("catch");
		tmp.add("try");
		tmp.add("int");
		tmp.add("char");
		tmp.add("boolean");
		tmp.add("long");
		tmp.add("float");
		tmp.add("double");
		tmp.add("false");
		tmp.add("true");
		tmp.add("break");
		tmp.add("byte");
		tmp.add("case");
		tmp.add("class");
		tmp.add("continue");
		tmp.add("default");
		tmp.add("do");
		tmp.add("else");
		tmp.add("extends");
		tmp.add("implements");
		tmp.add("for");
		tmp.add("if");
		tmp.add("implements");
		tmp.add("import");
		tmp.add("instanceof");
		tmp.add("interface");
		tmp.add("new");
		tmp.add("package");
		tmp.add("protected");
		tmp.add("return");
		tmp.add("short");
		tmp.add("super");
		tmp.add("switch");
		tmp.add("this");
		tmp.add("throws");
		tmp.add("transient");
		tmp.add("void");
		tmp.add("volatile");
		tmp.add("while");

		_FORBBIDEN_WORDS = (Set<String>) Collections.unmodifiableSet(tmp);

	}

	private static transient Logger logger = Logger.getLogger(UsageInterfaceValidator.class);

	/**
	 * This methods validate component which has usage parameter interface. Its
	 * interface for methods. In case of 1.1 components parameters list must
	 * match evey method defined. In case of 1.0 components parameters list MUST
	 * be empty. It does not validate get usage method, those
	 *
	 * @param isSlee11
	 *
	 * @param usageInterface
	 *            - interface class itself
	 * @param parameters
	 *            - list of parameters, in case of 1.0 sbb this MUST be null.
	 * @return
	 */
	static boolean validateUsageParameterInterface(ComponentID id, boolean isSlee11, Class<?> usageInterface, List<UsageParameterDescriptor> parameters) {

		boolean passed = true;
		String errorBuffer = new String("");
		try {
			if (!usageInterface.isInterface()) {
				passed = false;
				errorBuffer = appendToBuffer(id, "Usage parameter interface class is not an interface", "11.2", errorBuffer);
				return passed;
			}

			// Interface constraints
			if (isSlee11 && usageInterface.getPackage() == null) {
				passed = false;
				errorBuffer = appendToBuffer(id, "Usage parameter interface must be declared in pacakge name space.", "11.2", errorBuffer);
			}

			if (!Modifier.isPublic(usageInterface.getModifiers())) {
				passed = false;
				errorBuffer = appendToBuffer(id, "Usage parameter interface must be declared as public.", "11.2", errorBuffer);
			}

			// parameters check

			Set<String> ignore = new HashSet<String>();
			ignore.add("java.lang.Object");
			Map<String, Method> interfaceMethods = ClassUtils.getAllInterfacesMethods(usageInterface, ignore);
			Map<String, UsageParameterDescriptor> localParametersMap = new HashMap<String, UsageParameterDescriptor>();

			Set<String> identifiedIncrement = new HashSet<String>();
			Set<String> identifiedGetIncrement = new HashSet<String>();
			Set<String> identifiedSample = new HashSet<String>();
			Set<String> identifiedGetSample = new HashSet<String>();
			// this is for 1.1, get and increment methods must match with type

			// validate parameter names if we are slee11
			if (isSlee11)
				for (UsageParameterDescriptor usage : parameters) {
					char c = usage.getName().charAt(0);
					if (!Character.isLowerCase(c)) {
						passed = false;
						errorBuffer = appendToBuffer(id,
								"Parameter name must start with lower case character and be start of valid jva identifier, parameter name from descriptor: " + usage.getName(), "11.2", errorBuffer);
					}

					localParametersMap.put(usage.getName(), usage);
				}
			// at the end we have to have empty list
			for (Entry<String, Method> entry : interfaceMethods.entrySet()) {
				// String declaredLongMethodName = entry.getKey();

				Method m = entry.getValue();
				String declaredMethodName = m.getName();
				String declaredPrameterName = null;
				Character c = null;
				// he we just do checks, methods against constraints
				// we remove them from parameters map, there is something left
				// or not present in map in case of 1.1

				// some variable that we need to store info about method
				boolean isIncrement = false;
				boolean isGetIncrement = false;
				boolean isGetSample = false;
				boolean isSample = false;

				// 1.0 comp
				if (declaredMethodName.startsWith(_SAMPLE_METHOD_PREFIX)) {
					declaredPrameterName = declaredMethodName.replaceFirst(_SAMPLE_METHOD_PREFIX, "");
					c = declaredPrameterName.charAt(0);
					isSample = true;

					// 1.0 comp
				} else if (declaredMethodName.startsWith(_INCREMENT_METHOD_PREFIX)) {
					declaredPrameterName = declaredMethodName.replaceFirst(_INCREMENT_METHOD_PREFIX, "");
					c = declaredPrameterName.charAt(0);
					isIncrement = true;

					// 1.1 only
				} else if (declaredMethodName.startsWith(_GET_METHOD_PREFIX)) {
					declaredPrameterName = declaredMethodName.replaceFirst(_GET_METHOD_PREFIX, "");
					c = declaredPrameterName.charAt(0);
					if (!isSlee11) {
						passed = false;
						errorBuffer = appendToBuffer(id, "Wrong method declared in parameter usage interface. Get method for counter parameter types are allowed only in JSLEE 1.1, method: "
								+ declaredMethodName, "11.2.X", errorBuffer);
					}
					if (m.getReturnType().getName().compareTo("javax.slee.usage.SampleStatistics") == 0) {
						isGetSample = true;
					} else {
						// we asume thats increment get
						isGetIncrement = true;
					}

				} else {
					passed = false;
					errorBuffer = appendToBuffer(id, "Wrong method decalred in parameter usage interface. Methods must start with either \"get\", \"sample\" or \"increment\", method: "
							+ declaredMethodName, "11.2.X", errorBuffer);
					continue;
				}

				if (!Character.isUpperCase(c)) {
					passed = false;
					errorBuffer = appendToBuffer(id, "Method stripped of prefix, either \"get\", \"sample\" or \"increment\", must have following upper case character,method: " + declaredMethodName,
							"11.2", errorBuffer);

				}

				declaredPrameterName = Introspector.decapitalize(declaredPrameterName);

				if (!isValidJavaIdentifier(declaredPrameterName)) {
					passed = false;
					errorBuffer = appendToBuffer(id, "Parameter name must be valid java identifier: " + declaredPrameterName, "11.2", errorBuffer);
				}

				// well we have indentified parameter, lets store;
				if (isIncrement) {
					if (identifiedIncrement.contains(declaredMethodName)) {
						passed = false;
						errorBuffer = appendToBuffer(id, "Duplicate declaration of usage parameter, possibly twe methods with the same name and different signature, method: " + declaredMethodName,
								"11.2", errorBuffer);
					} else {
						identifiedIncrement.add(declaredPrameterName);
						if (!validateParameterSetterSignatureMethod(id, m, "11.2.3")) {
							passed = false;

						}
					}

				} else if (isGetIncrement) {
					if (identifiedGetIncrement.contains(declaredMethodName)) {
						passed = false;
						errorBuffer = appendToBuffer(id, "Duplicate declaration of usage parameter, possibly twe methods with the same name and different signature, method: " + declaredMethodName,
								"11.2", errorBuffer);
					} else {
						identifiedGetIncrement.add(declaredPrameterName);
						if (!validateParameterGetterSignatureMethod(id, m, "11.2.2", Long.TYPE)) {
							passed = false;

						}
					}

				} else if (isGetSample) {
					if (identifiedGetSample.contains(declaredMethodName)) {
						passed = false;
						errorBuffer = appendToBuffer(id, "Duplicate declaration of usage parameter, possibly twe methods with the same name and different signature, method: " + declaredMethodName,
								"11.2", errorBuffer);
					} else {
						identifiedGetSample.add(declaredPrameterName);
						if (!validateParameterGetterSignatureMethod(id, m, "11.2.4", javax.slee.usage.SampleStatistics.class)) {
							passed = false;

						}
					}

				} else if (isSample) {
					if (identifiedSample.contains(declaredMethodName)) {
						passed = false;
						errorBuffer = appendToBuffer(id, "Duplicate declaration of usage parameter, possibly twe methods with the same name and different signature, method: " + declaredMethodName,
								"11.2", errorBuffer);
					} else {
						identifiedSample.add(declaredPrameterName);
						if (!validateParameterSetterSignatureMethod(id, m, "11.2.1")) {
							passed = false;
							errorBuffer = appendToBuffer(id,
									"Duplicate declaration of usage parameter, possibly twe methods with the same name and different signature, method: " + declaredMethodName, "11.2", errorBuffer);
						}
					}

				}

				// UFFF, lets start the play
				// /uh its a bit complicated
			}
			// we siganture here is ok, return types also, no duplicates, left:
			// 1. cross check field types that we found - sample vs increments -
			// there cant be doubles
			// 2. remove all from list, if something is left, bam, we lack one
			// method or have to many :)
			Set<String> agregatedIncrement = new HashSet<String>();
			Set<String> agregatedSample = new HashSet<String>();

			agregatedIncrement.addAll(identifiedGetIncrement);
			agregatedIncrement.addAll(identifiedIncrement);

			agregatedSample.addAll(identifiedGetSample);
			agregatedSample.addAll(identifiedSample);
			Set<String> tmp = new HashSet<String>(agregatedSample);

			tmp.retainAll(agregatedIncrement);
			if (!tmp.isEmpty()) {
				// ugh, its the end
				passed = false;
				errorBuffer = appendToBuffer(id, "Usage parameters can be associated only with single type - increment or sample, offending parameters: " + Arrays.toString(tmp.toArray()), "11.2",
						errorBuffer);

				return passed;
			}

			if (isSlee11) {
				tmp.clear();
				tmp.addAll(agregatedSample);
				tmp.addAll(agregatedIncrement);

				// localParametersMap.size()!=0 - cause we can have zero of them
				// - usage-parameter may not be present so its generation is
				// turned off
				if (localParametersMap.size() != tmp.size() && localParametersMap.size() != 0) {

					passed = false;

					String errorPart = null;
					if (localParametersMap.size() > tmp.size()) {
						// is there any bettter way?
						for (String s : localParametersMap.keySet())
							tmp.remove(s);
						errorPart = "More parameters are defined in descriptor, offending parameters: " + Arrays.toString(tmp.toArray());
					} else {
						for (String s : tmp)
							localParametersMap.remove(s);
						errorPart = "More parameters are defined in descriptor, offending parameters: " + Arrays.toString(localParametersMap.keySet().toArray());
					}

					errorBuffer = appendToBuffer(id, "Failed to map descriptor defined usage parameters against interface class methods. " + errorPart, "11.2", errorBuffer);

				}
			}
		} finally {
			if (!passed) {
				logger.error(errorBuffer);
				// System.err.println(errorBuffer);
			}
		}

		return passed;
	}

	private static boolean isValidJavaIdentifier(String declaredPrameterName) {

		for (int i = 0; i < declaredPrameterName.length(); i++) {
			char ch = declaredPrameterName.charAt(i);
			if (i == 0) {
				// we allow only alpha and _ ??
				if (Character.isLetter(ch) || ch == "_".charAt(0)) {
				} else {
					if (logger.isDebugEnabled()) {
						logger.debug("Usage parameter: " + declaredPrameterName + " is not valid java identifier: " + new Character(ch));
					}
					return false;
				}
			} else {
				if (!Character.isJavaIdentifierPart(ch)) {
					if (logger.isDebugEnabled()) {
						logger.debug("Usage parameter: " + declaredPrameterName + " is not valid java identifier: " + new Character(ch));
					}
					return false;
				}
			}
		}

		if (_FORBBIDEN_WORDS.contains(declaredPrameterName)) {
			if (logger.isDebugEnabled()) {
				logger.debug("Usage parameter: " + declaredPrameterName + " is not valid java identifier, its forbbied java keyword.");
			}
			return false;
		}

		return true;
	}

	static boolean validateParameterGetterSignatureMethod(ComponentID id, Method m, String section, Class returnType) {
		boolean passed = true;
		String errorBuffer = new String("");
		try {
			// public, abstract, void, no throws, long parameter
			int modifiers = m.getModifiers();
			if (!Modifier.isPublic(modifiers)) {
				passed = false;
				errorBuffer = appendToBuffer(id, "Usage paremter method must be declared public, method: " + m, section, errorBuffer);
			}

			if (!Modifier.isAbstract(modifiers)) {
				passed = false;
				errorBuffer = appendToBuffer(id, "Usage paremter method must be declared abstract, method: " + m, section, errorBuffer);
			}

			if (m.getExceptionTypes().length > 0) {
				passed = false;
				errorBuffer = appendToBuffer(id, "Usage paremter method must not declared throws clause, method: " + m, section, errorBuffer);
			}

			if (m.getReturnType().getName().compareTo(returnType.getName()) != 0) {
				passed = false;
				errorBuffer = appendToBuffer(id, "Usage paremter method must not declare return type, method: " + m, section, errorBuffer);
			}

			Class[] params = new Class[] {};
			if (!Arrays.equals(m.getParameterTypes(), params)) {
				passed = false;
				errorBuffer = appendToBuffer(id, "Usage paremter method must not have parameters, method: " + m, section, errorBuffer);
			}

		} finally {
			if (!passed) {
				logger.error(errorBuffer);
				// ////System.err.println(errorBuffer);
			}
		}

		return passed;
	}

	static boolean validateParameterSetterSignatureMethod(ComponentID id, Method m, String section) {
		boolean passed = true;
		String errorBuffer = new String("");
		try {
			// public, abstract, void, no throws, long parameter
			int modifiers = m.getModifiers();
			if (!Modifier.isPublic(modifiers)) {
				passed = false;
				errorBuffer = appendToBuffer(id, "Usage paremter method must be declared public, method: " + m, section, errorBuffer);
			}

			if (!Modifier.isAbstract(modifiers)) {
				passed = false;
				errorBuffer = appendToBuffer(id, "Usage paremter method must be declared abstract, method: " + m, section, errorBuffer);
			}

			if (m.getExceptionTypes().length > 0) {
				passed = false;
				errorBuffer = appendToBuffer(id, "Usage paremter method must not declared throws clause, method: " + m, section, errorBuffer);
			}

			if (m.getReturnType().getName().compareTo("void") != 0) {
				passed = false;
				errorBuffer = appendToBuffer(id, "Usage paremter method must not declare return type, method: " + m, section, errorBuffer);
			}

			Class[] params = new Class[] { Long.TYPE };
			if (!Arrays.equals(m.getParameterTypes(), params)) {
				passed = false;
				errorBuffer = appendToBuffer(id, "Usage paremter method must have single parameter of type long, method: " + m, section, errorBuffer);
			}

		} finally {
			if (!passed) {
				logger.error(errorBuffer);
				// ////System.err.println(errorBuffer);
			}
		}

		return passed;
	}

	static boolean validateSbbUsageParameterInterface(SbbComponentImpl component, Map<String, Method> sbbAbstractClassMethods, Map<String, Method> sbbAbstractMethodsFromSuperClasses) {

		String errorBuffer = new String("");
		boolean passed = true;
		boolean foundAtleastOne = false;
		String methodName = "getDefaultSbbUsageParameterSet";

		Method m = null;

		m = ClassUtils.getMethodFromMap(methodName, new Class[] {}, sbbAbstractClassMethods, sbbAbstractMethodsFromSuperClasses);

		if (m != null) {
			foundAtleastOne = true;
			if (!validateGetUsageMethodSignature(component.getSbbID(), m, component.getUsageParametersInterface(), new Class[] {}, "8.4.1")) {
				passed = false;

			}

			sbbAbstractClassMethods.remove(ClassUtils.getMethodKey(m));
			sbbAbstractMethodsFromSuperClasses.remove(ClassUtils.getMethodKey(m));

		}
		methodName = "getSbbUsageParameterSet";

		m = ClassUtils.getMethodFromMap(methodName, new Class[] { String.class }, sbbAbstractClassMethods, sbbAbstractMethodsFromSuperClasses);

		if (m != null) {
			foundAtleastOne = true;
			if (!validateGetUsageMethodSignature(component.getSbbID(), m, component.getUsageParametersInterface(), new Class[] { UnrecognizedUsageParameterSetNameException.class }, "8.4.1")) {
				passed = false;

			}
			sbbAbstractClassMethods.remove(ClassUtils.getMethodKey(m));
			sbbAbstractMethodsFromSuperClasses.remove(ClassUtils.getMethodKey(m));
		}

		if (!validateUsageParameterInterface(component.getSbbID(), component.isSlee11(), component.getUsageParametersInterface(), component.getDescriptor().getSbbUsageParametersInterface().getUsageParameter())) {
			passed = false;
		}

		if (!foundAtleastOne) {
			passed = false;
			errorBuffer = appendToBuffer(component.getSbbID(), "Atleast one get usage interface method must be present(it must be public).", "8.4.1", errorBuffer);
		}

		if (!passed) {
			logger.error(errorBuffer);
			// System.err.println(errorBuffer);
		}

		return passed;

	}

	static boolean validateGetUsageMethodSignature(ComponentID id, Method m, Class returnType, Class[] exceptions, String section) {

		// must be public, abstract
		boolean passed = true;
		String errorBuffer = new String("");

		int modifiers = m.getModifiers();
		if (!Modifier.isAbstract(modifiers)) {
			passed = false;
			errorBuffer = appendToBuffer(id, "Usage interface access method must be abstract, method name: " + m.getName(), section, errorBuffer);
		}

		if (!Modifier.isPublic(modifiers)) {
			passed = false;
			errorBuffer = appendToBuffer(id, "Usage interface access method must be public, method name: " + m.getName(), section, errorBuffer);
		}

		// if (Modifier.isStatic(modifiers)) {
		// passed = false;
		// errorBuffer =
		// appendToBuffer(id,"Usage interface access method must be abstract is static, method name: "
		// + m.getName(),
		// section, errorBuffer);
		// }

		// FIXME: native?
		if (!Arrays.equals(m.getExceptionTypes(), exceptions)) {
			passed = false;
			errorBuffer = appendToBuffer(id, "Usage interface access method has wrong exception types defined, method: " + m.getName() + ", allowed: " + Arrays.toString(exceptions) + ", present: "
					+ Arrays.toString(m.getExceptionTypes()), section, errorBuffer);

		}

		if (m.getReturnType().getName().compareTo(returnType.getName()) == 0 || ClassUtils.checkInterfaces(returnType, m.getReturnType().getName()) != null) {

			// ok

		} else {
			passed = false;
			errorBuffer = appendToBuffer(id, "Usage interface access method has wrong return type defined, method: " + m.getName(), section, errorBuffer);
		}
		if (!passed) {
			logger.error(errorBuffer);
			// System.err.println(errorBuffer);
		}

		return passed;
	}

	static boolean validateResourceAdaptorUsageParameterInterface(ResourceAdaptorComponentImpl component) {

		boolean passed = true;
		if (!validateUsageParameterInterface(component.getResourceAdaptorID(), component.isSlee11(), component.getUsageParametersInterface(), component.getDescriptor()
				.getResourceAdaptorUsageParametersInterface().getUsageParameter())) {
			passed = false;
		}

		return passed;
	}

	static boolean validateProfileSpecificationUsageParameterInterface(ProfileSpecificationComponentImpl component, Map<String, Method> abstractClassMethods,
			Map<String, Method> abstractMethodsFromSuperClasses) {

		String errorBuffer = new String("");
		boolean passed = true;
		boolean foundAtleastOne = false;
		String methodName = "getDefaultUsageParameterSet";

		Method m = null;

		m = ClassUtils.getMethodFromMap(methodName, new Class[] {}, abstractClassMethods, abstractMethodsFromSuperClasses);

		if (m != null) {
			foundAtleastOne = true;
			if (!validateGetUsageMethodSignature(component.getProfileSpecificationID(), m, component.getUsageParametersInterface(), new Class[] {}, "11.4.2")) {
				passed = false;

			}

			abstractClassMethods.remove(ClassUtils.getMethodKey(m));
			abstractMethodsFromSuperClasses.remove(ClassUtils.getMethodKey(m));

		}
		methodName = "getUsageParameterSet";

		m = ClassUtils.getMethodFromMap(methodName, new Class[] { String.class }, abstractClassMethods, abstractMethodsFromSuperClasses);

		if (m != null) {
			foundAtleastOne = true;
			if (!validateGetUsageMethodSignature(component.getProfileSpecificationID(), m, component.getUsageParametersInterface(), new Class[] { UnrecognizedUsageParameterSetNameException.class },
					"11.4.2")) {
				passed = false;

			}
			abstractClassMethods.remove(ClassUtils.getMethodKey(m));
			abstractMethodsFromSuperClasses.remove(ClassUtils.getMethodKey(m));
		}

		if (!validateUsageParameterInterface(component.getProfileSpecificationID(), component.isSlee11(), component.getUsageParametersInterface(), component.getDescriptor()
				.getProfileUsageParameterInterface().getUsageParameter())) {
			passed = false;
		}

		if (!foundAtleastOne) {
			passed = false;
			errorBuffer = appendToBuffer(component.getProfileSpecificationID(), "Atleast one get usage interface method must be present(it must be public).", "11.4.2", errorBuffer);
		}

		if (!passed) {
			logger.error(errorBuffer);
			// System.err.println(errorBuffer);
		}

		return passed;
	}

	protected static String appendToBuffer(ComponentID id, String message, String section, String buffer) {
		buffer += (id + " : violates section " + section + " of jSLEE 1.1 specification : " + message + "\n");
		return buffer;
	}

}


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

/***************************************************
 *                                                 *
 *  Restcomm: The Open Source VoIP Platform      *
 *                                                 *
 *  Distributable under LGPL license.              *
 *  See terms of license at gnu.org.               *
 *                                                 *
 *  Created on 2005-5-21                             *
 *                                                 *
 ***************************************************/

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

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

import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;

import org.apache.log4j.Logger;

/**
 * @author baranowb
 */
public class ClassUtils {

	private static final String PUBLIC_IDENTIFIER = "Public";
	private static Logger logger = Logger.getLogger(ClassUtils.class);

	public static final String IS_PREFIX = "is";
	public static final String GET_PREFIX = "get";
	public static final String SET_PREFIX = "set";

	/**
	 * Searches for provided interface in passed Class object - it can be class
	 * or interface. If it finds, it return instance of it.
	 *
	 * @param classOrInterfaceWithInterfaces
	 * @param interfaceSearched
	 * @return
	 */
	public static Class checkInterfaces(Class classOrInterfaceWithInterfaces, String interfaceSearched) {
		Class returnValue = null;

		if (classOrInterfaceWithInterfaces.getName().compareTo(interfaceSearched) == 0) {
			return classOrInterfaceWithInterfaces;

		}
		// we do check only on get interfaces
		for (Class iface : classOrInterfaceWithInterfaces.getInterfaces()) {
			if (iface.getName().compareTo(interfaceSearched) == 0) {
				returnValue = iface;

			} else {
				returnValue = checkInterfaces(iface, interfaceSearched);
			}

			if (returnValue != null)
				break;
		}

		if (!classOrInterfaceWithInterfaces.isInterface() && returnValue == null) {
			Class superClass = classOrInterfaceWithInterfaces.getSuperclass();
			if (superClass != null) {
				returnValue = checkInterfaces(superClass, interfaceSearched);
			}
		}

		return returnValue;
	}

	public static String getMethodKey(Method method) {
		return method.getName() + Arrays.toString(method.getParameterTypes());
		// //System.err.println("KEY: "+ret);
	}

	public static Map<String, Method> getConcreteMethodsFromClass(Class xClass) {
		HashMap<String, Method> concreteMethods = new HashMap<String, Method>();
		Method[] methods = xClass.getDeclaredMethods();
		for (int i = 0; i < methods.length; i++) {
			int mods = methods[i].getModifiers();

			if (!Modifier.isAbstract(mods) && !Modifier.isNative(mods)) {
				concreteMethods.put(getMethodKey(methods[i]), methods[i]);
			}
		}

		return concreteMethods;
	}

	public static Map<String, Method> getConcreteMethodsFromSuperClasses(Class xClass) {
		HashMap<String, Method> concreteMethods = new HashMap<String, Method>();

		// We could; use CtClass.getMethods() which:
		// Returns an array containing CtMethod objects representing all the
		// non-private methods of the class. That array includes non-private
		// methods inherited from the superclasses. But we dont want
		// java.lang.Object
		Method[] methods = null;
		Class superClass;

		superClass = xClass.getSuperclass();

		while (superClass.getName().compareTo("java.lang.Object") != 0) {
			methods = superClass.getDeclaredMethods();
			for (int i = 0; i < methods.length; i++) {
				if (!Modifier.isAbstract(methods[i].getModifiers()) && !Modifier.isNative(methods[i].getModifiers())) {
					concreteMethods.put(getMethodKey(methods[i]), methods[i]);
				}
			}
			superClass = superClass.getSuperclass();
		}

		return concreteMethods;
	}

	/**
	 * Returns methods of this interface and all super interfaces
	 *
	 * @param ctInterfaceClass
	 * @return
	 */
	public static Map<String, Method> getAllInterfacesMethods(Class xInterfaceClass, Set<String> ignore) {
		HashMap<String, Method> abstractMethods = new HashMap<String, Method>();
		Method[] methods = null;
		Class[] superInterfaces;

		superInterfaces = xInterfaceClass.getInterfaces();

		for (Class superInterface : superInterfaces) {
			if (!ignore.contains(superInterface.getName()))
				abstractMethods.putAll(getAllInterfacesMethods(superInterface, ignore));
		}

		methods = xInterfaceClass.getDeclaredMethods();
		for (int i = 0; i < methods.length; i++) {
			abstractMethods.put(getMethodKey(methods[i]), methods[i]);
		}

		return abstractMethods;
	}

	public static Map<String, Method> getAbstractMethodsFromClass(Class xClass) {
		HashMap<String, Method> abstractMethods = new HashMap<String, Method>();

		// This includes methods only decalred, we also methods that are nto
		// implemented, but abstract since they come from interfaces.... ech ;[
		Method[] methods = xClass.getDeclaredMethods();
		for (int i = 0; i < methods.length; i++) {
			if (Modifier.isAbstract(methods[i].getModifiers())) {
				abstractMethods.put(getMethodKey(methods[i]), methods[i]);
			}
		}

		// now here comes methods from interfaces
		Set<String> ignore = new HashSet<String>();
		ignore.add("java.lang.Object");
		Map<String, Method> interfaceMethods = getAllInterfacesMethods(xClass, ignore);
		for (Method im : interfaceMethods.values()) {
			try {
				Method m = xClass.getMethod(im.getName(), im.getParameterTypes());
				if (Modifier.isAbstract(m.getModifiers())) {
					abstractMethods.put(getMethodKey(m), m);
				}
			} catch (SecurityException e) {

			} catch (NoSuchMethodException e) {
				// TODO Auto-generated catch block
				// e.printStackTrace();
				// in any case this shoudl be present there
			}
		}

		// //System.err.println("RET : "+abstractMethods);
		return abstractMethods;
	}

	public static Map<String, Method> getAbstractMethodsFromSuperClasses(Class xClass) {
		HashMap<String, Method> abstractMethods = new HashMap<String, Method>();
		Method[] methods = null;
		Class superClass;

		superClass = xClass.getSuperclass();
		while (superClass.getName().compareTo("java.lang.Object") != 0) {
			methods = superClass.getDeclaredMethods();
			for (int i = 0; i < methods.length; i++) {
				if (Modifier.isAbstract(methods[i].getModifiers())) {
					abstractMethods.put(getMethodKey(methods[i]), methods[i]);
				}
			}

			Set<String> ignore = new HashSet<String>();
			ignore.add("java.lang.Object");
			Map<String, Method> interfaceMethods = getAllInterfacesMethods(superClass, ignore);
			for (Method im : interfaceMethods.values()) {
				try {
					// yes, xClass
					Method m = xClass.getMethod(im.getName(), im.getParameterTypes());
					if (Modifier.isAbstract(m.getModifiers())) {
						abstractMethods.put(getMethodKey(m), m);
					}
				} catch (SecurityException e) {

				} catch (NoSuchMethodException e) {
					// TODO Auto-generated catch block
					// e.printStackTrace();
					// in any case this shoudl be present there
				}
			}

			superClass = superClass.getSuperclass();
		}

		// //System.err.println("RET SUPER: "+abstractMethods);
		return abstractMethods;
	}

	// public static Method getMethodFromMap(String name, String[]
	// parameterNames,Map<String,Method>... methods)
	// {
	// String key=name+Arrays.toString(parameterNames);
	// for(Map<String,Method> m:methods)
	// if(m.containsKey(key))
	// {
	// return m.get(key);
	// }else
	// {
	//
	// }
	//
	// return null;
	//
	// }

	public static Method getMethodFromMap(String name, Class[] parameters, Map<String, Method>... methods) {
		String key = name + Arrays.toString(parameters);
		for (Map<String, Method> m : methods) {
			if (m.containsKey(key)) {
				return m.get(key);
			} else {

			}
		}
		return null;
	}

	public static Class checkClasses(Class xClass, String classToSearch) {

		if (xClass.getName().compareTo(classToSearch) == 0) {
			return xClass;

		}
		Class superClass;

		superClass = xClass.getSuperclass();

		while (superClass.getName().compareTo("java.lang.Object") != 0) {

			if (xClass.getName().compareTo(classToSearch) == 0) {
				return xClass;

			}

			superClass = superClass.getSuperclass();
		}

		return null;
	}

}


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

package org.restcomm.slee.container.build.as7.deployment;

import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Hashtable;

/**
 *
 * Entity Resolver for JAIN SLEE DTDs used by Deployment
 *
 * @author  Alexandre Mendonca
 */
public class SleeDeployerEntityResolver implements EntityResolver {

    private Hashtable<String, URL> resources = null;

    public static SleeDeployerEntityResolver INSTANCE = new SleeDeployerEntityResolver();

    private SleeDeployerEntityResolver()
    {
        resources = new Hashtable<String, URL>();

        // For SLEE 1.0
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Deployable Unit 1.0//EN", "dtd/slee-deployable-unit_1_0.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE SBB 1.0//EN", "dtd/slee-sbb-jar_1_0.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Service 1.0//EN", "dtd/slee-service-xml_1_0.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Resource Adaptor Type 1.0//EN", "dtd/slee-resource-adaptor-type-jar_1_0.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Resource Adaptor 1.0//EN", "dtd/slee-resource-adaptor-jar_1_0.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Profile Specification 1.0//EN", "dtd/slee-profile-spec-jar_1_0.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Event 1.0//EN", "dtd/slee-event-jar_1_0.dtd");

        // For SLEE 1.1
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Deployable Unit 1.1//EN", "dtd/slee-deployable-unit_1_1.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE SBB 1.1//EN", "dtd/slee-sbb-jar_1_1.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Service 1.1//EN", "dtd/slee-service-xml_1_1.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Resource Adaptor Type 1.1//EN", "dtd/slee-resource-adaptor-type-jar_1_1.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Resource Adaptor 1.1//EN", "dtd/slee-resource-adaptor-jar_1_1.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Profile Specification 1.1//EN", "dtd/slee-profile-spec-jar_1_1.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Event 1.1//EN", "dtd/slee-event-jar_1_1.dtd");
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Library 1.1//EN", "dtd/slee-library-jar_1_1.dtd");

        // For SLEE 1.1 Extensions
        registerResource("-//Sun Microsystems, Inc.//DTD JAIN SLEE Ext Library 1.1//EN", "dtd/slee-library-jar_1_1-ext.dtd");
    }

    /**
     * Adds a URL to the specified resource (as returned by the system classloader) to the resource table of the resolver.
     *
     * @param publicID the public id of the resource
     * @param resourceName the path (starting from a location in the class path) and name of the dtd that should be used by the resolver for documents
     *                      with the specified public id.
     */
    private void registerResource(String publicID, String resourceName)
    {
        URL url = this.getClass().getClassLoader().getResource(resourceName);

        if (url != null) {
            resources.put(publicID, url);
        }
        else {
            throw new IllegalStateException("Cannot find resource:" + resourceName);
        }
    }

    /**
     * Creates an InputSource with a SystemID corresponding to a local dtd file.
     *
     * @param publicId The public identifier of the external entity being referenced, or null if none was supplied.
     * @param systemId The system identifier of the external entity being referenced (This is a dummy parameter and is overridden by the resource names
     *                 earlier specified by the registrerResource) method to correspond to the publicID.
     * @return An InputSource object describing the new input source, or null to request that the parser open a regular URI connection to the system identifier.
     * @exception org.xml.sax.SAXException Any SAX exception, possibly wrapping another exception.
     * @exception java.io.IOException A Java-specific IO exception, possibly the result of creating a new InputStream or Reader for the InputSource.
     */
    public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException
    {
        URL resourceURL = resources.get(publicId);

        if(resourceURL != null) {
            InputStream resourceStream = resourceURL.openStream();
            InputSource is = new InputSource(resourceStream);
            is.setPublicId(publicId);
            is.setSystemId(resourceURL.toExternalForm());
            return is;
        }

        return null;
    }
}


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

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

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

import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import javax.management.MBeanNotificationInfo;
import javax.slee.ComponentID;
import javax.slee.InvalidArgumentException;
import javax.slee.UnrecognizedComponentException;
import javax.slee.facilities.Level;
import javax.slee.facilities.TraceLevel;
import javax.slee.facilities.Tracer;
import javax.slee.management.ManagementException;
import javax.slee.management.NotificationSource;
import javax.slee.management.TraceMBean;
import javax.slee.management.UnrecognizedNotificationSourceException;
import javax.transaction.SystemException;

import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.management.TraceManagement;
import org.mobicents.slee.container.transaction.SleeTransactionManager;
import org.mobicents.slee.container.transaction.TransactionalAction;
import org.mobicents.slee.runtime.facilities.TraceFacilityImpl;
import org.mobicents.slee.runtime.facilities.TracerImpl;
import org.mobicents.slee.runtime.facilities.TracerStorage;

/**
 * Implementation of the Trace MBean.
 *
 * @author M. Ranganathan
 * @author baranowb
 * @author martins
 */
@SuppressWarnings("deprecation")
public class TraceMBeanImpl extends MobicentsServiceMBeanSupport implements TraceManagement,TraceMBeanImplMBean {

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

	private final TraceFacilityImpl traceFacility;

	// used in sync level ops between log4j and slee tracers
	private static final int LOG4J_LEVEL_SYNC_PERIOD = 1;
	private ScheduledFuture<?> scheduledFuture = null;

	/**
	 * Creates the trace mbean.
	 *
	 */
	public TraceMBeanImpl() {
		super();
		this.traceFacility = new TraceFacilityImpl(this);
	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.core.SleeContainerModule#setSleeContainer(org.mobicents.slee.core.SleeContainer)
	 */
	public void setSleeContainer(SleeContainer sleeContainer) {
		super.sleeContainer = sleeContainer;
	}

	/* (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.MobicentsServiceMBeanSupport#getSleeContainer()
	 */
	@Override
	public SleeContainer getSleeContainer() {
		return sleeContainer;
	}

	/**
	 *
	 * @return the traceFacility
	 */
	public TraceFacilityImpl getTraceFacility() {
		return traceFacility;
	}

	@Override
	public String toString() {
		return "Trace MBean Impl : "
			+ "\n+-- Tracers: "	+ tracerStorage.toString();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.management.TraceMBean#setTraceLevel(javax.slee.ComponentID,
	 * javax.slee.facilities.Level)
	 */
	public void setTraceLevel(ComponentID componentId, Level level) throws NullPointerException, UnrecognizedComponentException, ManagementException {
		if (componentId == null)
			throw new NullPointerException("null component Id");
		this.traceFacility.checkComponentID(componentId);
		this.traceFacility.setTraceLevel(componentId, level);

	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * javax.slee.management.TraceMBean#getTraceLevel(javax.slee.ComponentID)
	 */
	public Level getTraceLevel(ComponentID componentId) throws NullPointerException, UnrecognizedComponentException, ManagementException {
		if (componentId == null)
			throw new NullPointerException(" null component Id ");
		return this.traceFacility.getTraceLevel(componentId);
	}

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

		if (this.traceFacility == null)
			return null;

		String[] notificationTypes = this.traceFacility.getNotificationTypes();
		return new MBeanNotificationInfo[] { new MBeanNotificationInfo(notificationTypes, TraceMBean.TRACE_NOTIFICATION_TYPE,
				"SLEE Spec 1.0, #13.4. SBBs use the Trace Facility to generate trace messages intended for "
						+ "consumption by external management clients, such as a network management console or a management policy engine.") };
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.TraceMBean#getTraceLevel(javax.slee.management.NotificationSource, java.lang.String)
	 */
	public TraceLevel getTraceLevel(NotificationSource src, String tracerName) throws NullPointerException, InvalidArgumentException, UnrecognizedNotificationSourceException, ManagementException {
		if(src == null)
		{
			throw new NullPointerException("NotificationSource must not be null!");
		}

		if(!this.isNotificationSourceDefined(src))
		{
			throw new UnrecognizedNotificationSourceException("Notification source not recognized: "+src);
		}
		TracerImpl.checkTracerName(tracerName, src);

		if(!this.isTracerDefined(src,tracerName))
		{
			//FIXME: what is valid tracer name? JDOC contradicts that not existing tracer name is invalid
			this.createTracer(src,tracerName,false);
		}

		TracerStorage ts = this.tracerStorage.get(src);
		if (ts == null) {
			throw new ManagementException("NotificationSource has been uninstalled from SLEE. Can not create tracer.");
		}
		try {
			return ts.getTracerLevel(tracerName);
		} catch (Exception e) {
			throw new ManagementException("Failed to get trace level due to: ", e);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.TraceMBean#getTracersSet(javax.slee.management.NotificationSource)
	 */
	public String[] getTracersSet(NotificationSource src) throws NullPointerException, UnrecognizedNotificationSourceException, ManagementException {
		if(src == null)
		{
			throw new NullPointerException("NotificationSource must nto be null!");
		}
		if(!this.isNotificationSourceDefined(src))
		{
			throw new UnrecognizedNotificationSourceException("Notification source not recognized: "+src);
		}

		TracerStorage ts = this.tracerStorage.get(src);
		if (ts == null) {
			throw new ManagementException("NotificationSource has been uninstalled from SLEE. Can not create tracer.");
		}
		return ts.getDefinedTracerNames();
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.TraceMBean#getTracersUsed(javax.slee.management.NotificationSource)
	 */
	public String[] getTracersUsed(NotificationSource src) throws NullPointerException, UnrecognizedNotificationSourceException, ManagementException {
		if(src == null)
		{
			throw new NullPointerException("NotificationSource must nto be null!");
		}
		if(!this.isNotificationSourceDefined(src))
		{
			throw new UnrecognizedNotificationSourceException("Notification source not recognized: "+src);
		}
		TracerStorage ts = this.tracerStorage.get(src);
		if (ts == null) {
			throw new ManagementException("NotificationSource has been uninstalled from SLEE. Can not create tracer.");
		}
		return ts.getRequestedTracerNames();
	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.TraceMBean#setTraceLevel(javax.slee.management.NotificationSource, java.lang.String, javax.slee.facilities.TraceLevel)
	 */
	public void setTraceLevel(NotificationSource src, final String tracerName, TraceLevel lvl) throws NullPointerException, UnrecognizedNotificationSourceException, InvalidArgumentException,
			ManagementException {
		if(src == null)
		{
			throw new NullPointerException("NotificationSource must nto be null!");
		}

		if(lvl == null)
		{
			throw new NullPointerException("TraceLevel must not be null!");
		}
		if
		(!this.isNotificationSourceDefined(src))
		{
			throw new UnrecognizedNotificationSourceException("Notification source not recognized: "+src);
		}
		TracerImpl.checkTracerName(tracerName, src);

		if(!this.isTracerDefined(src,tracerName))
		{
			//FIXME: what is valid tracer name? JDOC contradicts that not existing tracer name is invalid
			this.createTracer(src,tracerName,false);
		}

		final TracerStorage ts = this.tracerStorage.get(src);
		if (ts == null) {
			throw new ManagementException("NotificationSource has been uninstalled from SLEE. Can not create tracer.");
		}
		try {

			try {
				final SleeTransactionManager sleeTransactionManager = sleeContainer.getTransactionManager();
				if(sleeTransactionManager.getTransaction()!=null)
				{
					final TraceLevel _oldLevel=ts.getTracerLevel(tracerName);
					TransactionalAction action = new TransactionalAction() {
						TraceLevel oldLevel = _oldLevel;
						public void execute() {
							try {
								ts.setTracerLevel(oldLevel, tracerName);
							} catch (InvalidArgumentException e) {
								logger.error(e.getMessage(),e);
							}
						}
					};
					sleeTransactionManager.getTransactionContext().getAfterRollbackActions().add(action);
				}
			} catch (SystemException e) {

				e.printStackTrace();
			}

			ts.setTracerLevel(lvl, tracerName);

		} catch (Exception e) {
			throw new ManagementException("Failed to set trace level due to: ", e);
		}

	}

	/*
	 * (non-Javadoc)
	 * @see javax.slee.management.TraceMBean#unsetTraceLevel(javax.slee.management.NotificationSource, java.lang.String)
	 */
	public void unsetTraceLevel(NotificationSource src, final String tracerName) throws NullPointerException, UnrecognizedNotificationSourceException, InvalidArgumentException, ManagementException {
		if(src == null)
		{
			throw new NullPointerException("NotificationSource must nto be null!");
		}

		if(!this.isNotificationSourceDefined(src))
		{
			throw new UnrecognizedNotificationSourceException("Notification source not recognized: "+src);
		}
		TracerImpl.checkTracerName(tracerName, src);

		if(!this.isTracerDefined(src,tracerName))
		{
			//FIXME: what is valid tracer name? JDOC contradicts that not existing tracer name is invalid
			this.createTracer(src,tracerName,false);
		}

		final TracerStorage ts = this.tracerStorage.get(src);
		if (ts == null) {
			throw new ManagementException("NotificationSource has been uninstalled from SLEE. Can not create tracer.");
		}
		try {

			final SleeTransactionManager sleeTransactionManager = sleeContainer.getTransactionManager();
			try {
				if(sleeTransactionManager.getTransaction()!=null)
				{
					final TraceLevel _oldLevel=ts.getTracerLevel(tracerName);
					TransactionalAction action = new TransactionalAction() {
						TraceLevel oldLevel = _oldLevel;
						public void execute() {
							try {
								ts.setTracerLevel(oldLevel, tracerName);
							} catch (InvalidArgumentException e) {
								logger.error(e.getMessage(),e);
							}
						}
					};
					sleeTransactionManager.getTransactionContext().getAfterRollbackActions().add(action);
				}
			} catch (SystemException e) {

				e.printStackTrace();
			}

			ts.unsetTracerLevel(tracerName);
		} catch (Exception e) {
			throw new ManagementException("Failed to unset trace level due to: ", e);
		}

	}

	//Non MBEAN methods

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.TraceManagement#getTraceMBeanObjectName()
	 */
	public javax.management.ObjectName getTraceMBeanObjectName() { return getObjectName(); };

	// 1.1 TracerImpl are. We define internal private class to hide details :)

	private Map<NotificationSource, TracerStorage> tracerStorage = new ConcurrentHashMap<NotificationSource, TracerStorage>();

	/**
	 * This checks if tracer name is ok. It must not be null;
	 *
	 * @param split
	 * @throws IllegalArgumentException
	 */
	public static void checkTracerName(String tracerName, NotificationSource notificationSource) throws IllegalArgumentException {

		if (tracerName.compareTo("") == 0) {
			// This is root
			return;
		}

		// String[] splitName = tracerName.split("\\.");
		StringTokenizer stringTokenizer = new StringTokenizer(tracerName, ".", true);

		int fqdnPartIndex = 0;

		// if(splitName.length==0)
		// {
		// throw new IllegalArgumentException("Passed tracer:" + tracerName +
		// ", name for source: " + notificationSource + ", is illegal");
		// }

		String lastToken = null;

		while (stringTokenizer.hasMoreTokens()) {
			String token = stringTokenizer.nextToken();
			if (lastToken == null) {
				// this is start
				lastToken = token;
			}

			if (lastToken.compareTo(token) == 0 && token.compareTo(".") == 0) {
				throw new IllegalArgumentException("Passed tracer:" + tracerName + ", name for source: " + notificationSource + ", is illegal");
			}

			if (token.compareTo(".") != 0) {
				for (int charIndex = 0; charIndex < token.length(); charIndex++) {
					Character c = token.charAt(charIndex);
					if (Character.isLetter(c) || Character.isDigit(c)) {
						// Its ok?
					} else {
						throw new IllegalArgumentException("Passed tracer:" + tracerName + " Token[" + token + "], name for source: " + notificationSource
								+ ", is illegal, contains illegal character: " + charIndex);
					}
				}

				fqdnPartIndex++;
			}
			lastToken = token;

		}

		if (lastToken.compareTo(".") == 0) {
			throw new IllegalArgumentException("Passed tracer:" + tracerName + ", name for source: " + notificationSource + ", is illegal");
		}

	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.TraceManagement#registerNotificationSource(javax.slee.management.NotificationSource)
	 */
	public void registerNotificationSource(final NotificationSource src) {
		if (!this.tracerStorage.containsKey(src)) {
			TracerStorage ts = new TracerStorage(src, this);
			this.tracerStorage.put(src, ts);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.TraceManagement#deregisterNotificationSource(javax.slee.management.NotificationSource)
	 */
	public void deregisterNotificationSource(final NotificationSource src) {

		this.tracerStorage.remove(src);

	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.TraceManagement#isNotificationSourceDefined(javax.slee.management.NotificationSource)
	 */
	public boolean isNotificationSourceDefined(NotificationSource src) {
		return this.tracerStorage.containsKey(src);
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.jmx.TraceManagement#isTracerDefined(javax.slee.management.NotificationSource, java.lang.String)
	 */
	public boolean isTracerDefined(NotificationSource src, String tracerName) throws ManagementException {
		TracerStorage ts = this.tracerStorage.get(src);
		if (ts == null) {
			throw new ManagementException("NotificationSource has been uninstalled from SLEE. Can not create tracer.");
		}

		return ts.isTracerDefined(tracerName);
	}

	/*
	 * (non-Javadoc)
	 * @see org.mobicents.slee.container.management.TraceManagement#createTracer(javax.slee.management.NotificationSource, java.lang.String, boolean)
	 */
	public Tracer createTracer(NotificationSource src, String tracerName, boolean createdBySource) throws NullPointerException, InvalidArgumentException {

		TracerImpl.checkTracerName(tracerName, src);

		TracerStorage ts = this.tracerStorage.get(src);
		if (ts == null) {
			throw new IllegalStateException("NotificationSource has been uninstalled from SLEE. Can not create tracer.");
		}

		return ts.createTracer(tracerName, createdBySource);

	}

	@Override
	public void sleeInitialization() {
		Runnable r = new Runnable() {
			public void run() {
				for(TracerStorage ts : tracerStorage.values()) {
					ts.syncTracersWithLog4J();
				}
			}
		};
		scheduledFuture = sleeContainer.getNonClusteredScheduler().scheduleWithFixedDelay(r, LOG4J_LEVEL_SYNC_PERIOD,LOG4J_LEVEL_SYNC_PERIOD, TimeUnit.MINUTES);
	}

	@Override
	public void sleeStarting() {

	}

	@Override
	public void sleeRunning() {

	}

	@Override
	public void sleeStopping() {

	}

	@Override
	public void sleeStopped() {

	}

	@Override
	public void sleeShutdown() {
		if (!sleeContainer.getNonClusteredScheduler().isShutdown()) {
			scheduledFuture.cancel(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.profile;

import java.util.Collection;

import javax.slee.InvalidArgumentException;
import javax.slee.SLEEException;
import javax.slee.TransactionRequiredLocalException;
import javax.slee.profile.AttributeTypeMismatchException;
import javax.slee.profile.ProfileLocalObject;
import javax.slee.profile.UnrecognizedQueryNameException;

/**
 *
 * Start time:12:49:42 2009-03-20

 * Project: restcomm-jainslee-server-core

 * This class handles queries call to certain ProfileTable impl objects. It must
 * be called within transaction
 *
 * @author  Bartosz Baranowski
 * @author  Alexandre Mendonca
 */
public class ProfileQueryHandler {

	/**
	 * Method that does lookup and creates PLOs
	 *
	 * @param profileTable
	 * @param queryName
	 * @param arguments
	 * @return
	 * @throws InvalidArgumentException
	 * @throws AttributeTypeMismatchException
	 * @throws UnrecognizedQueryNameException
	 * @throws SLEEException
	 * @throws NullPointerException
	 */
	public static Collection<ProfileLocalObject> handle(
			ProfileTableImpl profileTable, String queryName, Object[] arguments)
			throws NullPointerException, TransactionRequiredLocalException, SLEEException,
			UnrecognizedQueryNameException, AttributeTypeMismatchException,
			InvalidArgumentException {
		return profileTable.getProfilesByStaticQuery(queryName, arguments);
	}

}