blob: 2cf788cfb98e6feebe062955da48af9c06741c78 [file] [log] [blame]
/* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Author: Cezar Andrei ( cezar.andrei at bea.com )
* Date: Mar 25, 2004
*/
package org.apache.xmlbeans.impl.config;
import org.apache.xml.xmlbeans.x2004.x02.xbean.config.Extensionconfig;
import org.apache.xmlbeans.XmlObject;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class InterfaceExtension
{
private NameSet _xbeanSet;
private Class _interface;
private Class _delegateToClass;
private String _delegateToClassName;
private Method[] _interfaceMethods;
private Method[] _delegateToMethods;
static InterfaceExtension newInstance(NameSet xbeanSet, Extensionconfig.Interface intfXO)
{
InterfaceExtension result = new InterfaceExtension();
result._xbeanSet = xbeanSet;
result._interface = validateInterface(intfXO.getName(), intfXO);
if (result._interface == null)
{
SchemaConfig.error("Interface '" + intfXO.getStaticHandler() + "' not found.", intfXO);
return null;
}
result._delegateToClassName = intfXO.getStaticHandler();
result._delegateToClass = validateClass(result._delegateToClassName, intfXO);
if ( result._delegateToClass==null ) // no HandlerClass
{
SchemaConfig.warning("Handler class '" + intfXO.getStaticHandler() + "' not found on classpath, skip validation.", intfXO);
return result;
}
if (!result.validateMethods(intfXO))
return null;
return result;
}
private static Class validateInterface(String intfStr, XmlObject loc)
{
return validateJava(intfStr, true, loc);
}
static Class validateClass(String clsStr, XmlObject loc)
{
return validateJava(clsStr, false, loc);
}
static Class validateJava(String clsStr, boolean isInterface, XmlObject loc)
{
final String ent = isInterface ? "Interface" : "Class";
try
{
Class cls = Class.forName(clsStr);
if ( (isInterface && !cls.isInterface()) ||
(!isInterface && cls.isInterface()))
{
SchemaConfig.error("'" + clsStr + "' must be " +
(isInterface ? "an interface" : "a class") + ".", loc);
}
if (!Modifier.isPublic(cls.getModifiers()))
{
SchemaConfig.error(ent + " '" + clsStr + "' is not public.", loc);
}
return cls;
}
catch (ClassNotFoundException e)
{
SchemaConfig.error(ent + " '" + clsStr + "' not found.", loc);
return null;
}
}
private boolean validateMethods(XmlObject loc)
{
assert _delegateToClass != null : "Delegate to class handler expected.";
boolean valid = true;
_interfaceMethods = _interface.getMethods();
_delegateToMethods = new Method[_interfaceMethods.length];
for (int i = 0; i < _interfaceMethods.length; i++)
{
valid &= validateMethod(i, _interfaceMethods[i], loc);
}
return valid;
}
private boolean validateMethod(int index, Method method, XmlObject loc)
{
String methodName = method.getName();
Class[] paramTypes = method.getParameterTypes();
Class returnType = method.getReturnType();
Class[] delegateParams = new Class[paramTypes.length+1];
delegateParams[0] = XmlObject.class;
for (int i = 1; i < delegateParams.length; i++)
{
delegateParams[i] = paramTypes[i-1];
}
Method handlerMethod = null;
try
{
handlerMethod = _delegateToClass.getMethod(methodName, delegateParams);
// check for throws exceptions
Class[] intfExceptions = method.getExceptionTypes();
Class[] delegateExceptions = handlerMethod.getExceptionTypes();
if ( delegateExceptions.length!=intfExceptions.length )
{
SchemaConfig.error("Handler method '" + _delegateToClass.getName() + "." + methodName + "(" + listTypes(delegateParams) +
")' must declare the same exceptions as the interface method '" + _interface.getName() + "." + methodName + "(" + listTypes(paramTypes), loc);
return false;
}
for (int i = 0; i < delegateExceptions.length; i++)
{
if ( delegateExceptions[i]!=intfExceptions[i] )
{
SchemaConfig.error("Handler method '" + _delegateToClass.getName() + "." + methodName + "(" + listTypes(delegateParams) +
")' must declare the same exceptions as the interface method '" + _interface.getName() + "." + methodName + "(" + listTypes(paramTypes), loc);
return false;
}
}
}
catch (NoSuchMethodException e)
{
SchemaConfig.error("Handler class '" + _delegateToClass.getName() + "' does not contain method " + methodName + "(" + listTypes(delegateParams) + ")", loc);
return false;
}
catch (SecurityException e)
{
SchemaConfig.error("Security violation for class '" + _interface.getName() + "' accesing method " + methodName + "(" + listTypes(delegateParams) + ")", loc);
return false;
}
if (!Modifier.isPublic(handlerMethod.getModifiers()) || !Modifier.isStatic(handlerMethod.getModifiers()))
{
SchemaConfig.error("Method '" + _delegateToClass.getName() + "." + methodName + "(" + listTypes(delegateParams) + ")' must be declared public and static.", loc);
return false;
}
if (!returnType.equals(handlerMethod.getReturnType()))
{
SchemaConfig.error("Return type for method '" + handlerMethod.getReturnType() + " " + _delegateToClass.getName() +
"." + methodName + "(" + listTypes(delegateParams) + ")' does not match the return type of the interface method :'" + returnType + "'.", loc);
return false;
}
_delegateToMethods[index] = method;
return true;
}
private static String listTypes(Class[] types)
{
StringBuffer result = new StringBuffer();
for (int i = 0; i < types.length; i++)
{
Class type = types[i];
if (i>0)
result.append(", ");
result.append(emitType(type));
}
return result.toString();
}
public static String emitType(Class cls)
{
if (cls.isArray())
return emitType(cls.getComponentType()) + "[]";
else
return cls.getName().replace('$', '.');
}
/* public getters */
public boolean contains(String fullJavaName)
{
return _xbeanSet.contains(fullJavaName);
}
public String getInterfaceName()
{
return _interface.getName();
}
public String getInterfaceNameForJavaSource()
{
return emitType(_interface);
}
// used only for validation
public String getHandlerNameForJavaSource()
{
if (_delegateToClass==null)
return null;
return emitType(_delegateToClass);
}
public int getInterfaceMethodCount()
{
return _interfaceMethods.length;
}
public String getInterfaceMethodName(int methodIndex)
{
return _interfaceMethods[methodIndex].getName();
}
public Method getInterfaceMethod(int methodIndex)
{
return _interfaceMethods[methodIndex];
}
public String getInterfaceMethodDecl(int methodIndex)
{
StringBuffer sb = new StringBuffer();
Method m = _interfaceMethods[methodIndex];
Class[] paramTypes = m.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++)
{
Class paramType = paramTypes[i];
sb.append( i==0 ? "" : ", " );
sb.append( emitType(paramType) + " p" + i);
}
StringBuffer exceptions = new StringBuffer();
Class[] excClasses = m.getExceptionTypes();
for (int i=0; i<excClasses.length; i++)
exceptions.append((i==0 ? " throws " : ", ") + emitType(excClasses[i]));
return "public " + emitType(m.getReturnType()) + " " + m.getName() + "(" + sb.toString() + ")" + exceptions.toString();
}
public String getInterfaceMethodImpl(int methodIndex)
{
// use the methods from the interface for gen the call to the handler
StringBuffer sb = new StringBuffer();
if (!void.class.equals(_interfaceMethods[methodIndex].getReturnType()))
sb.append("return ");
sb.append(_delegateToClassName + "." + _delegateToMethods[methodIndex].getName() + "(this");
int paramCount = _interfaceMethods[methodIndex].getParameterTypes().length;
for (int i=0; i<paramCount; i++)
{
sb.append(", p" + i);
}
sb.append(");");
return sb.toString();
}
}