Home » xmlbeans-2.5.0-src » org.apache.xmlbeans.impl » config » [javadoc | source]

    1   /*   Copyright 2004 The Apache Software Foundation
    2    *
    3    *   Licensed under the Apache License, Version 2.0 (the "License");
    4    *   you may not use this file except in compliance with the License.
    5    *   You may obtain a copy of the License at
    6    *
    7    *       http://www.apache.org/licenses/LICENSE-2.0
    8    *
    9    *   Unless required by applicable law or agreed to in writing, software
   10    *   distributed under the License is distributed on an "AS IS" BASIS,
   11    *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   12    *   See the License for the specific language governing permissions and
   13    *  limitations under the License.
   14    */
   15   
   16   package org.apache.xmlbeans.impl.config;
   17   
   18   import org.apache.xmlbeans.impl.xb.xmlconfig.Extensionconfig;
   19   import org.apache.xmlbeans.InterfaceExtension;
   20   import org.apache.xmlbeans.XmlObject;
   21   import org.apache.xmlbeans.impl.jam.JMethod;
   22   import org.apache.xmlbeans.impl.jam.JClass;
   23   import org.apache.xmlbeans.impl.jam.JParameter;
   24   import org.apache.xmlbeans.impl.jam.JamClassLoader;
   25   
   26   public class InterfaceExtensionImpl implements InterfaceExtension
   27   {
   28       private NameSet _xbeanSet;
   29       private String _interfaceClassName;
   30       private String _delegateToClassName;
   31       private MethodSignatureImpl[] _methods;
   32   
   33       static InterfaceExtensionImpl newInstance(JamClassLoader loader, NameSet xbeanSet, Extensionconfig.Interface intfXO)
   34       {
   35           InterfaceExtensionImpl result = new InterfaceExtensionImpl();
   36   
   37           result._xbeanSet = xbeanSet;
   38           JClass interfaceJClass = validateInterface(loader, intfXO.getName(), intfXO);
   39   
   40   
   41           if (interfaceJClass == null)
   42           {
   43               BindingConfigImpl.error("Interface '" + intfXO.getStaticHandler() + "' not found.", intfXO);
   44               return null;
   45           }
   46   
   47           result._interfaceClassName = interfaceJClass.getQualifiedName();
   48   
   49           result._delegateToClassName = intfXO.getStaticHandler();
   50           JClass delegateJClass = validateClass(loader, result._delegateToClassName, intfXO);
   51   
   52           if (delegateJClass == null) // no HandlerClass
   53           {
   54               BindingConfigImpl.warning("Handler class '" + intfXO.getStaticHandler() + "' not found on classpath, skip validation.", intfXO);
   55               return result;
   56           }
   57   
   58           if (!result.validateMethods(interfaceJClass, delegateJClass, intfXO))
   59               return null;
   60   
   61           return result;
   62       }
   63   
   64       private static JClass validateInterface(JamClassLoader loader, String intfStr, XmlObject loc)
   65       {
   66           return validateJava(loader, intfStr, true, loc);
   67       }
   68   
   69       static JClass validateClass(JamClassLoader loader, String clsStr, XmlObject loc)
   70       {
   71           return validateJava(loader, clsStr, false, loc);
   72       }
   73   
   74       static JClass validateJava(JamClassLoader loader, String clsStr, boolean isInterface, XmlObject loc)
   75       {
   76           if (loader==null)
   77               return null;
   78   
   79           final String ent = isInterface ? "Interface" : "Class";
   80           JClass cls = loader.loadClass(clsStr);
   81   
   82           if (cls==null || cls.isUnresolvedType())
   83           {
   84               BindingConfigImpl.error(ent + " '" + clsStr + "' not found.", loc);
   85               return null;
   86           }
   87   
   88           if ( (isInterface && !cls.isInterface()) ||
   89                   (!isInterface && cls.isInterface()))
   90           {
   91               BindingConfigImpl.error("'" + clsStr + "' must be " +
   92                   (isInterface ? "an interface" : "a class") + ".", loc);
   93           }
   94   
   95           if (!cls.isPublic())
   96           {
   97               BindingConfigImpl.error(ent + " '" + clsStr + "' is not public.", loc);
   98           }
   99   
  100           return cls;
  101       }
  102   
  103       private boolean validateMethods(JClass interfaceJClass, JClass delegateJClass, XmlObject loc)
  104       {
  105           //assert _delegateToClass != null : "Delegate to class handler expected.";
  106           boolean valid = true;
  107   
  108           JMethod[] interfaceMethods = interfaceJClass.getMethods();
  109           _methods = new MethodSignatureImpl[interfaceMethods.length];
  110   
  111           for (int i = 0; i < interfaceMethods.length; i++)
  112           {
  113               JMethod method = validateMethod(interfaceJClass, delegateJClass, interfaceMethods[i], loc);
  114               if (method != null)
  115                   _methods[i] = new MethodSignatureImpl(getStaticHandler(), method);
  116               else
  117                   valid = false;
  118           }
  119   
  120   
  121           return valid;
  122       }
  123   
  124       private JMethod validateMethod(JClass interfaceJClass, JClass delegateJClass, JMethod method, XmlObject loc)
  125       {
  126           String methodName = method.getSimpleName();
  127           JParameter[] params = method.getParameters();
  128           JClass returnType = method.getReturnType();
  129   
  130           JClass[] delegateParams = new JClass[params.length+1];
  131           delegateParams[0] = returnType.forName("org.apache.xmlbeans.XmlObject");
  132           for (int i = 1; i < delegateParams.length; i++)
  133           {
  134               delegateParams[i] = params[i-1].getType();
  135           }
  136   
  137           JMethod handlerMethod = null;
  138           handlerMethod = getMethod(delegateJClass, methodName, delegateParams);
  139           if (handlerMethod==null)
  140           {
  141               BindingConfigImpl.error("Handler class '" + delegateJClass.getQualifiedName() + "' does not contain method " + methodName + "(" + listTypes(delegateParams) + ")", loc);
  142               return null;
  143           }
  144   
  145           // check for throws exceptions
  146           JClass[] intfExceptions = method.getExceptionTypes();
  147           JClass[] delegateExceptions = handlerMethod.getExceptionTypes();
  148           if ( delegateExceptions.length!=intfExceptions.length )
  149           {
  150               BindingConfigImpl.error("Handler method '" + delegateJClass.getQualifiedName() + "." + methodName + "(" + listTypes(delegateParams) +
  151                   ")' must declare the same exceptions as the interface method '" + interfaceJClass.getQualifiedName() + "." + methodName + "(" + listTypes(params), loc);
  152               return null;
  153           }
  154   
  155           for (int i = 0; i < delegateExceptions.length; i++)
  156           {
  157               if ( delegateExceptions[i]!=intfExceptions[i] )
  158               {
  159                   BindingConfigImpl.error("Handler method '" + delegateJClass.getQualifiedName() + "." + methodName + "(" + listTypes(delegateParams) +
  160                       ")' must declare the same exceptions as the interface method '" + interfaceJClass.getQualifiedName() + "." + methodName + "(" + listTypes(params), loc);
  161                   return null;
  162               }
  163           }
  164   
  165           if (!handlerMethod.isPublic() || !handlerMethod.isStatic())
  166           {
  167               BindingConfigImpl.error("Method '" + delegateJClass.getQualifiedName() + "." + methodName + "(" + listTypes(delegateParams) + ")' must be declared public and static.", loc);
  168               return null;
  169           }
  170   
  171           if (!returnType.equals(handlerMethod.getReturnType()))
  172           {
  173               BindingConfigImpl.error("Return type for method '" + handlerMethod.getReturnType() + " " + delegateJClass.getQualifiedName() +
  174                       "." + methodName + "(" + listTypes(delegateParams) + ")' does not match the return type of the interface method :'" + returnType + "'.", loc);
  175               return null;
  176           }
  177   
  178           return method;
  179       }
  180   
  181       static JMethod getMethod(JClass cls, String name, JClass[] paramTypes)
  182       {
  183           JMethod[] methods = cls.getMethods();
  184           for (int i = 0; i < methods.length; i++)
  185           {
  186               JMethod method = methods[i];
  187               if (!name.equals(method.getSimpleName()))
  188                   continue;
  189   
  190               JParameter[] mParams = method.getParameters();
  191   
  192               // can have methods with same name but different # of params
  193               if (mParams.length != paramTypes.length)
  194                   continue;
  195   
  196               for (int j = 0; j < mParams.length; j++)
  197               {
  198                   JParameter mParam = mParams[j];
  199                   if (!mParam.getType().equals(paramTypes[j]))
  200                       continue;
  201               }
  202   
  203               return method;
  204           }
  205           return null;
  206       }
  207   
  208       private static String listTypes(JClass[] types)
  209       {
  210           StringBuffer result = new StringBuffer();
  211           for (int i = 0; i < types.length; i++)
  212           {
  213               JClass type = types[i];
  214               if (i>0)
  215                   result.append(", ");
  216               result.append(emitType(type));
  217           }
  218           return result.toString();
  219       }
  220   
  221       private static String listTypes(JParameter[] params)
  222       {
  223           StringBuffer result = new StringBuffer();
  224           for (int i = 0; i < params.length; i++)
  225           {
  226               JClass type = params[i].getType();
  227               if (i>0)
  228                   result.append(", ");
  229               result.append(emitType(type));
  230           }
  231           return result.toString();
  232       }
  233   
  234       public static String emitType(JClass cls)
  235       {
  236           if (cls.isArrayType())
  237               return emitType(cls.getArrayComponentType()) + "[]";
  238           else
  239               return cls.getQualifiedName().replace('$', '.');
  240       }
  241   
  242       /* public getters */
  243       public boolean contains(String fullJavaName)
  244       {
  245           return _xbeanSet.contains(fullJavaName);
  246       }
  247   
  248       public String getStaticHandler()
  249       {
  250           return _delegateToClassName;
  251       }
  252   
  253       public String getInterface()
  254       {
  255           return _interfaceClassName;
  256       }
  257   
  258       public InterfaceExtension.MethodSignature[] getMethods()
  259       {
  260           return _methods;
  261       }
  262   
  263       public String toString()
  264       {
  265           StringBuffer buf = new StringBuffer();
  266           buf.append("  static handler: ").append(_delegateToClassName).append("\n");
  267           buf.append("  interface: ").append(_interfaceClassName).append("\n");
  268           buf.append("  name set: ").append(_xbeanSet).append("\n");
  269   
  270           for (int i = 0; i < _methods.length; i++)
  271               buf.append("  method[").append(i).append("]=").append(_methods[i]).append("\n");
  272   
  273           return buf.toString();
  274       }
  275   
  276       // this is used only for detecting method colisions of extending interfaces
  277       static class MethodSignatureImpl implements InterfaceExtension.MethodSignature
  278       {
  279           private String _intfName;  
  280           private final int NOTINITIALIZED = -1;
  281           private int _hashCode = NOTINITIALIZED;
  282           private String _signature;
  283   
  284           private String _name;
  285           private String _return;
  286           private String[] _params;
  287           private String[] _exceptions;
  288   
  289           MethodSignatureImpl(String intfName, JMethod method)
  290           {
  291               if (intfName==null || method==null)
  292                   throw new IllegalArgumentException("Interface: " + intfName + " method: " + method);
  293   
  294               _intfName = intfName;
  295               _hashCode = NOTINITIALIZED;
  296               _signature = null;
  297   
  298               _name = method.getSimpleName();
  299               _return = method.getReturnType().getQualifiedName().replace('$', '.');
  300   
  301               JParameter[] paramTypes = method.getParameters();
  302               _params = new String[paramTypes.length];
  303               for (int i = 0; i < paramTypes.length; i++)
  304                   _params[i] = paramTypes[i].getType().getQualifiedName().replace('$', '.');;
  305   
  306               JClass[] exceptionTypes = method.getExceptionTypes();
  307               _exceptions = new String[exceptionTypes.length];
  308               for (int i = 0; i < exceptionTypes.length; i++)
  309                   _exceptions[i] = exceptionTypes[i].getQualifiedName().replace('$', '.');
  310           }
  311   
  312           String getInterfaceName()
  313           {
  314               return _intfName;
  315           }
  316   
  317           public String getName()
  318           {
  319               return _name;
  320           }
  321   
  322           public String getReturnType()
  323           {
  324               return _return;
  325           }
  326   
  327           public String[] getParameterTypes()
  328           {
  329               return _params;
  330           }
  331   
  332           public String[] getExceptionTypes()
  333           {
  334               return _exceptions;
  335           }
  336   
  337           public boolean equals(Object o)
  338           {
  339               if ( !(o instanceof MethodSignatureImpl))
  340                   return false;
  341   
  342               MethodSignatureImpl ms = (MethodSignatureImpl)o;
  343   
  344               if (!ms.getName().equals(getName()) )
  345                   return false;
  346   
  347               String[] params = getParameterTypes();
  348               String[] msParams = ms.getParameterTypes();
  349   
  350               if (msParams.length != params.length )
  351                   return false;
  352   
  353               for (int i = 0; i < params.length; i++)
  354               {
  355                   if (!msParams[i].equals(params[i]))
  356                       return false;
  357               }
  358   
  359               if (!_intfName.equals(ms._intfName))
  360                   return false;
  361               
  362               return true;
  363           }
  364   
  365           public int hashCode()
  366           {
  367               if (_hashCode!=NOTINITIALIZED)
  368                   return _hashCode;
  369   
  370               int hash = getName().hashCode();
  371   
  372               String[] params = getParameterTypes();
  373   
  374               for (int i = 0; i < params.length; i++)
  375               {
  376                   hash *= 19;
  377                   hash += params[i].hashCode();
  378               }
  379   
  380               hash += 21 * _intfName.hashCode();
  381   
  382               _hashCode = hash;
  383               return _hashCode;
  384           }
  385   
  386           String getSignature()
  387           {
  388               if (_signature!=null)
  389                   return _signature;
  390   
  391               StringBuffer sb = new StringBuffer(60);
  392               sb.append(_name).append("(");
  393               for (int i = 0; i < _params.length; i++)
  394                   sb.append((i == 0 ? "" : " ,")).append(_params[i]);
  395               sb.append(")");
  396   
  397               _signature = sb.toString();
  398   
  399               return _signature;
  400           }
  401   
  402           public String toString()
  403           {
  404               StringBuffer buf = new StringBuffer();
  405   
  406               buf.append(getReturnType()).append(" ").append(getSignature());
  407   
  408               return buf.toString();
  409           }
  410       }
  411   }

Home » xmlbeans-2.5.0-src » org.apache.xmlbeans.impl » config » [javadoc | source]