Package com.dbxml.labrador.objects

Source Code of com.dbxml.labrador.objects.ObjectDiscovery$MethodInfo

package com.dbxml.labrador.objects;

/*
* The dbXML Labrador Software License, Version 1.0
*
*
* Copyright (c) 2003 The dbXML Group, L.L.C.  All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*       "This product includes software developed by The
*        dbXML Group, L.L.C. (http://www.dbxml.com/)."
*    Alternately, this acknowledgment may appear in the software
*    itself, if and wherever such third-party acknowledgments normally
*    appear.
*
* 4. The names "Labrador" and "dbXML Group" must not be used to
*    endorse or promote products derived from this software without
*    prior written permission. For written permission, please contact
*    info@dbxml.com
*
* 5. Products derived from this software may not be called "Labrador",
*    nor may "Labrador" appear in their name, without prior written
*    permission of The dbXML Group, L.L.C..
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE DBXML GROUP, L.L.C. OR ITS
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* $Id: ObjectDiscovery.java,v 1.7 2003/10/29 20:11:16 bradford Exp $
*/

import com.dbxml.labrador.Discovery;
import com.dbxml.labrador.types.ArrayConversions;
import com.dbxml.labrador.types.TypeConversions;
import com.dbxml.labrador.types.Types;
import com.dbxml.labrador.types.Variant;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* ObjectDiscovery is an Object reflection and method invocation utility for
* the standard Labrador object registration system.
*/

public final class ObjectDiscovery implements Discovery {
   private static final String[] EmptyStrings = new String[0];
   private static final Set ObjectMethods = new HashSet();
   static {
      Class c = Object.class;
      Method[] m = c.getMethods();
      for ( int i = 0; i < m.length; i++ ) {
         String name = m[i].getName();
         if ( !ObjectMethods.contains(name) )
            ObjectMethods.add(name);
      }
   }

   private static final String PARAMS_PREFIX = "PARAMS_";
   private static final String IGNORE_METHODS = "IGNORE_METHODS";
   private static final String INCLUDE_METHODS = "INCLUDE_METHODS";

   private Class cl;
   private Map methods = new HashMap(); // MethodInfo

   public ObjectDiscovery(Class cl) throws Exception {
      this.cl = cl;
      reflect();
   }

   /**
    * reflect performs an initial reflection against the Class that this
    * Discovery will support.  This method will not be capable of reflecting
    * parameter names because the Java compiler throws them away.  In order to
    * create parameter name mappings, you must call addMethod.
    */
   public void reflect() throws Exception {
      // Check For Ignored Methods
      Set ignoreMethods = new HashSet();
      Object ignoreObj = getStaticField(IGNORE_METHODS);
      if ( ignoreObj instanceof String[] ) {
         String[] ignore = (String[])ignoreObj;
         for ( int i = 0; i < ignore.length; i++ ) {
            String name = ignore[i];
            if ( !ignoreMethods.contains(name) )
               ignoreMethods.add(name);
         }
      }

      // Check For Included Methods
      Set includeMethods = new HashSet();
      Object includeObj = getStaticField(INCLUDE_METHODS);
      if ( includeObj instanceof String[] ) {
         String[] include = (String[])includeObj;
         for ( int i = 0; i < include.length; i++ ) {
            String name = include[i];
            if ( !includeMethods.contains(name) ) {
               includeMethods.add(name);
               ignoreMethods.remove(name); // No Point Being There
            }
         }
      }
     
      Method[] m = cl.getDeclaredMethods();
      Set defined = new HashSet();
      for ( int i = 0; i < m.length; i++ ) {
         String name = m[i].getName();

         // Check Modifiers
         int mod = m[i].getModifiers();
         if ( !Modifier.isPublic(mod) || Modifier.isStatic(mod) )
            continue;

         // Check Valid Return Types
         Class ret = m[i].getReturnType();
         int retType = Types.typeOf(ret);
         if ( retType == Types.UNKNOWN )
            continue;

         // If Not Included In INCLUDE_METHODS, Do A Special Check
         if ( !includeMethods.contains(name) ) {
            // Ignore Special Java Methods
            if ( ObjectMethods.contains(name) )
               continue;
  
            // Ignore Methods Specified By IGNORE_METHODS
            if ( ignoreMethods.contains(name) )
               continue;
         }
        
         if ( defined.contains(name) )
            throw new Exception("Duplicate Exposed Method '" + name + "'");

         // Check Valid Parameter Types
         Class[] p = m[i].getParameterTypes();
         ParamInfo[] params = new ParamInfo[p.length];

         String[] names = getFieldVals(cl, p.length, PARAMS_PREFIX + name);

         boolean good = true;
         for ( int j = 0; j < p.length && good; j++ ) {
            String pname;
        if ( names != null )
          pname = names[j];
        else
          pname = "arg" + j;

            int parmType = Types.typeOf(p[j]);
            good = parmType != Types.UNKNOWN;

            if ( p[j].isArray() )
               params[j] = new ParamInfo(pname, parmType, p[j].getComponentType(), true);
            else
               params[j] = new ParamInfo(pname, parmType, p[j], false);
         }
         if ( !good )
            continue;

         if ( ret.isArray() )
            methods.put(name, new MethodInfo(name, retType, ret.getComponentType(), true, m[i], params));
         else
            methods.put(name, new MethodInfo(name, retType, ret, false, m[i], params));

         defined.add(name);
      }
   }

   public Object getStaticField(String name) {
      try {
         Field f = cl.getDeclaredField(name);
         int mod = f.getModifiers();
         if ( Modifier.isStatic(mod) && Modifier.isPublic(mod) )
            return f.get(null);
      }
      catch ( Exception e ) {
      }
      return null;
   }

   private String[] getFieldVals(Class c, int len, String name) {
      try {
         Field f = c.getDeclaredField(name);
         int mod = f.getModifiers();
         if ( Modifier.isStatic(mod) && Modifier.isFinal(mod)
            && f.getType().isArray() && f.getType().getComponentType() == String.class ) {
            String[] res = (String[])f.get(null);
            if ( res.length == len )
               return res;
         }
      }
      catch ( Exception e ) {
      }
      return null;
   }

   public String[] listMethods() {
      return (String[])methods.keySet().toArray(EmptyStrings);
   }

   public int getParamCount(String method) {
      MethodInfo info = (MethodInfo)methods.get(method);
      if ( info != null )
         return info.params.length;
      else
         return 0;
   }

   public String[] listParams(String name) {
      MethodInfo info = (MethodInfo)methods.get(name);
      if ( info != null )
         return info.paramNames;
      else
         return null;
   }

   public int getReturnType(String method) {
      MethodInfo info = (MethodInfo)methods.get(method);
      if ( info != null )
         return info.type;
      else
         return Types.UNKNOWN;
   }

   public boolean isReturnArray(String method) {
      MethodInfo info = (MethodInfo)methods.get(method);
      if ( info != null )
         return info.array;
      else
         return false;
   }

   public int getParamType(String method, int index) {
      MethodInfo info = (MethodInfo)methods.get(method);
      if ( info != null && index < info.params.length )
         return info.params[index].type;
      else
         return Types.UNKNOWN;
   }

   public boolean isParamArray(String method, int index) {
      MethodInfo info = (MethodInfo)methods.get(method);
      if ( info != null && index < info.params.length )
         return info.params[index].array;
      else
         return false;
   }

   // Invocation Methods

   /**
    * invoke invokes the named method against the specified
    * Object, passing to the method the set of specified parameters.
    *
    * @param obj The target object
    * @param name The method name
    * @param params The parameter values
    * @return The result of the method
    * @throws Throwable if an invocation error occurs
    */
   public Object invoke(Object obj, String name, Object[] params) throws Throwable {
      Variant[] v = new Variant[params.length];
      for ( int i = 0; i < v.length; i++ )
         v[i] = new Variant(params[i]);
      return invoke(obj, name, v);
   }

   /**
    * invoke invokes the named method against the specified Object,
    * passing to the method the set of specified parameters.  This method will
    * convert the Variant array in args to the appropriate Object types before
    * invoking the method.
    *
    * @param obj The target object
    * @param name The method name
    * @param args The parameter values
    * @return The result of the method
    * @throws Throwable if an invocation error occurs
    */
   private Object invoke(Object obj, String name, Variant[] args) throws Throwable {
      MethodInfo info = (MethodInfo)methods.get(name);
      if ( info != null ) {
         Object[] params = new Object[info.params.length];
         for ( int i = 0; i < info.params.length; i++ ) {
            ParamInfo p = info.params[i];
            if ( !p.array )
               params[i] = TypeConversions.toTypedValue(p.type, args[i], p.classType);
            else {
               if ( args[i].getType() == Types.LIST ) {
                  List l = args[i].getList();
                  params[i] = ArrayConversions.toTypedArray(p.type, l, p.classType);
               }
               else if ( p.type == Types.BYTE && args[i].isArray() )
                  params[i] = (byte[])args[i].getObject();
               else if ( args[i].getType() != p.type ) {
                  // Try to convert the list
                  List l = ArrayConversions.toList(args[i]);
                  params[i] = ArrayConversions.toTypedArray(p.type, l, p.classType);
               }
               else
                  params[i] = args[i];
            }
         }
         try {
            return info.method.invoke(obj, params);
         }
         catch ( InvocationTargetException e ) {
            throw e.getTargetException();
         }
      }
      else
         throw new Exception("Method '" + name + "' Not Found");
   }


   /**
    * ParamInfo encapsulates parameter type and name information
    */

   private class ParamInfo {
      public String name;
      public int type;
      public Class classType;
      public boolean array;

      public ParamInfo(String name, int type, Class classType, boolean array) {
         this.name = name;
         this.type = type;
         this.classType = classType;
         this.array = array;
      }
   }


   /**
    * MethodInfo encapsulates Method result, name, and parameter information
    */

   private class MethodInfo extends ParamInfo {
      public Method method;
      public ParamInfo[] params;
      public String[] paramNames;

      public MethodInfo(String name, int type, Class component, boolean array, Method method, ParamInfo[] params) {
         super(name, type, component, array);
         this.method = method;
         this.params = params;
         calcParamNames();
      }

      public void calcParamNames() {
         paramNames = new String[params.length];
         for ( int i = 0; i < paramNames.length; i++ )
            paramNames[i] = params[i].name;
      }
   }
}



TOP

Related Classes of com.dbxml.labrador.objects.ObjectDiscovery$MethodInfo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.