320073 Reconcile jetty-8 and jetty-7 webapp configuration mechanisms

git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@2145 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
Jan Bartel 2010-07-16 07:15:13 +00:00
parent 8210d068c4
commit 314f94decc
60 changed files with 6947 additions and 3076 deletions

View File

@ -17,30 +17,36 @@ import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.Descriptor;
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
import org.eclipse.jetty.webapp.FragmentDescriptor;
import org.eclipse.jetty.webapp.MetaData;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.eclipse.jetty.webapp.WebXmlProcessor;
import org.eclipse.jetty.webapp.WebXmlProcessor.Descriptor;
import org.eclipse.jetty.webapp.Descriptor.MetaDataComplete;
public abstract class AbstractConfiguration implements Configuration
{
public static final String CONTAINER_JAR_RESOURCES = WebInfConfiguration.CONTAINER_JAR_RESOURCES;
public static final String WEB_INF_JAR_RESOURCES = WebInfConfiguration.WEB_INF_JAR_RESOURCES;
public static final String WEBXML_VERSION = WebXmlProcessor.WEBXML_VERSION;
public static final String METADATA_COMPLETE = WebXmlProcessor.METADATA_COMPLETE;
public static final String WEBXML_CLASSNAMES = WebXmlProcessor.WEBXML_CLASSNAMES;
public static final String WEB_INF_ORDERED_JAR_RESOURCES = WebInfConfiguration.WEB_INF_ORDERED_JAR_RESOURCES;
public static final String METADATA_COMPLETE = MetaData.METADATA_COMPLETE;
public static final String WEBXML_CLASSNAMES = MetaData.WEBXML_CLASSNAMES;
public static final String DISCOVERED_ANNOTATIONS = "org.eclipse.jetty.discoveredAnnotations";
public void parseContainerPath (final WebAppContext context, final AnnotationParser parser)
throws Exception
{
//if no pattern for the container path is defined, then by default scan NOTHING
Log.debug("Scanning container jars");
List<DiscoveredAnnotation> discoveredAnnotations = new ArrayList<DiscoveredAnnotation>();
context.setAttribute(DISCOVERED_ANNOTATIONS, discoveredAnnotations);
//Convert from Resource to URI
ArrayList<URI> containerUris = new ArrayList<URI>();
List<Resource> jarResources = (List<Resource>)context.getAttribute(CONTAINER_JAR_RESOURCES);
@ -68,60 +74,71 @@ public abstract class AbstractConfiguration implements Configuration
return false;
}
});
MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA);
if (metaData == null)
throw new IllegalStateException ("No metadata");
metaData.addDiscoveredAnnotations((List<DiscoveredAnnotation>)context.getAttribute(DISCOVERED_ANNOTATIONS));
context.removeAttribute(DISCOVERED_ANNOTATIONS);
}
public void parseWebInfLib (final WebAppContext context, final AnnotationParser parser)
throws Exception
{
WebXmlProcessor webXmlProcessor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR);
if (webXmlProcessor == null)
throw new IllegalStateException ("No processor for web xml");
MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA);
if (metaData == null)
throw new IllegalStateException ("No metadata");
List<Descriptor> frags = webXmlProcessor.getFragments();
List<FragmentDescriptor> frags = metaData.getFragments();
//Get the web-inf lib jars who have a web-fragment.xml that is not metadata-complete (or is not set)
//email from Rajiv Mordani jsrs 315 7 April 2010
//jars that do not have a web-fragment.xml are still considered fragments
//they have to participate in the ordering
ArrayList<URI> webInfUris = new ArrayList<URI>();
List<Resource> jarResources = (List<Resource>)context.getAttribute(WEB_INF_JAR_RESOURCES);
for (Resource r : jarResources)
List<Resource> jars = (List<Resource>)context.getAttribute(WEB_INF_ORDERED_JAR_RESOURCES);
//No ordering just use the jars in any order
if (jars == null || jars.isEmpty())
jars = (List<Resource>)context.getAttribute(WEB_INF_JAR_RESOURCES);
List<DiscoveredAnnotation> discoveredAnnotations = new ArrayList<DiscoveredAnnotation>();
context.setAttribute(DISCOVERED_ANNOTATIONS, discoveredAnnotations);
for (Resource r : jars)
{
discoveredAnnotations.clear(); //start fresh for each jar
URI uri = r.getURI();
Descriptor d = null;
for (Descriptor frag: frags)
FragmentDescriptor f = getFragmentFromJar(r, frags);
//if a jar has no web-fragment.xml we scan it (because it is not exluded by the ordering)
//or if it has a fragment we scan it if it is not metadata complete
if (f == null || !isMetaDataComplete(f))
{
Resource fragResource = frag.getResource(); //eg jar:file:///a/b/c/foo.jar!/META-INF/web-fragment.xml
if (Resource.isContainedIn(fragResource,r))
{
d = frag;
break;
}
parser.parse(uri,
new ClassNameResolver()
{
public boolean isExcluded (String name)
{
if (context.isSystemClass(name)) return true;
if (context.isServerClass(name)) return false;
return false;
}
public boolean shouldOverride (String name)
{
//looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp?
if (context.isParentLoaderPriority())
return false;
return true;
}
});
metaData.addDiscoveredAnnotations(r, discoveredAnnotations);
}
//if there was no web-fragment.xml for the jar, or there was one
//and its metadata is NOT complete, we want to exame it for annotations
if (d == null || (d != null && !d.isMetaDataComplete()))
webInfUris.add(uri);
}
parser.parse(webInfUris.toArray(new URI[webInfUris.size()]),
new ClassNameResolver()
{
public boolean isExcluded (String name)
{
if (context.isSystemClass(name)) return true;
if (context.isServerClass(name)) return false;
return false;
}
public boolean shouldOverride (String name)
{
//looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp?
if (context.isParentLoaderPriority())
return false;
return true;
}
});
context.removeAttribute(DISCOVERED_ANNOTATIONS);
}
public void parseWebInfClasses (final WebAppContext context, final AnnotationParser parser)
@ -133,6 +150,13 @@ public abstract class AbstractConfiguration implements Configuration
Resource classesDir = context.getWebInf().addPath("classes/");
if (classesDir.exists())
{
MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA);
if (metaData == null)
throw new IllegalStateException ("No metadata");
List<DiscoveredAnnotation> discoveredAnnotations = new ArrayList<DiscoveredAnnotation>();
context.setAttribute(DISCOVERED_ANNOTATIONS, discoveredAnnotations);
parser.parse(classesDir,
new ClassNameResolver()
{
@ -151,37 +175,36 @@ public abstract class AbstractConfiguration implements Configuration
return true;
}
});
//TODO - where to set the annotations discovered from WEB-INF/classes?
metaData.addDiscoveredAnnotations (discoveredAnnotations);
context.removeAttribute(DISCOVERED_ANNOTATIONS);
}
}
}
public void parse25Classes (final WebAppContext context, final AnnotationParser parser)
public FragmentDescriptor getFragmentFromJar (Resource jar, List<FragmentDescriptor> frags)
throws Exception
{
//only parse servlets, filters and listeners from web.xml
if (Log.isDebugEnabled()) Log.debug("Scanning only classes from web.xml");
ArrayList<String> classNames = (ArrayList<String>)context.getAttribute(WEBXML_CLASSNAMES);
for (String s : classNames)
//check if the jar has a web-fragment.xml
FragmentDescriptor d = null;
for (FragmentDescriptor frag: frags)
{
Class clazz = Loader.loadClass(null, s);
parser.parse(clazz, new ClassNameResolver()
Resource fragResource = frag.getResource(); //eg jar:file:///a/b/c/foo.jar!/META-INF/web-fragment.xml
if (Resource.isContainedIn(fragResource,jar))
{
public boolean isExcluded (String name)
{
if (context.isSystemClass(name)) return true;
if (context.isServerClass(name)) return false;
return false;
}
public boolean shouldOverride (String name)
{
//looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp?
if (context.isParentLoaderPriority())
return false;
return true;
}
}, true);
d = frag;
break;
}
}
return d;
}
public boolean isMetaDataComplete (Descriptor d)
{
return (d!=null && d.getMetaDataComplete() == MetaDataComplete.True);
}
}

View File

@ -13,17 +13,18 @@
package org.eclipse.jetty.annotations;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* Configuration
* Configuration for Annotations
*
*
*/
public class AnnotationConfiguration extends AbstractConfiguration
{
public static final String CLASS_INHERITANCE_MAP = "org.eclipse.jetty.classInheritanceMap";
public void preConfigure(final WebAppContext context) throws Exception
{
@ -31,53 +32,9 @@ public class AnnotationConfiguration extends AbstractConfiguration
public void configure(WebAppContext context) throws Exception
{
Boolean b = (Boolean)context.getAttribute(METADATA_COMPLETE);
boolean metadataComplete = (b != null && b.booleanValue());
Integer i = (Integer)context.getAttribute(WEBXML_VERSION);
int webxmlVersion = (i == null? 0 : i.intValue());
if (metadataComplete)
{
//Never scan any jars or classes for annotations if metadata is complete
if (Log.isDebugEnabled()) Log.debug("Metadata-complete==true, not processing annotations for context "+context);
return;
}
else
{
//Only scan jars and classes if metadata is not complete and the web app is version 3.0, or
//a 2.5 version webapp that has specifically asked to discover annotations
if (Log.isDebugEnabled()) Log.debug("parsing annotations");
AnnotationParser parser = new AnnotationParser();
parser.registerAnnotationHandler("javax.annotation.Resource", new ResourceAnnotationHandler (context));
parser.registerAnnotationHandler("javax.annotation.Resources", new ResourcesAnnotationHandler (context));
parser.registerAnnotationHandler("javax.annotation.PostConstruct", new PostConstructAnnotationHandler(context));
parser.registerAnnotationHandler("javax.annotation.PreDestroy", new PreDestroyAnnotationHandler(context));
parser.registerAnnotationHandler("javax.annotation.security.RunAs", new RunAsAnnotationHandler(context));
parser.registerAnnotationHandler("javax.annotation.security.DeclareRoles", new DeclareRolesAnnotationHandler(context));
ClassInheritanceHandler classHandler = new ClassInheritanceHandler();
parser.registerClassHandler(classHandler);
if (webxmlVersion >= 30 || context.isConfigurationDiscovered())
{
if (Log.isDebugEnabled()) Log.debug("Scanning all classes for annotations: webxmlVersion="+webxmlVersion+" configurationDiscovered="+context.isConfigurationDiscovered());
parseContainerPath(context, parser);
parseWebInfLib (context, parser);
parseWebInfClasses(context, parser);
}
else
{
if (Log.isDebugEnabled()) Log.debug("Scanning only classes in web.xml for annotations");
parse25Classes(context, parser);
}
//save the type inheritance map created by the parser for later reference
context.setAttribute(CLASS_INHERITANCE_MAP, classHandler.getMap());
}
{
WebAppDecoratorWrapper wrapper = new WebAppDecoratorWrapper(context, context.getDecorator());
context.setDecorator(wrapper);
}
@ -92,7 +49,5 @@ public class AnnotationConfiguration extends AbstractConfiguration
public void postConfigure(WebAppContext context) throws Exception
{
context.setAttribute(CLASS_INHERITANCE_MAP, null);
}
}

View File

@ -0,0 +1,102 @@
// ========================================================================
// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.annotations;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.util.log.Log;
/**
* AnnotationIntrospector
*
*
*/
public class AnnotationIntrospector
{
protected List<IntrospectableAnnotationHandler> _handlers = new ArrayList<IntrospectableAnnotationHandler>();
/**
* IntrospectableAnnotationHandler
*
* Interface for all handlers that wish to introspect a class to find a particular annotation
*/
public interface IntrospectableAnnotationHandler
{
public void handle(Class clazz);
}
/**
* AbstractIntrospectableAnnotationHandler
*
* Base class for handlers that introspect a class to find a particular annotation.
* A handler can optionally introspect the parent hierarchy of a class.
*/
public static abstract class AbstractIntrospectableAnnotationHandler implements IntrospectableAnnotationHandler
{
private boolean _introspectAncestors;
public abstract void doHandle(Class clazz);
public AbstractIntrospectableAnnotationHandler(boolean introspectAncestors)
{
_introspectAncestors = introspectAncestors;
}
public void handle(Class clazz)
{
Class c = clazz;
//process the whole inheritance hierarchy for the class
while (c!=null && (!c.equals(Object.class)))
{
doHandle(clazz);
if (!_introspectAncestors)
break;
c = c.getSuperclass();
}
}
}
public void registerHandler (IntrospectableAnnotationHandler handler)
{
_handlers.add(handler);
}
public void introspect (Class clazz)
{
if (_handlers == null)
return;
if (clazz == null)
return;
for (IntrospectableAnnotationHandler handler:_handlers)
{
try
{
handler.handle(clazz);
}
catch (Exception e)
{
Log.warn(e);
}
}
}
}

View File

@ -43,7 +43,7 @@ import org.objectweb.asm.commons.EmptyVisitor;
public class AnnotationParser
{
protected List<String> _parsedClassNames = new ArrayList<String>();
protected Map<String, AnnotationHandler> _annotationHandlers = new HashMap<String, AnnotationHandler>();
protected Map<String, List<DiscoverableAnnotationHandler>> _annotationHandlers = new HashMap<String, List<DiscoverableAnnotationHandler>>();
protected List<ClassHandler> _classHandlers = new ArrayList<ClassHandler>();
protected List<MethodHandler> _methodHandlers = new ArrayList<MethodHandler>();
protected List<FieldHandler> _fieldHandlers = new ArrayList<FieldHandler>();
@ -157,7 +157,7 @@ public class AnnotationParser
public interface AnnotationHandler
public interface DiscoverableAnnotationHandler
{
public void handleClass (String className, int version, int access,
String signature, String superName, String[] interfaces,
@ -310,12 +310,15 @@ public class AnnotationParser
public void visitEnd()
{
super.visitEnd();
//call all AnnotationHandlers with classname, annotation name + values
AnnotationHandler handler = AnnotationParser.this._annotationHandlers.get(_annotationName);
if (handler != null)
List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
if (handlers != null)
{
handler.handleClass(_className, _version, _access, _signature, _superName, _interfaces, _annotationName, _annotationValues);
for (DiscoverableAnnotationHandler h:handlers)
{
h.handleClass(_className, _version, _access, _signature, _superName, _interfaces, _annotationName, _annotationValues);
}
}
}
};
@ -340,10 +343,13 @@ public class AnnotationParser
{
super.visitEnd();
//call all AnnotationHandlers with classname, method, annotation name + values
AnnotationHandler handler = AnnotationParser.this._annotationHandlers.get(_annotationName);
if (handler != null)
List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
if (handlers != null)
{
handler.handleMethod(_className, name, access, methodDesc, signature, exceptions, _annotationName, _annotationValues);
for (DiscoverableAnnotationHandler h:handlers)
{
h.handleMethod(_className, name, access, methodDesc, signature, exceptions, _annotationName, _annotationValues);
}
}
}
};
@ -369,10 +375,13 @@ public class AnnotationParser
public void visitEnd()
{
super.visitEnd();
AnnotationHandler handler = AnnotationParser.this._annotationHandlers.get(_annotationName);
if (handler != null)
List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
if (handlers != null)
{
handler.handleField(_className, fieldName, access, fieldType, signature, value, _annotationName, _annotationValues);
for (DiscoverableAnnotationHandler h:handlers)
{
h.handleField(_className, fieldName, access, fieldType, signature, value, _annotationName, _annotationValues);
}
}
}
};
@ -383,9 +392,22 @@ public class AnnotationParser
}
public void registerAnnotationHandler (String annotationName, AnnotationHandler handler)
/**
* Register a handler that will be called back when the named annotation is
* encountered on a class.
*
* @param annotationName
* @param handler
*/
public void registerAnnotationHandler (String annotationName, DiscoverableAnnotationHandler handler)
{
_annotationHandlers.put(annotationName, handler);
List<DiscoverableAnnotationHandler> handlers = _annotationHandlers.get(annotationName);
if (handlers == null)
{
handlers = new ArrayList<DiscoverableAnnotationHandler>();
_annotationHandlers.put(annotationName, handlers);
}
handlers.add(handler);
}
public void registerClassHandler (ClassHandler handler)
@ -587,6 +609,14 @@ public class AnnotationParser
scanner.scan(null, uris, true);
}
public void parse (URI uri, final ClassNameResolver resolver)
throws Exception
{
if (uri == null)
return;
URI[] uris = {uri};
parse(uris, resolver);
}
private void scanClass (InputStream is)
throws IOException

View File

@ -1,5 +1,5 @@
// ========================================================================
// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd.
// Copyright (c) 2006-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
@ -11,79 +11,58 @@
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.annotations;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.servlet.Servlet;
import org.eclipse.jetty.annotations.AnnotationParser.AnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.ListValue;
import org.eclipse.jetty.annotations.AnnotationParser.SimpleValue;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import javax.annotation.security.DeclareRoles;
import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.webapp.WebAppContext;
public class DeclareRolesAnnotationHandler implements AnnotationHandler
/**
* DeclaresRolesAnnotationHandler
*
*
*/
public class DeclareRolesAnnotationHandler extends AbstractIntrospectableAnnotationHandler
{
protected WebAppContext _wac;
protected WebAppContext _context;
public DeclareRolesAnnotationHandler (WebAppContext wac)
/**
* @param introspectAncestors
*/
public DeclareRolesAnnotationHandler(WebAppContext context)
{
_wac = wac;
super(false);
_context = context;
}
/**
* A DeclareRoles annotation is equivalent to a <security-role> in web.xml.
*
* @see org.eclipse.jetty.annotations.AnnotationParser.AnnotationHandler#handleClass(java.lang.String, int, int, java.lang.String, java.lang.String, java.lang.String[], java.lang.String, java.util.List)
* @see org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler#doHandle(java.lang.Class)
*/
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)
public void doHandle(Class clazz)
{
//Add the role names to the list of roles for the webapp
Set<String> roles = new HashSet<String>();
if (!Servlet.class.isAssignableFrom(clazz))
return; //only applicable on javax.servlet.Servlet derivatives
try
{
Set<String> existing = ((ConstraintSecurityHandler)_wac.getSecurityHandler()).getRoles();
roles.addAll(existing);
if (values != null && values.size() == 1)
{
Value v = values.get(0);
if (v instanceof SimpleValue)
{
roles.add((String)((SimpleValue)v).getValue());
}
else if (v instanceof ListValue)
{
for (Value vv:((ListValue)v).getList())
{
roles.add((String)((SimpleValue)vv).getValue());
}
}
}
}
catch (Exception e)
{
Log.warn(e);
}
}
DeclareRoles declareRoles = (DeclareRoles) clazz.getAnnotation(DeclareRoles.class);
if (declareRoles == null)
return;
String[] roles = declareRoles.value();
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
{
Log.warn ("@DeclareRoles annotation not applicable for field: "+className+"."+fieldName);
}
public void handleMethod(String className, String methodName, int access, String desc, String signature, String[] exceptions, String annotation,
List<Value> values)
{
Log.warn ("@DeclareRoles annotation not applicable for method: "+className+"."+methodName);
if (roles != null && roles.length > 0)
{
for (String r:roles)
((ConstraintSecurityHandler)_context.getSecurityHandler()).addRole(r);
}
}
}

View File

@ -13,77 +13,65 @@
package org.eclipse.jetty.annotations;
import java.util.List;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.eclipse.jetty.annotations.AnnotationParser.AnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import javax.annotation.PostConstruct;
import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection;
import org.eclipse.jetty.plus.annotation.PostConstructCallback;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.webapp.MetaData;
import org.eclipse.jetty.webapp.WebAppContext;
public class PostConstructAnnotationHandler implements AnnotationHandler
public class PostConstructAnnotationHandler extends AbstractIntrospectableAnnotationHandler
{
protected WebAppContext _wac;
protected WebAppContext _context;
protected LifeCycleCallbackCollection _callbacks;
public PostConstructAnnotationHandler (WebAppContext wac)
{
_wac = wac;
_callbacks = (LifeCycleCallbackCollection)_wac.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
super(true);
_context = wac;
_callbacks = (LifeCycleCallbackCollection)_context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
}
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)
{
Log.warn ("@PostConstruct annotation not applicable to classes: "+className);
}
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
{
Log.warn("@PostConstruct annotation not applicable to fields: "+className+"."+fieldName);
}
public void handleMethod(String className, String methodName, int access, String desc, String signature, String[] exceptions, String annotation,
List<Value> values)
public void doHandle(Class clazz)
{
try
//Check that the PostConstruct is on a class that we're interested in
if (Util.isServletType(clazz))
{
org.objectweb.asm.Type[] args = org.objectweb.asm.Type.getArgumentTypes(desc);
if (args.length != 0)
Method[] methods = clazz.getDeclaredMethods();
for (int i=0; i<methods.length; i++)
{
Log.warn("Skipping PostConstruct annotation on "+className+"."+methodName+": has parameters");
return;
Method m = (Method)methods[i];
if (m.isAnnotationPresent(PostConstruct.class))
{
if (m.getParameterTypes().length != 0)
throw new IllegalStateException(m+" has parameters");
if (m.getReturnType() != Void.TYPE)
throw new IllegalStateException(m+" is not void");
if (m.getExceptionTypes().length != 0)
throw new IllegalStateException(m+" throws checked exceptions");
if (Modifier.isStatic(m.getModifiers()))
throw new IllegalStateException(m+" is static");
//ServletSpec 3.0 p80 If web.xml declares even one post-construct then all post-constructs
//in fragments must be ignored. Otherwise, they are additive.
MetaData metaData = ((MetaData)_context.getAttribute(MetaData.METADATA));
MetaData.Origin origin = metaData.getOrigin("post-construct");
if (origin != null &&
(origin == MetaData.Origin.WebXml ||
origin == MetaData.Origin.WebDefaults ||
origin == MetaData.Origin.WebOverride))
return;
PostConstructCallback callback = new PostConstructCallback();
callback.setTarget(clazz.getName(), m.getName());
_callbacks.add(callback);
}
}
if (org.objectweb.asm.Type.getReturnType(desc) != org.objectweb.asm.Type.VOID_TYPE)
{
Log.warn("Skipping PostConstruct annotation on "+className+"."+methodName+": is not void");
return;
}
if (exceptions != null && exceptions.length != 0)
{
Log.warn("Skipping PostConstruct annotation on "+className+"."+methodName+": throws checked exceptions");
return;
}
if ((access & org.objectweb.asm.Opcodes.ACC_STATIC) > 0)
{
Log.warn("Skipping PostConstruct annotation on "+className+"."+methodName+": is static");
return;
}
PostConstructCallback callback = new PostConstructCallback();
callback.setTarget(className, methodName);
_callbacks.add(callback);
}
catch (Exception e)
{
Log.warn(e);
}
}
}

View File

@ -13,75 +13,64 @@
package org.eclipse.jetty.annotations;
import java.util.List;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.eclipse.jetty.annotations.AnnotationParser.AnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import javax.annotation.PreDestroy;
import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection;
import org.eclipse.jetty.plus.annotation.PreDestroyCallback;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.webapp.MetaData;
import org.eclipse.jetty.webapp.WebAppContext;
public class PreDestroyAnnotationHandler implements AnnotationHandler
public class PreDestroyAnnotationHandler extends AbstractIntrospectableAnnotationHandler
{
WebAppContext _wac;
WebAppContext _context;
LifeCycleCallbackCollection _callbacks;
public PreDestroyAnnotationHandler (WebAppContext wac)
{
_wac = wac;
_callbacks = (LifeCycleCallbackCollection)_wac.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
super(true);
_context = wac;
_callbacks = (LifeCycleCallbackCollection)_context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
}
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)
{
Log.warn("@PreDestroy annotation not applicable for classes: "+className);
}
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
{
Log.warn("@PreDestroy annotation not applicable for fields: "+className+"."+fieldName);
}
public void handleMethod(String className, String methodName, int access, String desc, String signature, String[] exceptions, String annotation,
List<Value> values)
{
try
public void doHandle(Class clazz)
{
//Check that the PreDestroy is on a class that we're interested in
if (Util.isServletType(clazz))
{
org.objectweb.asm.Type[] args = org.objectweb.asm.Type.getArgumentTypes(desc);
if (args.length != 0)
Method[] methods = clazz.getDeclaredMethods();
for (int i=0; i<methods.length; i++)
{
Log.warn("Skipping PreDestroy annotation on "+className+"."+methodName+": has parameters");
return;
Method m = (Method)methods[i];
if (m.isAnnotationPresent(PreDestroy.class))
{
if (m.getParameterTypes().length != 0)
throw new IllegalStateException(m+" has parameters");
if (m.getReturnType() != Void.TYPE)
throw new IllegalStateException(m+" is not void");
if (m.getExceptionTypes().length != 0)
throw new IllegalStateException(m+" throws checked exceptions");
if (Modifier.isStatic(m.getModifiers()))
throw new IllegalStateException(m+" is static");
//ServletSpec 3.0 p80 If web.xml declares even one predestroy then all predestroys
//in fragments must be ignored. Otherwise, they are additive.
MetaData metaData = ((MetaData)_context.getAttribute(MetaData.METADATA));
MetaData.Origin origin = metaData.getOrigin("pre-destroy");
if (origin != null &&
(origin == MetaData.Origin.WebXml ||
origin == MetaData.Origin.WebDefaults ||
origin == MetaData.Origin.WebOverride))
return;
PreDestroyCallback callback = new PreDestroyCallback();
callback.setTarget(clazz.getName(), m.getName());
_callbacks.add(callback);
}
}
if (org.objectweb.asm.Type.getReturnType(desc) != org.objectweb.asm.Type.VOID_TYPE)
{
Log.warn("Skipping PreDestroy annotation on "+className+"."+methodName+": is not void");
return;
}
if (exceptions != null && exceptions.length != 0)
{
Log.warn("Skipping PreDestroy annotation on "+className+"."+methodName+": throws checked exceptions");
return;
}
if ((access & org.objectweb.asm.Opcodes.ACC_STATIC) > 0)
{
Log.warn("Skipping PreDestroy annotation on "+className+"."+methodName+": is static");
return;
}
PreDestroyCallback callback = new PreDestroyCallback();
callback.setTarget(className, methodName);
_callbacks.add(callback);
}
catch (Exception e)
{
Log.warn(e);
}
}
}

View File

@ -13,28 +13,33 @@
package org.eclipse.jetty.annotations;
import java.util.List;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import javax.annotation.Resource;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import org.eclipse.jetty.annotations.AnnotationParser.AnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
import org.eclipse.jetty.plus.annotation.Injection;
import org.eclipse.jetty.plus.annotation.InjectionCollection;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.webapp.MetaData;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.MetaData.Origin;
public class ResourceAnnotationHandler implements AnnotationHandler
public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationHandler
{
protected WebAppContext _wac;
protected WebAppContext _context;
protected InjectionCollection _injections;
public ResourceAnnotationHandler (WebAppContext wac)
{
_wac = wac;
_injections = (InjectionCollection)_wac.getAttribute(InjectionCollection.INJECTION_COLLECTION);
super(true);
_context = wac;
_injections = (InjectionCollection)_context.getAttribute(InjectionCollection.INJECTION_COLLECTION);
}
@ -43,95 +48,104 @@ public class ResourceAnnotationHandler implements AnnotationHandler
* environment that will be looked up at runtime. They do
* not specify an injection.
*/
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)
public void doHandle(Class clazz)
{
String name = null;
String mappedName = null;
String resourceType = null;
if (values != null)
if (Util.isServletType(clazz))
{
for (Value v : values)
{
if ("name".equals(v.getName()))
name = (String)v.getValue();
else if ("mappedName".equals(v.getName()))
mappedName = (String)v.getValue();
else if ("type".equals(v.getName()))
resourceType = (String)v.getValue();
}
if (name==null || name.trim().equals(""))
throw new IllegalStateException ("Class level Resource annotations must contain a name (Common Annotations Spec Section 2.3)");
try
{
if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac, name,mappedName))
if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac.getServer(), name,mappedName))
throw new IllegalStateException("No resource at "+(mappedName==null?name:mappedName));
}
catch (NamingException e)
{
Log.warn(e);
}
handleClass(clazz);
Method[] methods = clazz.getDeclaredMethods();
for (int i=0; i<methods.length; i++)
handleMethod(clazz, methods[i]);
Field[] fields = clazz.getDeclaredFields();
//For each field, get all of it's annotations
for (int i=0; i<fields.length; i++)
handleField(clazz, fields[i]);
}
}
public void handleClass (Class clazz)
{
Resource resource = (Resource)clazz.getAnnotation(Resource.class);
if (resource != null)
{
String name = resource.name();
String mappedName = resource.mappedName();
Resource.AuthenticationType auth = resource.authenticationType();
Class type = resource.type();
boolean shareable = resource.shareable();
if (name==null || name.trim().equals(""))
throw new IllegalStateException ("Class level Resource annotations must contain a name (Common Annotations Spec Section 2.3)");
try
{
if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context, name,mappedName))
if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context.getServer(), name,mappedName))
throw new IllegalStateException("No resource at "+(mappedName==null?name:mappedName));
}
catch (NamingException e)
{
Log.warn(e);
}
}
}
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
public void handleField(Class clazz, Field field)
{
try
Resource resource = (Resource)field.getAnnotation(Resource.class);
if (resource != null)
{
//JavaEE Spec 5.2.3: Field cannot be static
if ((access & org.objectweb.asm.Opcodes.ACC_STATIC) > 0)
if (Modifier.isStatic(field.getModifiers()))
{
Log.warn("Skipping Resource annotation on "+className+"."+fieldName+": cannot be static");
Log.warn("Skipping Resource annotation on "+clazz.getName()+"."+field.getName()+": cannot be static");
return;
}
//JavaEE Spec 5.2.3: Field cannot be final
if ((access & org.objectweb.asm.Opcodes.ACC_FINAL) > 0)
if (Modifier.isFinal(field.getModifiers()))
{
Log.warn("Skipping Resource annotation on "+className+"."+fieldName+": cannot be final");
Log.warn("Skipping Resource annotation on "+clazz.getName()+"."+field.getName()+": cannot be final");
return;
}
//work out default name
String name = className+"/"+fieldName;
String mappedName = null;
org.objectweb.asm.Type resourceType = null;
if (values != null)
String name = clazz.getCanonicalName()+"/"+field.getName();
//allow @Resource name= to override the field name
name = (resource.name()!=null && !resource.name().trim().equals("")? resource.name(): name);
String mappedName = (resource.mappedName()!=null && !resource.mappedName().trim().equals("")?resource.mappedName():null);
//get the type of the Field
Class type = field.getType();
//Servlet Spec 3.0 p. 76
//If a descriptor has specified at least 1 injection target for this
//resource, then it overrides this annotation
MetaData metaData = ((MetaData)_context.getAttribute(MetaData.METADATA));
if (metaData.getOriginDescriptor("resource-ref."+name+".injection") != null)
{
for (Value val :values)
{
//allow @Resource name= to override the field name
if (val.getName().equals("name") && !"".equals((String)val.getValue()))
name = (String)(val.getValue());
//get the mappedName if there is one
else if (val.getName().equals("mappedName") && !"".equals((String)val.getValue()))
mappedName = (String)val.getValue();
//save @Resource type, so we can check it is compatible with field type later
else if (val.getName().equals("type"))
{
resourceType = (org.objectweb.asm.Type)(val.getValue());
}
}
//at least 1 injection was specified for this resource by a descriptor, so
//it overrides this annotation
return;
}
//check if an injection has already been setup for this target by web.xml
Injection webXmlInjection = _injections.getInjection(name, className, fieldName);
if (webXmlInjection == null)
//No injections for this resource in any descriptors, so we can add it
//Does the injection already exist?
Injection injection = _injections.getInjection(name, clazz, field);
if (injection == null)
{
//No injection has been specified, add it
try
{
boolean bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac, name, mappedName);
boolean bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context, name, mappedName);
if (!bound)
bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac.getServer(), name, mappedName);
bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context.getServer(), name, mappedName);
if (!bound)
bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(null, name, mappedName);
if (!bound)
{
//see if there is an env-entry value been bound from web.xml
//see if there is an env-entry value been bound
try
{
InitialContext ic = new InitialContext();
@ -149,16 +163,17 @@ public class ResourceAnnotationHandler implements AnnotationHandler
{
Log.debug("Bound "+(mappedName==null?name:mappedName) + " as "+ name);
// Make the Injection for it if the binding succeeded
Injection injection = new Injection();
injection.setTarget(className, fieldName, Util.asCanonicalName(resourceType));
injection = new Injection();
injection.setTarget(clazz, field, type);
injection.setJndiName(name);
injection.setMappingName(mappedName);
_injections.add(injection);
}
else if (!Util.isEnvEntryType(fieldType))
{
System.err.println(fieldType);
//TODO - an @Resource is equivalent to a resource-ref, resource-env-ref, message-destination
metaData.setOrigin("resource-ref."+name+".injection");
}
else if (!Util.isEnvEntryType(type))
{
//if this is an env-entry type resource and there is no value bound for it, it isn't
//an error, it just means that perhaps the code will use a default value instead
// JavaEE Spec. sec 5.4.1.3
@ -171,29 +186,26 @@ public class ResourceAnnotationHandler implements AnnotationHandler
//if this is an env-entry type resource and there is no value bound for it, it isn't
//an error, it just means that perhaps the code will use a default value instead
// JavaEE Spec. sec 5.4.1.3
if (!Util.isEnvEntryType(fieldType))
if (!Util.isEnvEntryType(type))
throw new IllegalStateException(e);
}
}
}
catch (Exception e)
{
Log.warn(e);
}
}
/**
* Process a Resource annotation on a Method.
*
* This will generate a JNDI entry, and an Injection to be
* processed when an instance of the class is created.
*/
public void handleMethod(String className, String methodName, int access, String desc, String signature, String[] exceptions, String annotation,
List<Value> values)
public void handleMethod(Class clazz, Method method)
{
try
Resource resource = (Resource)method.getAnnotation(Resource.class);
if (resource != null)
{
/*
* Commons Annotations Spec 2.3
* " The Resource annotation is used to declare a reference to a resource.
@ -212,70 +224,68 @@ public class ResourceAnnotationHandler implements AnnotationHandler
* or field, inject it!".
*/
//JavaEE Spec 5.2.3: Method cannot be static
if ((access & org.objectweb.asm.Opcodes.ACC_STATIC) > 0)
if (Modifier.isStatic(method.getModifiers()))
{
Log.warn("Skipping Resource annotation on "+className+"."+methodName+": cannot be static");
Log.warn("Skipping Resource annotation on "+clazz.getName()+"."+method.getName()+": cannot be static");
return;
}
// Check it is a valid javabean: must be void return type, the name must start with "set" and it must have
// only 1 parameter
if (!methodName.startsWith("set"))
if (!method.getName().startsWith("set"))
{
Log.warn("Skipping Resource annotation on "+className+"."+methodName+": invalid java bean, does not start with 'set'");
Log.warn("Skipping Resource annotation on "+clazz.getName()+"."+method.getName()+": invalid java bean, does not start with 'set'");
return;
}
org.objectweb.asm.Type[] args = org.objectweb.asm.Type.getArgumentTypes(desc);
if (args == null || args.length != 1)
if (method.getParameterTypes().length != 1)
{
Log.warn("Skipping Resource annotation on "+className+"."+methodName+": invalid java bean, not single argument to method");
Log.warn("Skipping Resource annotation on "+clazz.getName()+"."+method.getName()+": invalid java bean, not single argument to method");
return;
}
org.objectweb.asm.Type retVal = org.objectweb.asm.Type.getReturnType(desc);
if (!org.objectweb.asm.Type.VOID_TYPE.equals(retVal))
if (Void.TYPE != method.getReturnType())
{
Log.warn("Skipping Resource annotation on "+className+"."+methodName+": invalid java bean, not void");
Log.warn("Skipping Resource annotation on "+clazz.getName()+"."+method.getName()+": invalid java bean, not void");
return;
}
//default name is the javabean property name
String name = methodName.substring(3);
String name = method.getName().substring(3);
name = name.substring(0,1).toLowerCase()+name.substring(1);
name = className+"/"+name;
String mappedName = null;
org.objectweb.asm.Type resourceType = null;
if (values != null)
{
for (Value v : values)
{
//allow default name to be overridden
if ("name".equals(v.getName()))
name = (String)(v.getValue());
//get the mappedName if there is one
else if ("mappedName".equals(v.getName()) && !"".equals((String)(v.getValue())))
mappedName = (String)(v.getValue());
else if ("type".equals(v.getName()))
{
resourceType = (org.objectweb.asm.Type)(v.getValue());
}
//TODO: authentication and shareable
}
}
name = clazz.getCanonicalName()+"/"+name;
name = (resource.name()!=null && !resource.name().trim().equals("")? resource.name(): name);
String mappedName = (resource.mappedName()!=null && !resource.mappedName().trim().equals("")?resource.mappedName():null);
Class paramType = method.getParameterTypes()[0];
Class resourceType = resource.type();
//Servlet Spec 3.0 p. 76
//If a descriptor has specified at least 1 injection target for this
//resource, then it overrides this annotation
MetaData metaData = ((MetaData)_context.getAttribute(MetaData.METADATA));
if (metaData.getOriginDescriptor("resource-ref."+name+".injection") != null)
{
//at least 1 injection was specified for this resource by a descriptor, so
//it overrides this annotation
return;
}
//check if an injection has already been setup for this target by web.xml
Injection webXmlInjection = _injections.getInjection(name, className, methodName, Util.asCanonicalName(args[0]));
if (webXmlInjection == null)
Injection injection = _injections.getInjection(name, clazz, method, paramType);
if (injection == null)
{
try
{
//try binding name to environment
//try the webapp's environment first
boolean bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac, name, mappedName);
boolean bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context, name, mappedName);
//try the server's environment
if (!bound)
bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac.getServer(), name, mappedName);
bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context.getServer(), name, mappedName);
//try the jvm's environment
if (!bound)
@ -302,13 +312,15 @@ public class ResourceAnnotationHandler implements AnnotationHandler
{
Log.debug("Bound "+(mappedName==null?name:mappedName) + " as "+ name);
// Make the Injection for it
Injection injection = new Injection();
injection.setTarget(className, methodName, Util.asCanonicalName(args[0]), Util.asCanonicalName(resourceType));
injection = new Injection();
injection.setTarget(clazz, method,paramType,resourceType);
injection.setJndiName(name);
injection.setMappingName(mappedName);
_injections.add(injection);
//TODO - an @Resource is equivalent to a resource-ref, resource-env-ref, message-destination
metaData.setOrigin("resource-ref."+name+".injection");
}
else if (!Util.isEnvEntryType(args[0].getDescriptor()))
else if (!Util.isEnvEntryType(paramType))
{
//if this is an env-entry type resource and there is no value bound for it, it isn't
@ -322,14 +334,11 @@ public class ResourceAnnotationHandler implements AnnotationHandler
//if this is an env-entry type resource and there is no value bound for it, it isn't
//an error, it just means that perhaps the code will use a default value instead
// JavaEE Spec. sec 5.4.1.3
if (!Util.isEnvEntryType(args[0].getDescriptor()))
if (!Util.isEnvEntryType(paramType))
throw new IllegalStateException(e);
}
}
}
catch (Exception e)
{
Log.warn(e);
}
}
}

View File

@ -13,78 +13,63 @@
package org.eclipse.jetty.annotations;
import java.util.List;
import javax.annotation.Resource;
import javax.annotation.Resources;
import javax.naming.NamingException;
import org.eclipse.jetty.annotations.AnnotationParser.AnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.ListValue;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.webapp.WebAppContext;
public class ResourcesAnnotationHandler implements AnnotationHandler
public class ResourcesAnnotationHandler extends AbstractIntrospectableAnnotationHandler
{
protected WebAppContext _wac;
public ResourcesAnnotationHandler (WebAppContext wac)
{
super(true);
_wac = wac;
}
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)
public void doHandle (Class clazz)
{
if (values != null && values.size() == 1)
Resources resources = (Resources)clazz.getAnnotation(Resources.class);
if (resources != null)
{
List<ListValue> list = (List<ListValue>)(values.get(0).getValue());
for (ListValue resource : list)
Resource[] resArray = resources.value();
if (resArray==null||resArray.length==0)
{
List<Value> resourceValues = resource.getList();
String name = null;
String mappedName = null;
for (Value v:resourceValues)
Log.warn ("Skipping empty or incorrect Resources annotation on "+clazz.getName());
return;
}
for (int j=0;j<resArray.length;j++)
{
String name = resArray[j].name();
String mappedName = resArray[j].mappedName();
Resource.AuthenticationType auth = resArray[j].authenticationType();
Class type = resArray[j].type();
boolean shareable = resArray[j].shareable();
if (name==null || name.trim().equals(""))
throw new IllegalStateException ("Class level Resource annotations must contain a name (Common Annotations Spec Section 2.3)");
try
{
if ("name".equals(v.getName()))
name = (String)v.getValue();
else if ("mappedName".equals(v.getName()))
mappedName = (String)v.getValue();
//TODO don't ignore the shareable, auth etc etc
if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac, name, mappedName))
if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac.getServer(), name, mappedName))
Log.warn("Skipping Resources(Resource) annotation on "+clazz.getName()+" for name "+name+": No resource bound at "+(mappedName==null?name:mappedName));
}
if (name == null)
Log.warn ("Skipping Resources(Resource) annotation with no name on class "+className);
else
catch (NamingException e)
{
try
{
//TODO don't ignore the shareable, auth etc etc
if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac, name, mappedName))
if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac.getServer(), name, mappedName))
Log.warn("Skipping Resources(Resource) annotation on "+className+" for name "+name+": No resource bound at "+(mappedName==null?name:mappedName));
}
catch (NamingException e)
{
Log.warn(e);
}
}
Log.warn(e);
}
}
}
else
{
Log.warn("Skipping empty or incorrect Resources annotation on "+className);
}
}
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
{
Log.warn ("@Resources not applicable for fields: "+className+"."+fieldName);
}
public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation,
List<Value> values)
{
Log.warn ("@Resources not applicable for methods: "+className+"."+methodName);
}
}
}

View File

@ -15,47 +15,63 @@ package org.eclipse.jetty.annotations;
import java.util.List;
import org.eclipse.jetty.annotations.AnnotationParser.AnnotationHandler;
import javax.servlet.Servlet;
import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import org.eclipse.jetty.plus.annotation.RunAsCollection;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.webapp.Descriptor;
import org.eclipse.jetty.webapp.MetaData;
import org.eclipse.jetty.webapp.WebAppContext;
public class RunAsAnnotationHandler implements AnnotationHandler
public class RunAsAnnotationHandler extends AbstractIntrospectableAnnotationHandler
{
protected WebAppContext _wac;
protected WebAppContext _context;
public RunAsAnnotationHandler (WebAppContext wac)
{
_wac = wac;
//Introspect only the given class for a RunAs annotation, as it is a class level annotation,
//and according to Common Annotation Spec p2-6 a class-level annotation is not inheritable.
super(false);
_context = wac;
}
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)
public void doHandle (Class clazz)
{
RunAsCollection runAsCollection = (RunAsCollection)_wac.getAttribute(RunAsCollection.RUNAS_COLLECTION);
try
RunAsCollection runAsCollection = (RunAsCollection)_context.getAttribute(RunAsCollection.RUNAS_COLLECTION);
if (!Servlet.class.isAssignableFrom(clazz))
return;
javax.annotation.security.RunAs runAs = (javax.annotation.security.RunAs)clazz.getAnnotation(javax.annotation.security.RunAs.class);
if (runAs != null)
{
if (values != null && values.size() == 1)
String role = runAs.value();
if (role != null)
{
String role = (String)values.get(0).getValue();
if (role != null)
ServletHolder holder = getServletHolderForClass(clazz);
if (holder != null)
{
org.eclipse.jetty.plus.annotation.RunAs ra = new org.eclipse.jetty.plus.annotation.RunAs();
ra.setTargetClassName(className);
ra.setRoleName(role);
runAsCollection.add(ra);
MetaData metaData = ((MetaData)_context.getAttribute(MetaData.METADATA));
Descriptor d = metaData.getOriginDescriptor(holder.getName()+".servlet.run-as");
//if a descriptor has already set the value for run-as, do not
//let the annotation override it
if (d == null)
{
metaData.setOrigin(holder.getName()+".servlet.run-as");
org.eclipse.jetty.plus.annotation.RunAs ra = new org.eclipse.jetty.plus.annotation.RunAs();
ra.setTargetClassName(clazz.getCanonicalName());
ra.setRoleName(role);
runAsCollection.add(ra);
}
}
}
else
Log.warn("Bad value for @RunAs annotation on class "+className);
Log.warn("Bad value for @RunAs annotation on class "+clazz.getName());
}
catch (Exception e)
{
Log.warn(e);
}
}
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
@ -70,4 +86,20 @@ public class RunAsAnnotationHandler implements AnnotationHandler
Log.warn("@RunAs annotation ignored on method: "+className+"."+methodName+" "+signature);
}
private ServletHolder getServletHolderForClass (Class clazz)
{
ServletHolder holder = null;
ServletHolder[] holders = _context.getServletHandler().getServlets();
if (holders != null)
{
for (ServletHolder h : holders)
{
if (h.getClassName().equals(clazz.getName()))
{
holder = h;
}
}
}
return holder;
}
}

View File

@ -0,0 +1,164 @@
// ========================================================================
// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.annotations;
import java.util.EventListener;
import javax.servlet.Filter;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.ServletContextHandler.Decorator;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* WebAppDecoratorWrapper
*
*
*/
public class WebAppDecoratorWrapper implements Decorator
{
Decorator _wrappedDecorator;
AnnotationIntrospector _introspector = new AnnotationIntrospector();
/**
* @param context
*/
public WebAppDecoratorWrapper(WebAppContext context, Decorator wrappedDecorator)
{
_wrappedDecorator = wrappedDecorator;
_introspector.registerHandler(new ResourceAnnotationHandler(context));
_introspector.registerHandler(new ResourcesAnnotationHandler(context));
_introspector.registerHandler(new RunAsAnnotationHandler(context));
_introspector.registerHandler(new PostConstructAnnotationHandler(context));
_introspector.registerHandler(new PreDestroyAnnotationHandler(context));
_introspector.registerHandler(new DeclareRolesAnnotationHandler(context));
}
/* ------------------------------------------------------------ */
/**
* @param filter
* @throws ServletException
* @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#decorateFilterHolder(org.eclipse.jetty.servlet.FilterHolder)
*/
public void decorateFilterHolder(FilterHolder filter) throws ServletException
{
_wrappedDecorator.decorateFilterHolder(filter);
}
/* ------------------------------------------------------------ */
/**
* @param <T>
* @param filter
* @return
* @throws ServletException
* @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#decorateFilterInstance(javax.servlet.Filter)
*/
public <T extends Filter> T decorateFilterInstance(T filter) throws ServletException
{
introspect(filter);
return _wrappedDecorator.decorateFilterInstance(filter);
}
/* ------------------------------------------------------------ */
/**
* @param <T>
* @param listener
* @return
* @throws ServletException
* @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#decorateListenerInstance(java.util.EventListener)
*/
public <T extends EventListener> T decorateListenerInstance(T listener) throws ServletException
{
introspect(listener);
return _wrappedDecorator.decorateListenerInstance(listener);
}
/* ------------------------------------------------------------ */
/**
* @param servlet
* @throws ServletException
* @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#decorateServletHolder(org.eclipse.jetty.servlet.ServletHolder)
*/
public void decorateServletHolder(ServletHolder servlet) throws ServletException
{
_wrappedDecorator.decorateServletHolder(servlet);
}
/* ------------------------------------------------------------ */
/**
* @param <T>
* @param servlet
* @return
* @throws ServletException
* @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#decorateServletInstance(javax.servlet.Servlet)
*/
public <T extends Servlet> T decorateServletInstance(T servlet) throws ServletException
{
introspect(servlet);
return _wrappedDecorator.decorateServletInstance(servlet);
}
/* ------------------------------------------------------------ */
/**
* @param f
* @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#destroyFilterInstance(javax.servlet.Filter)
*/
public void destroyFilterInstance(Filter f)
{
_wrappedDecorator.destroyFilterInstance(f);
}
/* ------------------------------------------------------------ */
/**
* @param s
* @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#destroyServletInstance(javax.servlet.Servlet)
*/
public void destroyServletInstance(Servlet s)
{
_wrappedDecorator.destroyServletInstance(s);
}
/* ------------------------------------------------------------ */
/**
* @param f
* @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#destroyListenerInstance(java.util.EventListener)
*/
public void destroyListenerInstance(EventListener f)
{
_wrappedDecorator.destroyListenerInstance(f);
}
/**
* Look for annotations that can be discovered with introspection:
* <ul>
* <li> Resource
* <li> Resources
* <li> PostConstruct
* <li> PreDestroy
* <li> ServletSecurity?
* </ul>
* @param o
*/
protected void introspect (Object o)
{
_introspector.introspect(o.getClass());
}
}

View File

@ -28,8 +28,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@RunAs("admin")
public class FilterC implements Filter
{

View File

@ -15,8 +15,6 @@ package org.eclipse.jetty.annotations;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ListenerC implements ServletContextListener
{

View File

@ -1,5 +1,5 @@
// ========================================================================
// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
// Copyright (c) 2008-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
@ -17,7 +17,7 @@ import java.io.IOException;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.annotation.Resources;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RunAs;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
@ -26,11 +26,7 @@ import javax.servlet.http.HttpServletResponse;
@Resources({
@Resource(name="apple", mappedName="foo"),
@Resource(name="banana", mappedName="foo")
})
@DeclareRoles({"alice"})
@RunAs("admin")
public class ServletC extends HttpServlet
{

View File

@ -0,0 +1,84 @@
// ========================================================================
// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.annotations;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.FragmentDescriptor;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* TestAnnotationConfiguration
*
*
*/
public class TestAnnotationConfiguration extends TestCase
{
public void testGetFragmentFromJar ()
throws Exception
{
String dir = System.getProperty("basedir", ".");
File file = new File(dir);
file=new File(file.getCanonicalPath());
URL url=file.toURL();
Resource jar1 = Resource.newResource(url+"file.jar");
AbstractConfiguration config = new AbstractConfiguration()
{
public void configure(WebAppContext context) throws Exception
{
// TODO Auto-generated method stub
}
public void deconfigure(WebAppContext context) throws Exception
{
// TODO Auto-generated method stub
}
public void postConfigure(WebAppContext context) throws Exception
{
// TODO Auto-generated method stub
}
public void preConfigure(WebAppContext context) throws Exception
{
// TODO Auto-generated method stub
}
};
WebAppContext wac = new WebAppContext();
List<FragmentDescriptor> frags = new ArrayList<FragmentDescriptor>();
frags.add(new FragmentDescriptor(Resource.newResource("jar:"+url+"file.jar!/fooa.props"), null));
frags.add(new FragmentDescriptor(Resource.newResource("jar:"+url+"file2.jar!/foob.props"), null));
assertNotNull(config.getFragmentFromJar(jar1, frags));
}
}

View File

@ -13,31 +13,29 @@
package org.eclipse.jetty.annotations;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.eclipse.jetty.annotations.AnnotationParser.AnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import org.eclipse.jetty.util.MultiMap;
import org.junit.After;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
*
*/
public class TestAnnotationInheritance
{
private List<String> classNames = new ArrayList<String>();
private class SampleHandler implements AnnotationHandler
List<String> classNames = new ArrayList<String>();
class SampleHandler implements DiscoverableAnnotationHandler
{
public final List<String> annotatedClassNames = new ArrayList<String>();
public final List<String> annotatedMethods = new ArrayList<String>();
@ -188,40 +186,4 @@ public class TestAnnotationInheritance
});
assertEquals (1, handler.annotatedClassNames.size());
}
@Test
public void testTypeInheritanceHandling() throws Exception
{
AnnotationParser parser = new AnnotationParser();
ClassInheritanceHandler handler = new ClassInheritanceHandler();
parser.registerClassHandler(handler);
class Foo implements InterfaceD
{
}
classNames.clear();
classNames.add(ClassA.class.getName());
classNames.add(ClassB.class.getName());
classNames.add(InterfaceD.class.getName());
classNames.add(Foo.class.getName());
parser.parse(classNames, null);
MultiMap map = handler.getMap();
assertNotNull(map);
assertFalse(map.isEmpty());
assertEquals(2, map.size());
Map stringArrayMap = map.toStringArrayMap();
assertTrue (stringArrayMap.keySet().contains("org.eclipse.jetty.annotations.ClassA"));
assertTrue (stringArrayMap.keySet().contains("org.eclipse.jetty.annotations.InterfaceD"));
String[] classes = (String[])stringArrayMap.get("org.eclipse.jetty.annotations.ClassA");
assertEquals(1, classes.length);
assertEquals ("org.eclipse.jetty.annotations.ClassB", classes[0]);
classes = (String[])stringArrayMap.get("org.eclipse.jetty.annotations.InterfaceD");
assertEquals(2, classes.length);
assertEquals ("org.eclipse.jetty.annotations.ClassB", classes[0]);
assertEquals(Foo.class.getName(), classes[1]);
}
}

View File

@ -15,7 +15,7 @@ package org.eclipse.jetty.annotations;
import java.util.Arrays;
import java.util.List;
import org.eclipse.jetty.annotations.AnnotationParser.AnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import org.junit.Test;
@ -31,7 +31,7 @@ public class TestAnnotationParser
String[] classNames = new String[]{"org.eclipse.jetty.annotations.ClassA"};
AnnotationParser parser = new AnnotationParser();
class SampleAnnotationHandler implements AnnotationHandler
class SampleAnnotationHandler implements DiscoverableAnnotationHandler
{
private List<String> methods = Arrays.asList("a", "b", "c", "d", "l");
@ -104,7 +104,7 @@ public class TestAnnotationParser
String[] classNames = new String[]{"org.eclipse.jetty.annotations.ClassB"};
AnnotationParser parser = new AnnotationParser();
class MultiAnnotationHandler implements AnnotationHandler
class MultiAnnotationHandler implements DiscoverableAnnotationHandler
{
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)

View File

@ -13,17 +13,15 @@
package org.eclipse.jetty.annotations;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.annotations.AnnotationParser.AnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.HashSet;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.webapp.MetaData;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.Test;
/**
* TestServletAnnotations
@ -32,172 +30,20 @@ import static org.junit.Assert.fail;
*/
public class TestServletAnnotations
{
@Test
public void testServletAnnotation() throws Exception
{
List<String> classes = new ArrayList<String>();
classes.add("org.eclipse.jetty.annotations.ServletC");
AnnotationParser parser = new AnnotationParser();
class ResourceAnnotationHandler implements AnnotationHandler
{
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)
{}
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
{
assertEquals ("org.eclipse.jetty.annotations.ServletC", className);
assertEquals ("foo",fieldName);
assertNotNull (values);
assertNotNull (annotation);
assertTrue (annotation.endsWith("Resource"));
for (Value v :values)
{
if (v.getName().equals("mappedName"))
assertEquals ("foo", v.getValue());
else if (v.getName().equals("type"))
{
try
{
assertEquals(fieldType, ((org.objectweb.asm.Type)v.getValue()).getDescriptor());
}
catch (Exception e)
{
fail(e.getMessage());
}
}
}
}
public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation,
List<Value> values)
{
}
}
class CallbackAnnotationHandler implements AnnotationHandler
{
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)
{
}
public void handleMethod(String className, String methodName, int access, String desc, String signature, String[] exceptions, String annotation,
List<Value> values)
{
assertEquals ("org.eclipse.jetty.annotations.ServletC", className);
assertNotNull(methodName);
if (methodName.endsWith("pre"))
{
assertTrue(annotation.endsWith("PreDestroy"));
assertTrue(values.isEmpty());
}
else if (methodName.endsWith("post"))
{
assertTrue(annotation.endsWith("PostConstruct"));
assertTrue(values.isEmpty());
}
assertEquals (org.objectweb.asm.Type.VOID_TYPE, org.objectweb.asm.Type.getReturnType(desc));
assertEquals(0, org.objectweb.asm.Type.getArgumentTypes(desc).length);
int isstatic = access & org.objectweb.asm.Opcodes.ACC_STATIC;
assertTrue (isstatic == 0);
}
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
{
}
}
class RunAsAnnotationHandler implements AnnotationHandler
{
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)
{
assertNotNull (values);
assertEquals(1, values.size());
Value anv = values.get(0);
assertEquals("value", anv.getName());
assertEquals("admin", anv.getValue());
}
public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation,
List<Value> values)
{
}
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
{
}
}
class ResourcesAnnotationHandler implements AnnotationHandler
{
public void handleClass (String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)
{
assertNotNull (values);
for (Value v : values)
{
List list = (List)(v.getValue());
for (Object o : list)
{
AnnotationParser.ListValue lv = (AnnotationParser.ListValue)o;
List<Value> theValues = lv.getList();
for (Value vv : theValues)
{
if ("name".equals((String)vv.getName()))
{
if (!"apple".equals((String)vv.getValue()) && !"banana".equals((String)vv.getValue()))
fail("Wrong name "+vv.getName());
}
else if ("mappedName".equals((String)vv.getName()))
assertEquals("foo", (String)vv.getValue());
}
}
}
}
public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation,
List<Value> values)
{
}
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
{
}
}
parser.registerAnnotationHandler("javax.annotation.Resources", new ResourcesAnnotationHandler());
parser.registerAnnotationHandler("javax.annotation.Resource", new ResourceAnnotationHandler ());
parser.registerAnnotationHandler("javax.annotation.PostConstruct", new CallbackAnnotationHandler());
parser.registerAnnotationHandler("javax.annotation.PreDestroy", new CallbackAnnotationHandler());
parser.registerAnnotationHandler("javax.annotation.security.RunAs", new RunAsAnnotationHandler());
long start = System.currentTimeMillis();
parser.parse(classes, new ClassNameResolver ()
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
});
long end = System.currentTimeMillis();
System.err.println("Time to parse class: "+((end-start)));
public void testDeclareRoles ()
throws Exception
{
WebAppContext wac = new WebAppContext();
wac.setAttribute(MetaData.METADATA, new MetaData(wac));
ConstraintSecurityHandler sh = new ConstraintSecurityHandler();
wac.setSecurityHandler(sh);
sh.setRoles(new HashSet<String>(Arrays.asList(new String[]{"humpty", "dumpty"})));
DeclareRolesAnnotationHandler handler = new DeclareRolesAnnotationHandler(wac);
handler.doHandle(ServletC.class);
assertTrue(sh.getRoles().contains("alice"));
assertTrue(sh.getRoles().contains("humpty"));
assertTrue(sh.getRoles().contains("dumpty"));
}
}

View File

@ -6,6 +6,7 @@ import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.eclipse.jetty.annotations.AnnotationIntrospector;
import org.eclipse.jetty.annotations.AnnotationParser;
import org.eclipse.jetty.annotations.ClassNameResolver;
import org.eclipse.jetty.annotations.ResourceAnnotationHandler;
@ -13,6 +14,8 @@ import org.eclipse.jetty.annotations.ResourcesAnnotationHandler;
import org.eclipse.jetty.plus.annotation.Injection;
import org.eclipse.jetty.plus.annotation.InjectionCollection;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.MetaData;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.Test;
@ -21,40 +24,29 @@ import static org.junit.Assert.assertNotNull;
public class TestResourceAnnotations
{
@Test
public void testResourceAnnotations() throws Exception
public void testResourceAnnotations ()
throws Exception
{
Server server = new Server();
WebAppContext wac = new WebAppContext();
wac.setServer(server);
InjectionCollection injections = new InjectionCollection();
wac.setAttribute(InjectionCollection.INJECTION_COLLECTION, injections);
wac.setAttribute(MetaData.METADATA, new MetaData(wac));
InitialContext ic = new InitialContext();
Context comp = (Context)ic.lookup("java:comp");
Context env = comp.createSubcontext("env");
org.eclipse.jetty.plus.jndi.EnvEntry resourceA = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resA", new Integer(1000), false);
org.eclipse.jetty.plus.jndi.EnvEntry resourceB = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resB", new Integer(2000), false);
org.eclipse.jetty.plus.jndi.EnvEntry resourceA = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resA", 1000, false);
org.eclipse.jetty.plus.jndi.EnvEntry resourceB = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resB", 2000, false);
ArrayList<String> classNames = new ArrayList<String>();
classNames.add(ResourceA.class.getName());
classNames.add(ResourceB.class.getName());
AnnotationParser parser = new AnnotationParser();
AnnotationIntrospector parser = new AnnotationIntrospector();
ResourceAnnotationHandler handler = new ResourceAnnotationHandler(wac);
parser.registerAnnotationHandler("javax.annotation.Resource", handler);
parser.parse(classNames, new ClassNameResolver()
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
});
parser.registerHandler(handler);
parser.introspect(ResourceA.class);
parser.introspect(ResourceB.class);
//processing classA should give us these jndi name bindings:
// java:comp/env/myf
@ -82,7 +74,7 @@ public class TestResourceAnnotations
//only 1 field injection because the other has no Resource mapping
assertEquals(1, resBInjections.size());
Injection fi = resBInjections.get(0);
assertEquals ("f", fi.getFieldName());
assertEquals ("f", fi.getTarget().getName());
//3 method injections on class ResourceA, 4 field injections
List<Injection> resAInjections = injections.getInjections(ResourceA.class.getCanonicalName());
@ -126,9 +118,11 @@ public class TestResourceAnnotations
comp.destroySubcontext("env");
}
@Test
public void testResourcesAnnotation() throws Exception
public void testResourcesAnnotation ()
throws Exception
{
Server server = new Server();
WebAppContext wac = new WebAppContext();
@ -138,29 +132,15 @@ public class TestResourceAnnotations
InitialContext ic = new InitialContext();
Context comp = (Context)ic.lookup("java:comp");
Context env = comp.createSubcontext("env");
org.eclipse.jetty.plus.jndi.EnvEntry resourceA = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resA", 1000, false);
org.eclipse.jetty.plus.jndi.EnvEntry resourceB = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resB", 2000, false);
ArrayList<String> classNames = new ArrayList<String>();
classNames.add(ResourceA.class.getName());
classNames.add(ResourceB.class.getName());
AnnotationParser parser = new AnnotationParser();
org.eclipse.jetty.plus.jndi.EnvEntry resourceA = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resA", new Integer(1000), false);
org.eclipse.jetty.plus.jndi.EnvEntry resourceB = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resB", new Integer(2000), false);
AnnotationIntrospector introspector = new AnnotationIntrospector();
ResourcesAnnotationHandler handler = new ResourcesAnnotationHandler(wac);
parser.registerAnnotationHandler("javax.annotation.Resources", handler);
parser.parse(classNames, new ClassNameResolver()
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
});
introspector.registerHandler(handler);
introspector.introspect(ResourceA.class);
introspector.introspect(ResourceB.class);
assertEquals(resourceA.getObjectToBind(), env.lookup("peach"));
assertEquals(resourceB.getObjectToBind(), env.lookup("pear"));
}

View File

@ -58,7 +58,6 @@
<!-- Uncomment the following to set up a deployer that will -->
<!-- deploy webapps from a directory called webapps-plus. Note -->
<!-- that you will need to create this directory first! -->
<!--
<Ref id="DeploymentManager">
<Call name="addAppProvider">
<Arg>
@ -74,6 +73,5 @@
</Arg>
</Call>
</Ref>
-->
</Configure>

View File

@ -39,12 +39,9 @@ public class Injection
private String _jndiName;
private String _mappingName;
private Member _target;
private String _className;
private String _fieldName;
private String _methodName;
private String _paramCanonicalName;
private String _annotationResourceType;
private Class _paramClass;
private Class _resourceClass;
public Injection ()
{}
@ -58,35 +55,24 @@ public class Injection
return _targetClass;
}
public String getTargetClassName()
public Class getParamClass ()
{
return _className;
return _paramClass;
}
public String getFieldName ()
public Class getResourceClass ()
{
return _fieldName;
}
public String getMethodName ()
{
return _methodName;
}
public String getParamCanonicalName ()
{
return _paramCanonicalName;
return _resourceClass;
}
public boolean isField ()
{
return (_fieldName != null);
return (_target != null && _target instanceof Field);
}
public boolean isMethod ()
{
return (_methodName != null);
return (_target != null && _target instanceof Method);
}
/**
@ -126,59 +112,51 @@ public class Injection
return _target;
}
/**
* Set up an injection target that is a field
* @param className
* @param fieldName
*/
public void setTarget (String className, String fieldName, String annotationResourceType)
public void setTarget(Class clazz, Field field, Class resourceType)
{
_className = className;
_fieldName = fieldName;
_annotationResourceType = annotationResourceType;
_targetClass = clazz;
_target = field;
_resourceClass = resourceType;
}
public void setTarget(Class clazz, Method method, Class arg, Class resourceType)
{
_targetClass = clazz;
_target = method;
_resourceClass = resourceType;
_paramClass = arg;
}
public void setTarget (String className, String methodName, String paramCanonicalName, String annotationResourceType)
{
_className = className;
_methodName = methodName;
_paramCanonicalName = paramCanonicalName;
_annotationResourceType = annotationResourceType;
}
public void setTarget (Class clazz, String targetName, Class targetType)
public void setTarget (Class clazz, String target, Class resourceType)
{
_targetClass = clazz;
_resourceClass = resourceType;
//first look for a javabeans style setter matching the targetName
String setter = "set"+targetName.substring(0,1).toUpperCase()+targetName.substring(1);
String setter = "set"+target.substring(0,1).toUpperCase()+target.substring(1);
try
{
Log.debug("Looking for method for setter: "+setter+" with arg "+targetType);
_target = IntrospectionUtil.findMethod(clazz, setter, new Class[] {targetType}, true, false);
Log.debug("Looking for method for setter: "+setter+" with arg "+_resourceClass);
_target = IntrospectionUtil.findMethod(clazz, setter, new Class[] {_resourceClass}, true, false);
_targetClass = clazz;
_className = clazz.getCanonicalName();
_methodName = targetName;
_paramCanonicalName = targetType.getCanonicalName();
_paramClass = _resourceClass;
}
catch (NoSuchMethodException me)
{
//try as a field
try
{
_target = IntrospectionUtil.findField(clazz, targetName, targetType, true, false);
_targetClass = clazz;
_className = clazz.getCanonicalName();
_fieldName = targetName;
_target = IntrospectionUtil.findField(clazz, target, resourceType, true, false);
_targetClass = clazz;
}
catch (NoSuchFieldException fe)
{
throw new IllegalArgumentException("No such field or method "+targetName+" on class "+_targetClass);
throw new IllegalArgumentException("No such field or method "+target+" on class "+_targetClass);
}
}
}
}
/**
* Inject a value for a Resource from JNDI into an object
@ -186,19 +164,6 @@ public class Injection
*/
public void inject (Object injectable)
{
try
{
if (_target == null)
loadField();
if (_target == null)
loadMethod();
}
catch (Exception e)
{
throw new IllegalStateException (e);
}
if (_target != null)
{
if (_target instanceof Field)
@ -223,7 +188,7 @@ public class Injection
return context.lookup("java:comp/env/"+getJndiName());
}
/**
* Inject value from jndi into a field of an instance
@ -231,24 +196,19 @@ public class Injection
* @param injectable
*/
protected void injectField (Field field, Object injectable)
{
if (validateInjection())
{
try
{
try
{
boolean accessibility = field.isAccessible();
field.setAccessible(true);
field.set(injectable, lookupInjectedValue());
field.setAccessible(accessibility);
}
catch (Exception e)
{
Log.warn(e);
throw new IllegalStateException("Inject failed for field "+field.getName());
}
boolean accessibility = field.isAccessible();
field.setAccessible(true);
field.set(injectable, lookupInjectedValue());
field.setAccessible(accessibility);
}
catch (Exception e)
{
Log.warn(e);
throw new IllegalStateException("Inject failed for field "+field.getName());
}
else
throw new IllegalStateException ("Invalid injection for "+_className+"."+_fieldName);
}
/**
@ -258,100 +218,18 @@ public class Injection
*/
protected void injectMethod (Method method, Object injectable)
{
if (validateInjection())
try
{
try
{
boolean accessibility = method.isAccessible();
method.setAccessible(true);
method.invoke(injectable, new Object[] {lookupInjectedValue()});
method.setAccessible(accessibility);
}
catch (Exception e)
{
Log.warn(e);
throw new IllegalStateException("Inject failed for method "+method.getName());
}
boolean accessibility = method.isAccessible();
method.setAccessible(true);
method.invoke(injectable, new Object[] {lookupInjectedValue()});
method.setAccessible(accessibility);
}
catch (Exception e)
{
Log.warn(e);
throw new IllegalStateException("Inject failed for method "+method.getName());
}
else
throw new IllegalStateException("Invalid injection for "+_className+"."+_methodName);
}
protected void loadField()
throws ClassNotFoundException, NoSuchFieldException
{
if (_fieldName == null || _className == null)
return;
if (_targetClass == null)
_targetClass = Loader.loadClass(null, _className);
_target = _targetClass.getDeclaredField(_fieldName);
}
/**
* Load the target class and method.
* A valid injection target method only has 1 argument.
* @throws ClassNotFoundException
* @throws NoSuchMethodException
*/
protected void loadMethod ()
throws ClassNotFoundException, NoSuchMethodException
{
if (_methodName == null || _className == null)
return;
if (_targetClass == null)
_targetClass = Loader.loadClass(null, _className);
Class arg = TypeUtil.fromName(_paramCanonicalName);
if (arg == null)
arg = Loader.loadClass(null, _paramCanonicalName);
_target = _targetClass.getDeclaredMethod(_methodName, new Class[] {arg});
}
private boolean validateInjection ()
{
//check that if the injection came from an annotation, the type specified in the annotation
//is compatible with the field or method to inject
//JavaEE spec sec 5.2.4
if (_annotationResourceType != null)
{
if (_target == null)
return false;
try
{
Class<?> annotationType = TypeUtil.fromName(_annotationResourceType);
if (annotationType == null)
annotationType = Loader.loadClass(null, _annotationResourceType);
if (_target instanceof Field)
{
return ((Field)_target).getType().isAssignableFrom(annotationType);
}
else if (_target instanceof Method)
{
Class<?>[] args = ((Method)_target).getParameterTypes();
return args[0].isAssignableFrom(annotationType);
}
return false;
}
catch (Exception e)
{
Log.warn("Unable to verify injection for "+_className+"."+ (_fieldName==null?_methodName:_fieldName));
return false;
}
}
else
return true;
}
}

View File

@ -13,6 +13,8 @@
package org.eclipse.jetty.plus.annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@ -30,22 +32,22 @@ public class InjectionCollection
public static final String INJECTION_COLLECTION = "org.eclipse.jetty.injectionCollection";
private HashMap<String, List<Injection>> _injectionMap = new HashMap<String, List<Injection>>();//map of classname to injections
public void add (Injection injection)
{
if ((injection==null) || injection.getTargetClassName()==null)
if ((injection==null) || injection.getTargetClass()==null)
return;
if (Log.isDebugEnabled())
Log.debug("Adding injection for class="+(injection.getTargetClassName()+ " on a "+(injection.isField()?injection.getFieldName():injection.getMethodName())));
Log.debug("Adding injection for class="+(injection.getTargetClass()+ " on a "+(injection.getTarget().getName())));
List<Injection> injections = (List<Injection>)_injectionMap.get(injection.getTargetClassName());
List<Injection> injections = (List<Injection>)_injectionMap.get(injection.getTargetClass().getCanonicalName());
if (injections==null)
{
injections = new ArrayList<Injection>();
_injectionMap.put(injection.getTargetClassName(), injections);
_injectionMap.put(injection.getTargetClass().getCanonicalName(), injections);
}
injections.add(injection);
}
@ -57,14 +59,15 @@ public class InjectionCollection
return _injectionMap.get(className);
}
public Injection getInjection (String jndiName, String className, String fieldName)
public Injection getInjection (String jndiName, Class clazz, Field field)
{
if (fieldName == null || className == null)
if (field == null || clazz == null)
return null;
List<Injection> injections = getInjections(className);
List<Injection> injections = getInjections(clazz.getCanonicalName());
if (injections == null)
return null;
Iterator<Injection> itor = injections.iterator();
@ -72,19 +75,19 @@ public class InjectionCollection
while (itor.hasNext() && injection == null)
{
Injection i = itor.next();
if (fieldName.equals(i.getFieldName()))
if (i.isField() && field.getName().equals(i.getTarget().getName()))
injection = i;
}
return injection;
}
public Injection getInjection (String jndiName, String className, String methodName, String paramCanonicalName)
public Injection getInjection (String jndiName, Class clazz, Method method, Class paramClass)
{
if (className == null || methodName == null || paramCanonicalName == null)
if (clazz == null || method == null || paramClass == null)
return null;
List<Injection> injections = getInjections(className);
List<Injection> injections = getInjections(clazz.getCanonicalName());
if (injections == null)
return null;
Iterator<Injection> itor = injections.iterator();
@ -92,7 +95,7 @@ public class InjectionCollection
while (itor.hasNext() && injection == null)
{
Injection i = itor.next();
if (methodName.equals(i.getMethodName()) && paramCanonicalName.equals(i.getParamCanonicalName()))
if (i.isMethod() && i.getTarget().getName().equals(method.getName()) && paramClass.equals(i.getParamClass()))
injection = i;
}
@ -101,7 +104,6 @@ public class InjectionCollection
public void inject (Object injectable)
throws Exception
{
if (injectable==null)
return;

View File

@ -13,6 +13,7 @@
package org.eclipse.jetty.plus.annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@ -93,8 +94,8 @@ public abstract class LifeCycleCallback
public void callback (Object instance)
throws Exception
public void callback (Object instance)
throws SecurityException, NoSuchMethodException, ClassNotFoundException, IllegalArgumentException, IllegalAccessException, InvocationTargetException
{
if (_target == null)
{

View File

@ -101,14 +101,16 @@ public class LifeCycleCallbackCollection
Class clazz = o.getClass();
List<LifeCycleCallback> callbacks = postConstructCallbacksMap.get(clazz.getName());
if (callbacks == null)
return;
for (int i=0;i<callbacks.size();i++)
{
((LifeCycleCallback)callbacks.get(i)).callback(o);
}
}
/**
* Call the method, if one exists, that is annotated with PreDestroy

View File

@ -13,6 +13,7 @@
package org.eclipse.jetty.plus.annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@ -45,8 +46,8 @@ public class PostConstructCallback extends LifeCycleCallback
}
public void callback (Object instance)
throws Exception
public void callback (Object instance)
throws SecurityException, IllegalArgumentException, NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException
{
super.callback(instance);
}

View File

@ -53,7 +53,7 @@ public class RunAs
}
public void setRunAs (ServletHolder holder, SecurityHandler securityHandler)
public void setRunAs (ServletHolder holder)
throws ServletException
{
if (holder == null)
@ -61,6 +61,11 @@ public class RunAs
String className = holder.getClassName();
if (className.equals(_className))
holder.setRunAsRole(_roleName);
{
//Only set the RunAs if it has not already been set, presumably by web/web-fragment.xml
if (holder.getRegistration().getRunAsRole() == null)
holder.getRegistration().setRunAsRole(_roleName);
}
}
}

View File

@ -20,6 +20,7 @@ import javax.servlet.ServletException;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.webapp.WebAppContext;
/**
@ -31,6 +32,7 @@ public class RunAsCollection
{
public static final String RUNAS_COLLECTION = "org.eclipse.jetty.runAsCollection";
private HashMap _runAsMap = new HashMap();//map of classname to run-as
public void add (RunAs runAs)
@ -49,32 +51,23 @@ public class RunAsCollection
if (o==null)
return null;
if (!(o instanceof ServletHolder))
return null;
ServletHolder holder = (ServletHolder)o;
String className = holder.getClassName();
return (RunAs)_runAsMap.get(className);
return (RunAs)_runAsMap.get(o.getClass().getCanonicalName());
}
public void setRunAs(Object o, SecurityHandler securityHandler)
public void setRunAs(Object o)
throws ServletException
{
if (o==null)
if (o == null)
return;
if (!(o instanceof ServletHolder))
if (!ServletHolder.class.isAssignableFrom(o.getClass()))
return;
ServletHolder holder = (ServletHolder)o;
String className = holder.getClassName();
RunAs runAs = (RunAs)_runAsMap.get(className);
RunAs runAs = (RunAs)_runAsMap.get(o.getClass().getName());
if (runAs == null)
return;
runAs.setRunAs(holder, securityHandler);
runAs.setRunAs((ServletHolder)o);
}
}

View File

@ -70,54 +70,5 @@ public class ServletHandler extends org.eclipse.jetty.servlet.ServletHandler
this._injections = injections;
}
/**
* @see org.eclipse.jetty.servlet.ServletHandler#customizeFilter(javax.servlet.Filter)
*/
public Filter customizeFilter(Filter filter) throws Exception
{
if (_injections != null)
_injections.inject(filter);
if (_callbacks != null)
_callbacks.callPostConstructCallback(filter);
return super.customizeFilter(filter);
}
/**
* @see org.eclipse.jetty.servlet.ServletHandler#customizeServlet(javax.servlet.Servlet)
*/
public Servlet customizeServlet(Servlet servlet) throws Exception
{
if (_injections != null)
_injections.inject(servlet);
if (_callbacks != null)
_callbacks.callPostConstructCallback(servlet);
return super.customizeServlet(servlet);
}
/**
* @see org.eclipse.jetty.servlet.ServletHandler#customizeFilterDestroy(Filter)
*/
public Filter customizeFilterDestroy(Filter filter) throws Exception
{
if (_callbacks != null)
_callbacks.callPreDestroyCallback(filter);
return super.customizeFilterDestroy(filter);
}
/**
* @see org.eclipse.jetty.servlet.ServletHandler#customizeServletDestroy(Servlet)
*/
public Servlet customizeServletDestroy(Servlet servlet) throws Exception
{
if (_callbacks != null)
_callbacks.callPreDestroyCallback(servlet);
return super.customizeServletDestroy(servlet);
}
}

View File

@ -1,508 +0,0 @@
// ========================================================================
// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.plus.webapp;
import java.util.EventListener;
import java.util.Iterator;
import javax.servlet.UnavailableException;
import org.eclipse.jetty.plus.annotation.Injection;
import org.eclipse.jetty.plus.annotation.InjectionCollection;
import org.eclipse.jetty.plus.annotation.LifeCycleCallback;
import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection;
import org.eclipse.jetty.plus.annotation.PostConstructCallback;
import org.eclipse.jetty.plus.annotation.PreDestroyCallback;
import org.eclipse.jetty.plus.annotation.RunAsCollection;
import org.eclipse.jetty.plus.servlet.ServletHandler;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebXmlProcessor;
import org.eclipse.jetty.webapp.WebXmlProcessor.Descriptor;
import org.eclipse.jetty.xml.XmlParser;
/**
* Configuration
*
*
*/
public abstract class AbstractConfiguration implements Configuration
{
public abstract void bindEnvEntry (WebAppContext context, String name, Object value) throws Exception;
public abstract void bindResourceRef (WebAppContext context, String name, Class type) throws Exception;
public abstract void bindResourceEnvRef (WebAppContext context, String name, Class type) throws Exception;
public abstract void bindUserTransaction (WebAppContext context) throws Exception;
public abstract void bindMessageDestinationRef (WebAppContext context, String name, Class type) throws Exception;
public class PlusWebXmlProcessor
{
WebAppContext _context;
public PlusWebXmlProcessor (WebAppContext context)
{
_context = context;
}
public void process (Descriptor d)
throws Exception
{
if (d != null)
process(d.getRoot());
}
public void process (XmlParser.Node root)
throws Exception
{
if (root == null)
return;
Iterator iter = root.iterator();
XmlParser.Node node = null;
while (iter.hasNext())
{
try
{
Object o = iter.next();
if (!(o instanceof XmlParser.Node)) continue;
node = (XmlParser.Node) o;
String name = node.getTag();
initWebXmlElement(name, node);
}
catch (ClassNotFoundException e)
{
throw e;
}
catch (Exception e)
{
Log.warn("Configuration problem at " + node, e);
throw new UnavailableException("Configuration problem");
}
}
}
protected void initWebXmlElement(String element,XmlParser.Node node) throws Exception
{
if ("env-entry".equals(element))
{
initEnvEntry (node);
}
else if ("resource-ref".equals(element))
{
//resource-ref entries are ONLY for connection factories
//the resource-ref says how the app will reference the jndi lookup relative
//to java:comp/env, but it is up to the deployer to map this reference to
//a real resource in the environment. At the moment, we insist that the
//jetty.xml file name of the resource has to be exactly the same as the
//name in web.xml deployment descriptor, but it shouldn't have to be
initResourceRef(node);
}
else if ("resource-env-ref".equals(element))
{
//resource-env-ref elements are a non-connection factory type of resource
//the app looks them up relative to java:comp/env
//again, need a way for deployer to link up app naming to real naming.
//Again, we insist now that the name of the resource in jetty.xml is
//the same as web.xml
initResourceEnvRef(node);
}
else if ("message-destination-ref".equals(element))
{
initMessageDestinationRef(node);
}
else if ("post-construct".equals(element))
{
//post-construct is the name of a class and method to call after all
//resources have been setup but before the class is put into use
initPostConstruct(node);
}
else if ("pre-destroy".equals(element))
{
//pre-destroy is the name of a class and method to call just as
//the instance is being destroyed
initPreDestroy(node);
}
}
/**
* JavaEE 5.4.1.3
*
*
* @param node
* @throws Exception
*/
protected void initEnvEntry (XmlParser.Node node)
throws Exception
{
String name=node.getString("env-entry-name",false,true);
String type = node.getString("env-entry-type",false,true);
String valueStr = node.getString("env-entry-value",false,true);
//if there's no value there's no point in making a jndi entry
//nor processing injection entries
if (valueStr==null || valueStr.equals(""))
{
Log.warn("No value for env-entry-name "+name);
return;
}
//the javaee_5.xsd says that the env-entry-type is optional
//if there is an <injection> element, because you can get
//type from the element, but what to do if there is more
//than one <injection> element, do you just pick the type
//of the first one?
//check for <injection> elements
initInjection (node, name, TypeUtil.fromName(type));
//bind the entry into jndi
Object value = TypeUtil.valueOf(type,valueStr);
bindEnvEntry(_context, name, value);
}
/**
* Common Annotations Spec section 2.3:
* resource-ref is for:
* - javax.sql.DataSource
* - javax.jms.ConnectionFactory
* - javax.jms.QueueConnectionFactory
* - javax.jms.TopicConnectionFactory
* - javax.mail.Session
* - java.net.URL
* - javax.resource.cci.ConnectionFactory
* - org.omg.CORBA_2_3.ORB
* - any other connection factory defined by a resource adapter
* @param node
* @throws Exception
*/
protected void initResourceRef (XmlParser.Node node)
throws Exception
{
String jndiName = node.getString("res-ref-name",false,true);
String type = node.getString("res-type", false, true);
String auth = node.getString("res-auth", false, true);
String shared = node.getString("res-sharing-scope", false, true);
//check for <injection> elements
Class typeClass = TypeUtil.fromName(type);
if (typeClass==null)
typeClass = _context.loadClass(type);
initInjection (node, jndiName, typeClass);
bindResourceRef(_context, jndiName, typeClass);
}
/**
* Common Annotations Spec section 2.3:
* resource-env-ref is for:
* - javax.transaction.UserTransaction
* - javax.resource.cci.InteractionSpec
* - anything else that is not a connection factory
* @param node
* @throws Exception
*/
protected void initResourceEnvRef (XmlParser.Node node)
throws Exception
{
String jndiName = node.getString("resource-env-ref-name",false,true);
String type = node.getString("resource-env-ref-type", false, true);
//check for <injection> elements
//JavaEE Spec sec 5.7.1.3 says the resource-env-ref-type
//is mandatory, but the schema says it is optional!
Class typeClass = TypeUtil.fromName(type);
if (typeClass==null)
typeClass = _context.loadClass(type);
initInjection (node, jndiName, typeClass);
bindResourceEnvRef(_context, jndiName, typeClass);
}
/**
* Common Annotations Spec section 2.3:
* message-destination-ref is for:
* - javax.jms.Queue
* - javax.jms.Topic
* @param node
* @throws Exception
*/
protected void initMessageDestinationRef (XmlParser.Node node)
throws Exception
{
String jndiName = node.getString("message-destination-ref-name",false,true);
String type = node.getString("message-destination-type",false,true);
String usage = node.getString("message-destination-usage",false,true);
Class typeClass = TypeUtil.fromName(type);
if (typeClass==null)
typeClass = _context.loadClass(type);
initInjection(node, jndiName, typeClass);
bindMessageDestinationRef(_context, jndiName, typeClass);
}
/**
* Process &lt;post-construct&gt;
* @param node
*/
protected void initPostConstruct(XmlParser.Node node)
{
String className = node.getString("lifecycle-callback-class", false, true);
String methodName = node.getString("lifecycle-callback-method", false, true);
if (className==null || className.equals(""))
{
Log.warn("No lifecycle-callback-class specified");
return;
}
if (methodName==null || methodName.equals(""))
{
Log.warn("No lifecycle-callback-method specified for class "+className);
return;
}
LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)_context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
try
{
Class clazz = _context.loadClass(className);
LifeCycleCallback callback = new PostConstructCallback();
callback.setTarget(clazz, methodName);
callbacks.add(callback);
}
catch (ClassNotFoundException e)
{
Log.warn("Couldn't load post-construct target class "+className);
}
}
/**
* Process &lt;pre-destroy&gt;
* @param node
*/
protected void initPreDestroy(XmlParser.Node node)
{
String className = node.getString("lifecycle-callback-class", false, true);
String methodName = node.getString("lifecycle-callback-method", false, true);
if (className==null || className.equals(""))
{
Log.warn("No lifecycle-callback-class specified for pre-destroy");
return;
}
if (methodName==null || methodName.equals(""))
{
Log.warn("No lifecycle-callback-method specified for pre-destroy class "+className);
return;
}
LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)_context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
try
{
Class clazz = _context.loadClass(className);
LifeCycleCallback callback = new PreDestroyCallback();
callback.setTarget(clazz, methodName);
callbacks.add(callback);
}
catch (ClassNotFoundException e)
{
Log.warn("Couldn't load pre-destory target class "+className);
}
}
/**
* Iterate over the &lt;injection-target&gt; entries for a node
*
* @param node
* @param jndiName
* @param valueClass
*/
protected void initInjection (XmlParser.Node node, String jndiName, Class valueClass)
{
Iterator itor = node.iterator("injection-target");
while(itor.hasNext())
{
XmlParser.Node injectionNode = (XmlParser.Node)itor.next();
String targetClassName = injectionNode.getString("injection-target-class", false, true);
String targetName = injectionNode.getString("injection-target-name", false, true);
if ((targetClassName==null) || targetClassName.equals(""))
{
Log.warn("No classname found in injection-target");
continue;
}
if ((targetName==null) || targetName.equals(""))
{
Log.warn("No field or method name in injection-target");
continue;
}
InjectionCollection injections = (InjectionCollection)_context.getAttribute(InjectionCollection.INJECTION_COLLECTION);
// comments in the javaee_5.xsd file specify that the targetName is looked
// for first as a java bean property, then if that fails, as a field
try
{
Class clazz = _context.loadClass(targetClassName);
Injection injection = new Injection();
injection.setJndiName(jndiName);
injection.setTarget(clazz, targetName, valueClass);
injections.add(injection);
}
catch (ClassNotFoundException e)
{
Log.warn("Couldn't load injection target class "+targetClassName);
}
}
}
}
public void preConfigure (WebAppContext context)
throws Exception
{
//set up our special ServletHandler to remember injections and lifecycle callbacks
ServletHandler servletHandler = new ServletHandler();
SecurityHandler securityHandler = context.getSecurityHandler();
org.eclipse.jetty.servlet.ServletHandler existingHandler = context.getServletHandler();
servletHandler.setFilters(existingHandler.getFilters());
servletHandler.setFilterMappings(existingHandler.getFilterMappings());
servletHandler.setServlets(existingHandler.getServlets());
servletHandler.setServletMappings(existingHandler.getServletMappings());
context.setServletHandler(servletHandler);
securityHandler.setHandler(servletHandler);
LifeCycleCallbackCollection callbacks = new LifeCycleCallbackCollection();
context.setAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION, callbacks);
InjectionCollection injections = new InjectionCollection();
context.setAttribute(InjectionCollection.INJECTION_COLLECTION, injections);
RunAsCollection runAsCollection = new RunAsCollection();
context.setAttribute(RunAsCollection.RUNAS_COLLECTION, runAsCollection);
}
public void postConfigure(WebAppContext context) throws Exception
{
context.setAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION, null);
context.setAttribute(InjectionCollection.INJECTION_COLLECTION, null);
context.setAttribute(RunAsCollection.RUNAS_COLLECTION, null);
}
public void configure (WebAppContext context)
throws Exception
{
bindUserTransaction(context);
WebXmlProcessor webXmlProcessor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR);
if (webXmlProcessor == null)
throw new IllegalStateException ("No processor for web xml");
//TODO: When webdefaults.xml, web.xml, fragments and web-override.xml are merged into an effective web.xml this
//will change
PlusWebXmlProcessor plusProcessor = new PlusWebXmlProcessor(context);
plusProcessor.process(webXmlProcessor.getWebDefault());
plusProcessor.process(webXmlProcessor.getWebXml());
//Process plus-elements of each descriptor
for (Descriptor frag: webXmlProcessor.getFragments())
{
plusProcessor.process(frag);
}
//process the override-web.xml descriptor
plusProcessor.process(webXmlProcessor.getOverrideWeb());
//configure injections and callbacks to be called by the FilterHolder and ServletHolder
//when they lazily instantiate the Filter/Servlet.
((ServletHandler)context.getServletHandler()).setInjections((InjectionCollection)context.getAttribute(InjectionCollection.INJECTION_COLLECTION));
((ServletHandler)context.getServletHandler()).setCallbacks((LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION));
//do any injects on the listeners that were created and then
//also callback any postConstruct lifecycle methods
injectAndCallPostConstructCallbacks(context);
}
public void deconfigure (WebAppContext context)
throws Exception
{
//call any preDestroy methods on the listeners
callPreDestroyCallbacks(context);
}
protected void injectAndCallPostConstructCallbacks(WebAppContext context)
throws Exception
{
InjectionCollection injections = (InjectionCollection)context.getAttribute(InjectionCollection.INJECTION_COLLECTION);
RunAsCollection runAsCollection = (RunAsCollection)context.getAttribute(RunAsCollection.RUNAS_COLLECTION);
LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
SecurityHandler securityHandler = context.getSecurityHandler();
//look thru the servlets to apply any runAs annotations
//NOTE: that any run-as in web.xml will already have been applied
if (runAsCollection != null)
{
ServletHolder[] holders = context.getServletHandler().getServlets();
for (int i=0;holders!=null && i<holders.length;i++)
{
runAsCollection.setRunAs(holders[i], securityHandler);
}
}
EventListener[] listeners = context.getEventListeners();
for (int i=0;listeners!=null && i<listeners.length;i++)
{
if (injections != null)
injections.inject(listeners[i]);
if (callbacks != null)
callbacks.callPostConstructCallback(listeners[i]);
}
}
protected void callPreDestroyCallbacks (WebAppContext context)
throws Exception
{
LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
if (callbacks != null)
{
EventListener[] listeners = context.getEventListeners();
for (int i=0; listeners!=null && i<listeners.length;i++)
{
callbacks.callPreDestroyCallback(listeners[i]);
}
}
}
}

View File

@ -19,14 +19,14 @@ import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import org.eclipse.jetty.jndi.NamingUtil;
import org.eclipse.jetty.plus.jndi.EnvEntry;
import org.eclipse.jetty.plus.jndi.Link;
import org.eclipse.jetty.plus.jndi.NamingEntry;
import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
import org.eclipse.jetty.plus.annotation.InjectionCollection;
import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection;
import org.eclipse.jetty.plus.annotation.RunAsCollection;
import org.eclipse.jetty.plus.jndi.Transaction;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.webapp.FragmentDescriptor;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.MetaData;
/**
@ -34,80 +34,71 @@ import org.eclipse.jetty.webapp.WebAppContext;
*
*
*/
public class Configuration extends AbstractConfiguration
public class Configuration implements org.eclipse.jetty.webapp.Configuration
{
private Integer _key;
/**
* @see AbstractConfiguration#bindEnvEntry(WebAppContext, String, Object)
* @param name
* @param value
* @throws Exception
*/
public void bindEnvEntry(WebAppContext context, String name, Object value) throws Exception
{
InitialContext ic = null;
boolean bound = false;
//check to see if we bound a value and an EnvEntry with this name already
//when we processed the server and the webapp's naming environment
//@see EnvConfiguration.bindEnvEntries()
ic = new InitialContext();
try
{
NamingEntry ne = (NamingEntry)ic.lookup("java:comp/env/"+NamingEntryUtil.makeNamingEntryName(ic.getNameParser(""), name));
if (ne!=null && ne instanceof EnvEntry)
{
EnvEntry ee = (EnvEntry)ne;
bound = ee.isOverrideWebXml();
}
}
catch (NameNotFoundException e)
{
bound = false;
}
if (!bound)
{
//either nothing was bound or the value from web.xml should override
Context envCtx = (Context)ic.lookup("java:comp/env");
NamingUtil.bind(envCtx, name, value);
}
public void preConfigure (WebAppContext context)
throws Exception
{
LifeCycleCallbackCollection callbacks = new LifeCycleCallbackCollection();
context.setAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION, callbacks);
InjectionCollection injections = new InjectionCollection();
context.setAttribute(InjectionCollection.INJECTION_COLLECTION, injections);
RunAsCollection runAsCollection = new RunAsCollection();
context.setAttribute(RunAsCollection.RUNAS_COLLECTION, runAsCollection);
WebAppDecorator decorator = new WebAppDecorator(context);
context.setDecorator(decorator);
}
/**
* Bind a resource reference.
*
* If a resource reference with the same name is in a jetty-env.xml
* file, it will already have been bound.
*
* @see AbstractConfiguration#bindResourceRef(WebAppContext, String, Class)
* @param name
* @throws Exception
*/
public void bindResourceRef(WebAppContext context, String name, Class typeClass)
public void configure (WebAppContext context)
throws Exception
{
bindEntry(context, name, typeClass);
}
bindUserTransaction(context);
MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA);
if (metaData == null)
throw new IllegalStateException ("No metadata");
metaData.addDescriptorProcessor(new PlusDescriptorProcessor());
/*
* THE PROCESSING IS NOW DONE IN metadata.resolve ()
PlusDescriptorProcessor plusProcessor = new PlusDescriptorProcessor(metaData);
plusProcessor.process(metaData.getWebDefault());
plusProcessor.process(metaData.getWebXml());
/**
* @see AbstractConfiguration#bindResourceEnvRef(WebAppContext, String, Class)
* @param name
* @throws Exception
*/
public void bindResourceEnvRef(WebAppContext context, String name, Class typeClass)
throws Exception
{
bindEntry(context, name, typeClass);
//Process plus-elements of each descriptor
for (FragmentDescriptor frag: metaData.getOrderedFragments())
{
plusProcessor.process(frag);
}
//process the override-web.xml descriptor
plusProcessor.process(metaData.getOverrideWeb());
*/
}
public void postConfigure(WebAppContext context) throws Exception
{
//lock this webapp's java:comp namespace as per J2EE spec
lockCompEnv(context);
public void bindMessageDestinationRef(WebAppContext context, String name, Class typeClass)
context.setAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION, null);
context.setAttribute(InjectionCollection.INJECTION_COLLECTION, null);
context.setAttribute(RunAsCollection.RUNAS_COLLECTION, null);
}
public void deconfigure (WebAppContext context)
throws Exception
{
bindEntry(context, name, typeClass);
unlockCompEnv(context);
_key = null;
}
public void bindUserTransaction (WebAppContext context)
@ -123,40 +114,8 @@ public class Configuration extends AbstractConfiguration
}
}
public void preConfigure (WebAppContext context)
throws Exception
{
super.preConfigure(context);
}
public void configure (WebAppContext context)
throws Exception
{
super.configure (context);
}
public void postConfigure (WebAppContext context)
throws Exception
{
//lock this webapp's java:comp namespace as per J2EE spec
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(context.getClassLoader());
lockCompEnv(context);
Thread.currentThread().setContextClassLoader(oldLoader);
}
public void deconfigure (WebAppContext context) throws Exception
{
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(context.getClassLoader());
unlockCompEnv(context);
_key = null;
Thread.currentThread().setContextClassLoader(oldLoader);
super.deconfigure (context);
}
protected void lockCompEnv (WebAppContext wac)
throws Exception
{
@ -180,86 +139,20 @@ public class Configuration extends AbstractConfiguration
throws Exception
{
if (_key!=null)
{ClassLoader old_loader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(wac.getClassLoader());
try
{
Context context = new InitialContext();
Context compCtx = (Context)context.lookup("java:comp");
compCtx.addToEnvironment("org.eclipse.jndi.unlock", _key);
}
finally
{
Thread.currentThread().setContextClassLoader(old_loader);
}
}
}
ClassLoader old_loader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(wac.getClassLoader());
/**
* Bind a resource with the given name from web.xml of the given type
* with a jndi resource from either the server or the webapp's naming
* environment.
*
* As the servlet spec does not cover the mapping of names in web.xml with
* names from the execution environment, jetty uses the concept of a Link, which is
* a subclass of the NamingEntry class. A Link defines a mapping of a name
* from web.xml with a name from the execution environment (ie either the server or the
* webapp's naming environment).
*
* @param name name of the resource from web.xml
* @param typeClass
* @throws Exception
*/
private void bindEntry (WebAppContext context, String name, Class typeClass)
throws Exception
{
String nameInEnvironment = name;
boolean bound = false;
//check if the name in web.xml has been mapped to something else
//check a context-specific naming environment first
Object scope = context;
NamingEntry ne = NamingEntryUtil.lookupNamingEntry(scope, name);
if (ne!=null && (ne instanceof Link))
{
//if we found a mapping, get out name it is mapped to in the environment
nameInEnvironment = (String)((Link)ne).getObjectToBind();
Link l = (Link)ne;
try
{
Context context = new InitialContext();
Context compCtx = (Context)context.lookup("java:comp");
compCtx.addToEnvironment("org.eclipse.jndi.unlock", _key);
}
finally
{
Thread.currentThread().setContextClassLoader(old_loader);
}
}
//try finding that mapped name in the webapp's environment first
scope = context;
bound = NamingEntryUtil.bindToENC(scope, name, nameInEnvironment);
if (bound)
return;
//try the server's environment
scope = context.getServer();
bound = NamingEntryUtil.bindToENC(scope, name, nameInEnvironment);
if (bound)
return;
//try the jvm environment
bound = NamingEntryUtil.bindToENC(null, name, nameInEnvironment);
if (bound)
return;
//There is no matching resource so try a default name.
//The default name syntax is: the [res-type]/default
//eg javax.sql.DataSource/default
nameInEnvironment = typeClass.getName()+"/default";
//First try the server scope
NamingEntry defaultNE = NamingEntryUtil.lookupNamingEntry(context.getServer(), nameInEnvironment);
if (defaultNE==null)
defaultNE = NamingEntryUtil.lookupNamingEntry(null, nameInEnvironment);
if (defaultNE!=null)
defaultNE.bindToENC(name);
else
throw new IllegalStateException("Nothing to bind for name "+nameInEnvironment);
}
}

View File

@ -0,0 +1,778 @@
// ========================================================================
// Copyright (c) 2006-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.plus.webapp;
import java.util.Iterator;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import org.eclipse.jetty.jndi.NamingUtil;
import org.eclipse.jetty.plus.annotation.Injection;
import org.eclipse.jetty.plus.annotation.InjectionCollection;
import org.eclipse.jetty.plus.annotation.LifeCycleCallback;
import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection;
import org.eclipse.jetty.plus.annotation.PostConstructCallback;
import org.eclipse.jetty.plus.annotation.PreDestroyCallback;
import org.eclipse.jetty.plus.jndi.EnvEntry;
import org.eclipse.jetty.plus.jndi.Link;
import org.eclipse.jetty.plus.jndi.NamingEntry;
import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.webapp.Descriptor;
import org.eclipse.jetty.webapp.FragmentDescriptor;
import org.eclipse.jetty.webapp.IterativeDescriptorProcessor;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.MetaData;
import org.eclipse.jetty.webapp.MetaData.Origin;
import org.eclipse.jetty.xml.XmlParser;
/**
* PlusDescriptorProcessor
*
*
*/
public class PlusDescriptorProcessor extends IterativeDescriptorProcessor
{
protected WebAppContext _context;
protected MetaData _metaData;
public PlusDescriptorProcessor ()
{
try
{
registerVisitor("env-entry", getClass().getDeclaredMethod("visitEnvEntry", __signature));
registerVisitor("resource-ref", getClass().getDeclaredMethod("visitResourceRef", __signature));
registerVisitor("resource-env-ref", getClass().getDeclaredMethod("visitResourceEnvRef", __signature));
registerVisitor("message-destination-ref", getClass().getDeclaredMethod("visitMessageDestinationRef", __signature));
registerVisitor("post-construct", getClass().getDeclaredMethod("visitPostConstruct", __signature));
registerVisitor("pre-destroy", getClass().getDeclaredMethod("visitPreDestroy", __signature));
}
catch (Exception e)
{
throw new IllegalStateException(e);
}
}
/**
* @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#start(org.eclipse.jetty.webapp.Descriptor)
*/
public void start(Descriptor descriptor)
{
_metaData = descriptor.getMetaData();
_context = _metaData.getContext();
}
/**
* @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#end(org.eclipse.jetty.webapp.Descriptor)
*/
public void end(Descriptor descriptor)
{
_metaData = null;
_context = null;
}
/**
* JavaEE 5.4.1.3
*
* @param node
* @throws Exception
*/
public void visitEnvEntry (Descriptor descriptor, XmlParser.Node node)
throws Exception
{
String name=node.getString("env-entry-name",false,true);
String type = node.getString("env-entry-type",false,true);
String valueStr = node.getString("env-entry-value",false,true);
//if there's no value there's no point in making a jndi entry
//nor processing injection entries
if (valueStr==null || valueStr.equals(""))
{
Log.warn("No value for env-entry-name "+name);
return;
}
Origin o = _metaData.getOrigin("env-entry."+name);
switch (o)
{
case NotSet:
{
//no descriptor has configured an env-entry of this name previously
_metaData.setOrigin("env-entry."+name, descriptor);
//the javaee_5.xsd says that the env-entry-type is optional
//if there is an <injection> element, because you can get
//type from the element, but what to do if there is more
//than one <injection> element, do you just pick the type
//of the first one?
addInjections (descriptor, node, name, TypeUtil.fromName(type));
Object value = TypeUtil.valueOf(type,valueStr);
bindEnvEntry(name, value);
break;
}
case WebXml:
case WebDefaults:
case WebOverride:
{
//ServletSpec 3.0 p75. web.xml (or web-override/web-defaults) declared
//the env-entry. A fragment is not allowed to change that, except unless
//the web.xml did not declare any injections.
if (!(descriptor instanceof FragmentDescriptor))
{
//We're processing web-defaults, web.xml or web-override. Any of them can
//set or change the env-entry.
_metaData.setOrigin("env-entry."+name, descriptor);
addInjections (descriptor, node, name, TypeUtil.fromName(type));
Object value = TypeUtil.valueOf(type,valueStr);
bindEnvEntry(name, value);
}
else
{
//A web.xml declared the env-entry. Check to see if any injections have been
//declared for it. If it was declared in web.xml then don't merge any injections.
//If it was declared in a web-fragment, then we can keep merging fragments.
Descriptor d = _metaData.getOriginDescriptor("env-entry."+name+".injection");
if (d==null || d instanceof FragmentDescriptor)
addInjections(descriptor, node, name, TypeUtil.fromName(type));
}
break;
}
case WebFragment:
{
//ServletSpec p.75. No declaration in web.xml, but in multiple web-fragments. Error.
throw new IllegalStateException("Conflicting env-entry "+name+" in "+descriptor.getResource());
}
}
}
/**
* Common Annotations Spec section 2.3:
* resource-ref is for:
* - javax.sql.DataSource
* - javax.jms.ConnectionFactory
* - javax.jms.QueueConnectionFactory
* - javax.jms.TopicConnectionFactory
* - javax.mail.Session
* - java.net.URL
* - javax.resource.cci.ConnectionFactory
* - org.omg.CORBA_2_3.ORB
* - any other connection factory defined by a resource adapter
*
* TODO
* If web.xml contains a resource-ref with injection targets, all resource-ref entries
* of the same name are ignored in web fragments. If web.xml does not contain any
* injection-targets, then they are merged from all the fragments.
* If web.xml does not contain a resource-ref element of same name, but 2 fragments
* declare the same name it is an error.
* resource-ref entries are ONLY for connection factories
* the resource-ref says how the app will reference the jndi lookup relative
* to java:comp/env, but it is up to the deployer to map this reference to
* a real resource in the environment. At the moment, we insist that the
* jetty.xml file name of the resource has to be exactly the same as the
* name in web.xml deployment descriptor, but it shouldn't have to be
*
* @param node
* @throws Exception
*/
public void visitResourceRef (Descriptor descriptor, XmlParser.Node node)
throws Exception
{
String jndiName = node.getString("res-ref-name",false,true);
String type = node.getString("res-type", false, true);
String auth = node.getString("res-auth", false, true);
String shared = node.getString("res-sharing-scope", false, true);
Origin o = _metaData.getOrigin("resource-ref."+jndiName);
switch (o)
{
case NotSet:
{
//No descriptor or annotation previously declared a resource-ref of this name.
_metaData.setOrigin("resource-ref."+jndiName, descriptor);
//check for <injection> elements
Class typeClass = TypeUtil.fromName(type);
if (typeClass==null)
typeClass = _context.loadClass(type);
addInjections(descriptor, node, jndiName, typeClass);
bindResourceRef(jndiName, typeClass);
break;
}
case WebXml:
case WebDefaults:
case WebOverride:
{
//A web xml previously declared the resource-ref.
if (!(descriptor instanceof FragmentDescriptor))
{
//We're processing web-defaults, web.xml or web-override. Any of them can
//set or change the resource-ref.
_metaData.setOrigin("resource-ref."+jndiName, descriptor);
//check for <injection> elements
Class typeClass = TypeUtil.fromName(type);
if (typeClass==null)
typeClass = _context.loadClass(type);
addInjections(descriptor, node, jndiName, typeClass);
//bind the entry into jndi
bindResourceRef(jndiName, typeClass);
}
else
{
//A web xml declared the resource-ref and we're processing a
//web-fragment. Check to see if any injections were declared for it by web.xml.
//If any injection was declared in web.xml then don't merge any injections.
//If it was declared in a web-fragment, then we can keep merging fragments.
Descriptor d = _metaData.getOriginDescriptor("resource-ref."+jndiName+".injection");
if (d==null || d instanceof FragmentDescriptor)
{
Class typeClass = TypeUtil.fromName(type);
if (typeClass==null)
typeClass = _context.loadClass(type);
addInjections(descriptor, node, jndiName, TypeUtil.fromName(type));
}
}
break;
}
case WebFragment:
{
//ServletSpec p.75. No declaration of resource-ref in web xml, but in multiple web-fragments. Error.
throw new IllegalStateException("Conflicting resource-ref "+jndiName+" in "+descriptor.getResource());
}
}
}
/**
* Common Annotations Spec section 2.3:
* resource-env-ref is for:
* - javax.transaction.UserTransaction
* - javax.resource.cci.InteractionSpec
* - anything else that is not a connection factory
*
* @param node
* @throws Exception
*/
public void visitResourceEnvRef (Descriptor descriptor, XmlParser.Node node)
throws Exception
{
String jndiName = node.getString("resource-env-ref-name",false,true);
String type = node.getString("resource-env-ref-type", false, true);
Origin o = _metaData.getOrigin("resource-env-ref."+jndiName);
switch (o)
{
case NotSet:
{
//First declaration of resource-env-ref with this jndiName
//JavaEE Spec sec 5.7.1.3 says the resource-env-ref-type
//is mandatory, but the schema says it is optional!
Class typeClass = TypeUtil.fromName(type);
if (typeClass==null)
typeClass = _context.loadClass(type);
addInjections (descriptor, node, jndiName, typeClass);
bindResourceEnvRef(jndiName, typeClass);
break;
}
case WebXml:
case WebDefaults:
case WebOverride:
{
//A resource-env-ref of this name has been declared first in a web xml.
//Only allow other web-default, web.xml, web-override to change it.
if (!(descriptor instanceof FragmentDescriptor))
{
//We're processing web-defaults, web.xml or web-override. Any of them can
//set or change the resource-env-ref.
_metaData.setOrigin("resource-env-ref."+jndiName, descriptor);
Class typeClass = TypeUtil.fromName(type);
if (typeClass==null)
typeClass = _context.loadClass(type);
addInjections (descriptor, node, jndiName, typeClass);
bindResourceEnvRef(jndiName, typeClass);
}
else
{
//We're processing a web-fragment. It can only contribute injections if the
//there haven't been any injections declared yet, or they weren't declared in a WebXml file.
Descriptor d = _metaData.getOriginDescriptor("resource-env-ref."+jndiName+".injection");
if (d == null || d instanceof FragmentDescriptor)
{
Class typeClass = TypeUtil.fromName(type);
if (typeClass==null)
typeClass = _context.loadClass(type);
addInjections (descriptor, node, jndiName, typeClass);
}
}
break;
}
case WebFragment:
{
//ServletSpec p.75. No declaration of resource-env-ref in web xml, but in multiple web-fragments. Error.
throw new IllegalStateException("Conflicting resource-env-ref "+jndiName+" in "+descriptor.getResource());
}
}
}
/**
* Common Annotations Spec section 2.3:
* message-destination-ref is for:
* - javax.jms.Queue
* - javax.jms.Topic
* @param node
* @throws Exception
*/
public void visitMessageDestinationRef (Descriptor descriptor, XmlParser.Node node)
throws Exception
{
String jndiName = node.getString("message-destination-ref-name",false,true);
String type = node.getString("message-destination-type",false,true);
String usage = node.getString("message-destination-usage",false,true);
Origin o = _metaData.getOrigin("message-destination-ref."+jndiName);
switch (o)
{
case NotSet:
{
//A message-destination-ref of this name has not been previously declared
Class typeClass = TypeUtil.fromName(type);
if (typeClass==null)
typeClass = _context.loadClass(type);
addInjections(descriptor, node, jndiName, typeClass);
bindMessageDestinationRef(jndiName, typeClass);
_metaData.setOrigin("message-destination-ref."+jndiName, descriptor);
break;
}
case WebXml:
case WebDefaults:
case WebOverride:
{
//A message-destination-ref of this name has been declared first in a web xml.
//Only allow other web-default, web.xml, web-override to change it.
if (!(descriptor instanceof FragmentDescriptor))
{
Class typeClass = TypeUtil.fromName(type);
if (typeClass==null)
typeClass = _context.loadClass(type);
addInjections(descriptor, node, jndiName, typeClass);
bindMessageDestinationRef(jndiName, typeClass);
_metaData.setOrigin("message-destination-ref."+jndiName, descriptor);
}
else
{
//A web-fragment has declared a message-destination-ref with the same name as a web xml.
//It can only contribute injections, and only if the web xml didn't declare any.
Descriptor d = _metaData.getOriginDescriptor("message-destination-ref."+jndiName+".injection");
if (d == null || d instanceof FragmentDescriptor)
{
Class typeClass = TypeUtil.fromName(type);
if (typeClass==null)
typeClass = _context.loadClass(type);
addInjections(descriptor, node, jndiName, typeClass);
}
}
break;
}
case WebFragment:
{
//ServletSpec p.75. No declaration of message-destination-ref in web xml, but in multiple web-fragments. Error.
throw new IllegalStateException("Conflicting message-destination-ref "+jndiName+" in "+descriptor.getResource());
}
}
}
/**
*
* TODO
* If web.xml has at least 1 post-construct, then all post-constructs in fragments
* are ignored. Otherwise, post-constructs from fragments are merged.
* post-construct is the name of a class and method to call after all
* resources have been setup but before the class is put into use
* @param node
*/
public void visitPostConstruct(Descriptor descriptor, XmlParser.Node node)
{
String className = node.getString("lifecycle-callback-class", false, true);
String methodName = node.getString("lifecycle-callback-method", false, true);
if (className==null || className.equals(""))
{
Log.warn("No lifecycle-callback-class specified");
return;
}
if (methodName==null || methodName.equals(""))
{
Log.warn("No lifecycle-callback-method specified for class "+className);
return;
}
LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)_context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
//ServletSpec 3.0 p80 If web.xml declares a post-construct then all post-constructs
//in fragments must be ignored. Otherwise, they are additive.
Origin o = _metaData.getOrigin("post-construct");
switch (o)
{
case NotSet:
{
//No post-constructs have been declared previously.
_metaData.setOrigin("post-construct", descriptor);
try
{
Class clazz = _context.loadClass(className);
LifeCycleCallback callback = new PostConstructCallback();
callback.setTarget(clazz, methodName);
callbacks.add(callback);
}
catch (ClassNotFoundException e)
{
Log.warn("Couldn't load post-construct target class "+className);
}
break;
}
case WebXml:
case WebDefaults:
case WebOverride:
{
//A web xml first declared a post-construct. Only allow other web xml files (web-defaults, web-overrides etc)
//to add to it
if (!(descriptor instanceof FragmentDescriptor))
{
try
{
Class clazz = _context.loadClass(className);
LifeCycleCallback callback = new PostConstructCallback();
callback.setTarget(clazz, methodName);
callbacks.add(callback);
}
catch (ClassNotFoundException e)
{
Log.warn("Couldn't load post-construct target class "+className);
}
}
break;
}
case WebFragment:
{
//A web-fragment first declared a post-construct. Allow all other web-fragments to merge in their post-constructs
try
{
Class clazz = _context.loadClass(className);
LifeCycleCallback callback = new PostConstructCallback();
callback.setTarget(clazz, methodName);
callbacks.add(callback);
}
catch (ClassNotFoundException e)
{
Log.warn("Couldn't load post-construct target class "+className);
}
break;
}
}
}
/**
*
* pre-destroy is the name of a class and method to call just as
* the instance is being destroyed
* @param node
*/
public void visitPreDestroy(Descriptor descriptor, XmlParser.Node node)
{
String className = node.getString("lifecycle-callback-class", false, true);
String methodName = node.getString("lifecycle-callback-method", false, true);
if (className==null || className.equals(""))
{
Log.warn("No lifecycle-callback-class specified for pre-destroy");
return;
}
if (methodName==null || methodName.equals(""))
{
Log.warn("No lifecycle-callback-method specified for pre-destroy class "+className);
return;
}
LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)_context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
Origin o = _metaData.getOrigin("pre-destroy");
switch(o)
{
case NotSet:
{
//No pre-destroys have been declared previously. Record this descriptor
//as the first declarer.
_metaData.setOrigin("pre-destroy", descriptor);
try
{
Class clazz = _context.loadClass(className);
LifeCycleCallback callback = new PreDestroyCallback();
callback.setTarget(clazz, methodName);
callbacks.add(callback);
}
catch (ClassNotFoundException e)
{
Log.warn("Couldn't load pre-destory target class "+className);
}
break;
}
case WebXml:
case WebDefaults:
case WebOverride:
{
//A web xml file previously declared a pre-destroy. Only allow other web xml files
//(not web-fragments) to add to them.
if (!(descriptor instanceof FragmentDescriptor))
{
try
{
Class clazz = _context.loadClass(className);
LifeCycleCallback callback = new PreDestroyCallback();
callback.setTarget(clazz, methodName);
callbacks.add(callback);
}
catch (ClassNotFoundException e)
{
Log.warn("Couldn't load pre-destory target class "+className);
}
}
break;
}
case WebFragment:
{
//No pre-destroys in web xml, so allow all fragments to merge their pre-destroys.
try
{
Class clazz = _context.loadClass(className);
LifeCycleCallback callback = new PreDestroyCallback();
callback.setTarget(clazz, methodName);
callbacks.add(callback);
}
catch (ClassNotFoundException e)
{
Log.warn("Couldn't load pre-destory target class "+className);
}
break;
}
}
}
/**
* Iterate over the &lt;injection-target&gt; entries for a node
*
* @param descriptor
* @param node
* @param jndiName
* @param valueClass
* @return
*/
public void addInjections (Descriptor descriptor, XmlParser.Node node, String jndiName, Class valueClass)
{
Iterator itor = node.iterator("injection-target");
while(itor.hasNext())
{
XmlParser.Node injectionNode = (XmlParser.Node)itor.next();
String targetClassName = injectionNode.getString("injection-target-class", false, true);
String targetName = injectionNode.getString("injection-target-name", false, true);
if ((targetClassName==null) || targetClassName.equals(""))
{
Log.warn("No classname found in injection-target");
continue;
}
if ((targetName==null) || targetName.equals(""))
{
Log.warn("No field or method name in injection-target");
continue;
}
InjectionCollection injections = (InjectionCollection)_context.getAttribute(InjectionCollection.INJECTION_COLLECTION);
// comments in the javaee_5.xsd file specify that the targetName is looked
// for first as a java bean property, then if that fails, as a field
try
{
Class clazz = _context.loadClass(targetClassName);
Injection injection = new Injection();
injection.setJndiName(jndiName);
injection.setTarget(clazz, targetName, valueClass);
injections.add(injection);
//Record which was the first descriptor to declare an injection for this name
if (_metaData.getOriginDescriptor(node.getTag()+"."+jndiName+".injection") == null)
_metaData.setOrigin(node.getTag()+"."+jndiName+".injection", descriptor);
}
catch (ClassNotFoundException e)
{
Log.warn("Couldn't load injection target class "+targetClassName);
}
}
}
/**
* @see org.eclipse.jetty.plus.webapp.AbstractConfiguration#bindEnvEntry(java.lang.String, java.lang.String)
* @param name
* @param value
* @throws Exception
*/
public void bindEnvEntry(String name, Object value) throws Exception
{
InitialContext ic = null;
boolean bound = false;
//check to see if we bound a value and an EnvEntry with this name already
//when we processed the server and the webapp's naming environment
//@see EnvConfiguration.bindEnvEntries()
ic = new InitialContext();
try
{
NamingEntry ne = (NamingEntry)ic.lookup("java:comp/env/"+NamingEntryUtil.makeNamingEntryName(ic.getNameParser(""), name));
if (ne!=null && ne instanceof EnvEntry)
{
EnvEntry ee = (EnvEntry)ne;
bound = ee.isOverrideWebXml();
}
}
catch (NameNotFoundException e)
{
bound = false;
}
if (!bound)
{
//either nothing was bound or the value from web.xml should override
Context envCtx = (Context)ic.lookup("java:comp/env");
NamingUtil.bind(envCtx, name, value);
}
}
/**
* Bind a resource reference.
*
* If a resource reference with the same name is in a jetty-env.xml
* file, it will already have been bound.
*
* @see org.eclipse.jetty.plus.webapp.AbstractConfiguration#bindResourceRef(java.lang.String)
* @param name
* @throws Exception
*/
public void bindResourceRef(String name, Class typeClass)
throws Exception
{
bindEntry(name, typeClass);
}
/**
* @see org.eclipse.jetty.plus.webapp.AbstractConfiguration#bindResourceEnvRef(java.lang.String)
* @param name
* @throws Exception
*/
public void bindResourceEnvRef(String name, Class typeClass)
throws Exception
{
bindEntry(name, typeClass);
}
public void bindMessageDestinationRef(String name, Class typeClass)
throws Exception
{
bindEntry(name, typeClass);
}
/**
* Bind a resource with the given name from web.xml of the given type
* with a jndi resource from either the server or the webapp's naming
* environment.
*
* As the servlet spec does not cover the mapping of names in web.xml with
* names from the execution environment, jetty uses the concept of a Link, which is
* a subclass of the NamingEntry class. A Link defines a mapping of a name
* from web.xml with a name from the execution environment (ie either the server or the
* webapp's naming environment).
*
* @param name name of the resource from web.xml
* @param typeClass
* @throws Exception
*/
protected void bindEntry (String name, Class typeClass)
throws Exception
{
String nameInEnvironment = name;
boolean bound = false;
//check if the name in web.xml has been mapped to something else
//check a context-specific naming environment first
Object scope = _context;
NamingEntry ne = NamingEntryUtil.lookupNamingEntry(scope, name);
if (ne!=null && (ne instanceof Link))
{
//if we found a mapping, get out name it is mapped to in the environment
nameInEnvironment = (String)((Link)ne).getObjectToBind();
Link l = (Link)ne;
}
//try finding that mapped name in the webapp's environment first
scope = _context;
bound = NamingEntryUtil.bindToENC(scope, name, nameInEnvironment);
if (bound)
return;
//try the server's environment
scope = _context.getServer();
bound = NamingEntryUtil.bindToENC(scope, name, nameInEnvironment);
if (bound)
return;
//try the jvm environment
bound = NamingEntryUtil.bindToENC(null, name, nameInEnvironment);
if (bound)
return;
//There is no matching resource so try a default name.
//The default name syntax is: the [res-type]/default
//eg javax.sql.DataSource/default
nameInEnvironment = typeClass.getName()+"/default";
//First try the server scope
NamingEntry defaultNE = NamingEntryUtil.lookupNamingEntry(_context.getServer(), nameInEnvironment);
if (defaultNE==null)
defaultNE = NamingEntryUtil.lookupNamingEntry(null, nameInEnvironment);
if (defaultNE!=null)
defaultNE.bindToENC(name);
else
throw new IllegalStateException("Nothing to bind for name "+nameInEnvironment);
}
}

View File

@ -0,0 +1,164 @@
// ========================================================================
// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.plus.webapp;
import java.util.EventListener;
import javax.servlet.Filter;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import org.eclipse.jetty.plus.annotation.InjectionCollection;
import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection;
import org.eclipse.jetty.plus.annotation.RunAsCollection;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.Holder;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.ServletContextHandler.Decorator;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* WebAppDecorator
*
*
*/
public class WebAppDecorator implements Decorator
{
private WebAppContext _wac;
public WebAppDecorator (WebAppContext context)
{
_wac = context;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#decorateFilterHolder(org.eclipse.jetty.servlet.FilterHolder)
*/
public void decorateFilterHolder(FilterHolder filter) throws ServletException
{
// TODO Auto-generated method stub
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#decorateFilterInstance(javax.servlet.Filter)
*/
public <T extends Filter> T decorateFilterInstance(T filter) throws ServletException
{
decorate(filter);
return filter;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#decorateListenerInstance(java.util.EventListener)
*/
public <T extends EventListener> T decorateListenerInstance(T listener) throws ServletException
{
decorate(listener);
return listener;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#decorateServletHolder(org.eclipse.jetty.servlet.ServletHolder)
*/
public void decorateServletHolder(ServletHolder holder) throws ServletException
{
decorate(holder);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#decorateServletInstance(javax.servlet.Servlet)
*/
public <T extends Servlet> T decorateServletInstance(T servlet) throws ServletException
{
decorate(servlet);
return servlet;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#destroyFilterInstance(javax.servlet.Filter)
*/
public void destroyFilterInstance(Filter f)
{
destroy(f);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#destroyServletInstance(javax.servlet.Servlet)
*/
public void destroyServletInstance(Servlet s)
{
destroy(s);
}
/**
* @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#destroyListenerInstance(java.util.EventListener)
*/
public void destroyListenerInstance(EventListener l)
{
destroy(l);
}
protected void decorate (Object o)
throws ServletException
{
InjectionCollection injections = (InjectionCollection)_wac.getAttribute(InjectionCollection.INJECTION_COLLECTION);
LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)_wac.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
RunAsCollection runAses = (RunAsCollection)_wac.getAttribute(RunAsCollection.RUNAS_COLLECTION);
if (runAses != null)
runAses.setRunAs(o);
if (injections != null)
injections.inject(o);
if (callbacks != null)
{
try
{
callbacks.callPostConstructCallback(o);
}
catch (Exception e)
{
throw new ServletException(e);
}
}
}
protected void destroy (Object o)
{
LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)_wac.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
if (callbacks != null)
{
try
{
callbacks.callPreDestroyCallback(o);
}
catch (Exception e)
{
Log.warn("Destroying instance of "+o.getClass(), e);
}
}
}
}

View File

@ -21,6 +21,7 @@ import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppClassLoader;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.MetaData;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@ -50,6 +51,10 @@ public class TestConfiguration
WebAppContext wac = new MyWebAppContext();
wac.setServer(server);
wac.setClassLoader(new WebAppClassLoader(Thread.currentThread().getContextClassLoader(), wac));
MetaData metaData = new MetaData(wac);
PlusDescriptorProcessor plusProcessor = new PlusDescriptorProcessor();
//bind some EnvEntrys at the server level
EnvEntry ee1 = new EnvEntry(server, "xxx/a", "100", true);
@ -73,8 +78,7 @@ public class TestConfiguration
assertNotNull(NamingEntryUtil.lookupNamingEntry(wac, "zzz/c"));
assertNotNull(NamingEntryUtil.lookupNamingEntry(wac, "zzz/e"));
Configuration config = new Configuration();
//make a new env configuration
EnvConfiguration envConfig = new EnvConfiguration();
@ -105,20 +109,20 @@ public class TestConfiguration
ne = (NamingEntry)ic.lookup("java:comp/env/"+NamingEntry.__contextName+"/zzz/e");
assertNotNull(ne);
config.bindEnvEntry(wac, "foo", "99");
plusProcessor.bindEnvEntry("foo", "99");
assertEquals("99",ic.lookup( "java:comp/env/foo"));
config.bindEnvEntry(wac, "xxx/a", "7");
plusProcessor.bindEnvEntry("xxx/a", "7");
assertEquals("900", ic.lookup("java:comp/env/xxx/a")); //webapp overrides web.xml
config.bindEnvEntry(wac, "yyy/b", "7");
plusProcessor.bindEnvEntry("yyy/b", "7");
assertEquals("910", ic.lookup("java:comp/env/yyy/b"));//webapp overrides web.xml
config.bindEnvEntry(wac,"zzz/c", "7");
plusProcessor.bindEnvEntry("zzz/c", "7");
assertEquals("7", ic.lookup("java:comp/env/zzz/c"));//webapp does NOT override web.xml
config.bindEnvEntry(wac,"zzz/d", "7");
plusProcessor.bindEnvEntry("zzz/d", "7");
assertEquals("7", ic.lookup("java:comp/env/zzz/d"));//server does NOT override web.xml
config.bindEnvEntry(wac,"zzz/e", "7");
plusProcessor.bindEnvEntry("zzz/e", "7");
assertEquals("7", ic.lookup("java:comp/env/zzz/e"));//webapp does NOT override web.xml
config.bindEnvEntry(wac,"zzz/f", "7");
plusProcessor.bindEnvEntry("zzz/f", "7");
assertEquals("500", ic.lookup("java:comp/env/zzz/f"));//server overrides web.xml
((Context)ic.lookup("java:comp")).destroySubcontext("env");

View File

@ -1269,7 +1269,14 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
_localeEncodingMap=new HashMap<String,String>();
_localeEncodingMap.put(locale, encoding);
}
public String getLocaleEncoding (String locale)
{
if (_localeEncodingMap==null)
return null;
String encoding = _localeEncodingMap.get(locale);
return encoding;
}
/* ------------------------------------------------------------ */
/**
* Get the character encoding for a locale. The full locale name is first

View File

@ -13,8 +13,17 @@
package org.eclipse.jetty.servlet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import org.eclipse.jetty.server.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import org.eclipse.jetty.servlet.api.FilterRegistration;
import javax.servlet.ServletException;
import org.eclipse.jetty.util.log.Log;
@ -22,25 +31,26 @@ import org.eclipse.jetty.util.log.Log;
/**
*
*/
public class FilterHolder extends Holder
public class FilterHolder extends Holder<Filter>
{
/* ------------------------------------------------------------ */
private transient Filter _filter;
private transient Config _config;
/* ---------------------------------------------------------------- */
/** Constructor for Serialization.
/** Constructor
*/
public FilterHolder()
{
}
/* ---------------------------------------------------------------- */
/** Constructor for Serialization.
/** Constructor
*/
public FilterHolder(Class filter)
public FilterHolder(Class<? extends Filter> filter)
{
super (filter);
setHeldClass(filter);
}
/* ---------------------------------------------------------------- */
@ -67,9 +77,22 @@ public class FilterHolder extends Holder
}
if (_filter==null)
_filter=(Filter)newInstance();
{
try
{
_filter=((ServletContextHandler.Context)_servletHandler.getServletContext()).createFilter(getHeldClass());
}
catch (ServletException se)
{
Throwable cause = se.getRootCause();
if (cause instanceof InstantiationException)
throw (InstantiationException)cause;
if (cause instanceof IllegalAccessException)
throw (IllegalAccessException)cause;
throw se;
}
}
_filter = getServletHandler().customizeFilter(_filter);
_config=new Config();
_filter.init(_config);
}
@ -100,13 +123,13 @@ public class FilterHolder extends Holder
/* ------------------------------------------------------------ */
@Override
public void destroyInstance (Object o)
throws Exception
throws Exception
{
if (o==null)
return;
Filter f = (Filter)o;
f.destroy();
getServletHandler().customizeFilterDestroy(f);
getServletHandler().destroyFilter(f);
}
/* ------------------------------------------------------------ */
@ -132,6 +155,74 @@ public class FilterHolder extends Holder
return getName();
}
/* ------------------------------------------------------------ */
public FilterRegistration.Dynamic getRegistration()
{
return new Registration();
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
protected class Registration extends HolderRegistration implements FilterRegistration.Dynamic
{
public void addMappingForServletNames(EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter, String... servletNames)
{
illegalStateIfContextStarted();
FilterMapping mapping = new FilterMapping();
mapping.setFilterHolder(FilterHolder.this);
mapping.setServletNames(servletNames);
mapping.setDispatcherTypes(dispatcherTypes);
if (isMatchAfter)
_servletHandler.addFilterMapping(mapping);
else
_servletHandler.prependFilterMapping(mapping);
}
public void addMappingForUrlPatterns(EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter, String... urlPatterns)
{
illegalStateIfContextStarted();
FilterMapping mapping = new FilterMapping();
mapping.setFilterHolder(FilterHolder.this);
mapping.setPathSpecs(urlPatterns);
mapping.setDispatcherTypes(dispatcherTypes);
if (isMatchAfter)
_servletHandler.addFilterMapping(mapping);
else
_servletHandler.prependFilterMapping(mapping);
}
public Collection<String> getServletNameMappings()
{
FilterMapping[] mappings =_servletHandler.getFilterMappings();
List<String> names=new ArrayList<String>();
for (FilterMapping mapping : mappings)
{
if (mapping.getFilterHolder()!=FilterHolder.this)
continue;
String[] servlets=mapping.getServletNames();
if (servlets!=null && servlets.length>0)
names.addAll(Arrays.asList(servlets));
}
return names;
}
public Collection<String> getUrlPatternMappings()
{
FilterMapping[] mappings =_servletHandler.getFilterMappings();
List<String> patterns=new ArrayList<String>();
for (FilterMapping mapping : mappings)
{
if (mapping.getFilterHolder()!=FilterHolder.this)
continue;
String[] specs=mapping.getPathSpecs();
if (specs!=null && specs.length>0)
patterns.addAll(Arrays.asList(specs));
}
return patterns;
}
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */

View File

@ -16,8 +16,9 @@ package org.eclipse.jetty.servlet;
import java.util.Arrays;
import java.util.EnumSet;
import org.eclipse.jetty.http.PathMap;
import org.eclipse.jetty.server.DispatcherType;
import org.eclipse.jetty.http.PathMap;
import org.eclipse.jetty.server.Handler;
@ -36,18 +37,18 @@ public class FilterMapping
/* ------------------------------------------------------------ */
/** Dispatch type from name
*/
public static int dispatch(String type)
public static DispatcherType dispatch(String type)
{
if ("request".equalsIgnoreCase(type))
return REQUEST;
return DispatcherType.REQUEST;
if ("forward".equalsIgnoreCase(type))
return FORWARD;
return DispatcherType.FORWARD;
if ("include".equalsIgnoreCase(type))
return INCLUDE;
return DispatcherType.INCLUDE;
if ("error".equalsIgnoreCase(type))
return ERROR;
return DispatcherType.ERROR;
if ("async".equalsIgnoreCase(type))
return ASYNC;
return DispatcherType.ASYNC;
throw new IllegalArgumentException(type);
}
@ -71,28 +72,6 @@ public class FilterMapping
}
throw new IllegalArgumentException(type.toString());
}
/* ------------------------------------------------------------ */
/** Dispatch type from name
*/
public static DispatcherType dispatch(int type)
{
switch(type)
{
case REQUEST:
return DispatcherType.REQUEST;
case ASYNC:
return DispatcherType.ASYNC;
case FORWARD:
return DispatcherType.FORWARD;
case INCLUDE:
return DispatcherType.INCLUDE;
case ERROR:
return DispatcherType.ERROR;
}
throw new IllegalArgumentException(""+type);
}
/* ------------------------------------------------------------ */
@ -140,15 +119,6 @@ public class FilterMapping
return (_dispatches&type)!=0;
}
/* ------------------------------------------------------------ */
/**
* @return Returns the dispatches.
*/
public int getDispatches()
{
return _dispatches;
}
/* ------------------------------------------------------------ */
/**
* @return Returns the filterName.
@ -180,16 +150,23 @@ public class FilterMapping
public void setDispatcherTypes(EnumSet<DispatcherType> dispatcherTypes)
{
_dispatches=DEFAULT;
if (dispatcherTypes.contains(DispatcherType.ERROR))
_dispatches|=ERROR;
if (dispatcherTypes.contains(DispatcherType.FORWARD))
_dispatches|=FORWARD;
if (dispatcherTypes.contains(DispatcherType.INCLUDE))
_dispatches|=INCLUDE;
if (dispatcherTypes.contains(DispatcherType.REQUEST))
_dispatches|=REQUEST;
if (dispatcherTypes!=null)
{
if (dispatcherTypes.contains(DispatcherType.ERROR))
_dispatches|=ERROR;
if (dispatcherTypes.contains(DispatcherType.FORWARD))
_dispatches|=FORWARD;
if (dispatcherTypes.contains(DispatcherType.INCLUDE))
_dispatches|=INCLUDE;
if (dispatcherTypes.contains(DispatcherType.REQUEST))
_dispatches|=REQUEST;
if (dispatcherTypes.contains(DispatcherType.ASYNC))
_dispatches|=ASYNC;
}
}
/* ------------------------------------------------------------ */
/**
* @param dispatches The dispatches to set.

View File

@ -16,8 +16,11 @@ package org.eclipse.jetty.servlet;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.jetty.servlet.api.Registration;
import javax.servlet.ServletContext;
import javax.servlet.UnavailableException;
@ -31,10 +34,10 @@ import org.eclipse.jetty.util.log.Log;
/**
*
*/
public class Holder extends AbstractLifeCycle
public class Holder<T> extends AbstractLifeCycle
{
protected transient Class<? extends T> _class;
protected final Map<String,String> _initParams=new HashMap<String,String>(3);
protected transient Class<?> _class;
protected String _className;
protected String _displayName;
protected boolean _extInstance;
@ -44,22 +47,20 @@ public class Holder extends AbstractLifeCycle
protected String _name;
protected ServletHandler _servletHandler;
/* ---------------------------------------------------------------- */
protected Holder()
{
}
/* ---------------------------------------------------------------- */
protected Holder(Class held)
/* ------------------------------------------------------------ */
/**
* @return True if this holder was created for a specific instance.
*/
public boolean isInstance()
{
_class=held;
if (held!=null)
{
_className=held.getName();
_name=held.getName()+"-"+this.hashCode();
}
return _extInstance;
}
/* ------------------------------------------------------------ */
public void doStart()
throws Exception
@ -85,6 +86,7 @@ public class Holder extends AbstractLifeCycle
}
/* ------------------------------------------------------------ */
@Override
public void doStop()
throws Exception
{
@ -99,7 +101,7 @@ public class Holder extends AbstractLifeCycle
}
/* ------------------------------------------------------------ */
public Class getHeldClass()
public Class<? extends T> getHeldClass()
{
return _class;
}
@ -127,7 +129,7 @@ public class Holder extends AbstractLifeCycle
}
/* ---------------------------------------------------------------- */
public Map getInitParameters()
public Map<String,String> getInitParameters()
{
return _initParams;
}
@ -147,16 +149,6 @@ public class Holder extends AbstractLifeCycle
return _servletHandler;
}
/* ------------------------------------------------------------ */
public synchronized Object newInstance()
throws InstantiationException,
IllegalAccessException
{
if (_class==null)
throw new InstantiationException("!"+_className);
return _class.newInstance();
}
/* ------------------------------------------------------------ */
public void destroyInstance(Object instance)
throws Exception
@ -177,10 +169,15 @@ public class Holder extends AbstractLifeCycle
/**
* @param held The class to hold
*/
public void setHeldClass(Class held)
public void setHeldClass(Class<? extends T> held)
{
_class=held;
_className = held!=null?held.getName():null;
if (held!=null)
{
_className=held.getName();
if (_name==null)
_name=held.getName()+"-"+this.hashCode();
}
}
/* ------------------------------------------------------------ */
@ -276,6 +273,72 @@ public class Holder extends AbstractLifeCycle
return Holder.this.getInitParameterNames();
}
}
/* -------------------------------------------------------- */
/* -------------------------------------------------------- */
/* -------------------------------------------------------- */
protected class HolderRegistration implements Registration.Dynamic
{
public void setAsyncSupported(boolean isAsyncSupported)
{
illegalStateIfContextStarted();
Holder.this.setAsyncSupported(isAsyncSupported);
}
public void setDescription(String description)
{
if (Log.isDebugEnabled())
Log.debug(this+" is "+description);
}
public String getClassName()
{
return Holder.this.getClassName();
}
public String getInitParameter(String name)
{
return Holder.this.getInitParameter(name);
}
public Map<String, String> getInitParameters()
{
return Holder.this.getInitParameters();
}
public String getName()
{
return Holder.this.getName();
}
public boolean setInitParameter(String name, String value)
{
illegalStateIfContextStarted();
if (Holder.this.getInitParameter(name)!=null)
return false;
Holder.this.setInitParameter(name,value);
return true;
}
public Set<String> setInitParameters(Map<String, String> initParameters)
{
illegalStateIfContextStarted();
Set<String> clash=null;
for (String name : initParameters.keySet())
{
if (Holder.this.getInitParameter(name)!=null)
{
if (clash==null)
clash=new HashSet<String>();
clash.add(name);
}
}
if (clash!=null)
return clash;
Holder.this.setInitParameters(initParameters);
return Collections.emptySet();
};
}
}

View File

@ -13,13 +13,26 @@
package org.eclipse.jetty.servlet;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.Filter;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import org.eclipse.jetty.security.ConstraintAware;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.DispatcherType;
@ -29,8 +42,10 @@ import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.handler.ScopedHandler;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.servlet.api.FilterRegistration;
import org.eclipse.jetty.servlet.api.ServletRegistration;
import org.eclipse.jetty.util.Loader;
/* ------------------------------------------------------------ */
@ -56,6 +71,10 @@ public class ServletContextHandler extends ContextHandler
protected SecurityHandler _securityHandler;
protected ServletHandler _servletHandler;
protected int _options;
protected Decorator _decorator;
protected Object _restrictedContextListeners;
protected final Set<Object> _created = Collections.newSetFromMap(new ConcurrentHashMap<Object,Boolean>());
/* ------------------------------------------------------------ */
public ServletContextHandler()
@ -115,6 +134,42 @@ public class ServletContextHandler extends ContextHandler
((HandlerCollection)parent).addHandler(this);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.handler.ContextHandler#doStart()
*/
@Override
protected void doStart() throws Exception
{
_created.clear();
super.doStart();
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.handler.ContextHandler#doStop()
*/
@Override
protected void doStop() throws Exception
{
super.doStop();
_created.clear();
}
/* ------------------------------------------------------------ */
/**
* Check if instance was created by a call to {@link ServletContext#createFilter(Class)},
* {@link ServletContext#createServlet(Class)} or {@link ServletContext#createListener(Class)}
* @param instance Instance of {@link Servlet}, {@link Filter} or {@link EventListener}
* @return True if the instance was created by a call to {@link ServletContext#createFilter(Class)},
* {@link ServletContext#createServlet(Class)} or {@link ServletContext#createListener(Class)}
*/
public boolean isCreatedInstance(Object instance)
{
return _created.contains(instance);
}
/* ------------------------------------------------------------ */
/** Get the defaultSecurityHandlerClass.
* @return the defaultSecurityHandlerClass
@ -201,7 +256,19 @@ public class ServletContextHandler extends ContextHandler
// OK to Initialize servlet handler now
if (_servletHandler != null && _servletHandler.isStarted())
{
if (_decorator!=null)
{
if (_servletHandler.getFilters()!=null)
for (FilterHolder holder:_servletHandler.getFilters())
_decorator.decorateFilterHolder(holder);
if(_servletHandler.getServlets()!=null)
for (ServletHolder holder:_servletHandler.getServlets())
_decorator.decorateServletHolder(holder);
}
_servletHandler.initialize();
}
}
/* ------------------------------------------------------------ */
@ -262,6 +329,31 @@ public class ServletContextHandler extends ContextHandler
getServletHandler().addServletWithMapping(servlet, pathSpec);
}
/* ------------------------------------------------------------ */
/** conveniance method to add a filter
*/
public void addFilter(FilterHolder holder,String pathSpec,EnumSet<DispatcherType> dispatches)
{
getServletHandler().addFilterWithMapping(holder,pathSpec,dispatches);
}
/* ------------------------------------------------------------ */
/** convenience method to add a filter
*/
public FilterHolder addFilter(Class<? extends Filter> filterClass,String pathSpec,EnumSet<DispatcherType> dispatches)
{
return getServletHandler().addFilterWithMapping(filterClass,pathSpec,dispatches);
}
/* ------------------------------------------------------------ */
/** convenience method to add a filter
*/
public FilterHolder addFilter(String filterClass,String pathSpec,EnumSet<DispatcherType> dispatches)
{
return getServletHandler().addFilterWithMapping(filterClass,pathSpec,dispatches);
}
/* ------------------------------------------------------------ */
/** conveniance method to add a filter
*/
@ -286,6 +378,21 @@ public class ServletContextHandler extends ContextHandler
return getServletHandler().addFilterWithMapping(filterClass,pathSpec,dispatches);
}
public void callContextInitialized(ServletContextListener l, ServletContextEvent e)
{
l.contextInitialized(e);
}
public void callContextDestroyed(ServletContextListener l, ServletContextEvent e)
{
l.contextDestroyed(e);
}
/* ------------------------------------------------------------ */
/**
* @param sessionHandler The sessionHandler to set.
@ -322,14 +429,46 @@ public class ServletContextHandler extends ContextHandler
_servletHandler = servletHandler;
}
/* ------------------------------------------------------------ */
/**
* @return The decorator used to resource inject new Filters, Servlets and EventListeners
*/
public Decorator getDecorator()
{
return _decorator;
}
/* ------------------------------------------------------------ */
/**
* @param decorator The inject used to resource inject new Filters, Servlets and EventListeners
*/
public void setDecorator(Decorator decorator)
{
_decorator = decorator;
}
/* ------------------------------------------------------------ */
void destroyServlet(Servlet servlet)
{
if (_decorator!=null)
_decorator.destroyServletInstance(servlet);
}
/* ------------------------------------------------------------ */
void destroyFilter(Filter filter)
{
if (_decorator!=null)
_decorator.destroyFilterInstance(filter);
}
/* ------------------------------------------------------------ */
public class Context extends ContextHandler.Context
{
/* ------------------------------------------------------------ */
/*
* @see javax.servlet.ServletContext#getNamedDispatcher(java.lang.String)
*/
@Override
public RequestDispatcher getNamedDispatcher(String name)
{
ContextHandler context=org.eclipse.jetty.servlet.ServletContextHandler.this;
@ -337,33 +476,307 @@ public class ServletContextHandler extends ContextHandler
return null;
return new Dispatcher(context, name);
}
/* ------------------------------------------------------------ */
public void addFilterMappingForServletNames(String filterName, EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter, String... servletNames)
/**
* @see javax.servlet.ServletContext#addFilter(java.lang.String, java.lang.Class)
*/
public FilterRegistration.Dynamic addFilter(String filterName, Class<? extends Filter> filterClass)
{
if (isStarted())
throw new IllegalStateException();
ServletHandler handler = ServletContextHandler.this.getServletHandler();
FilterMapping mapping = new FilterMapping();
mapping.setFilterName(filterName);
mapping.setServletNames(servletNames);
mapping.setDispatcherTypes(dispatcherTypes);
handler.addFilterMapping(mapping);
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
final FilterHolder holder= handler.newFilterHolder();
holder.setName(filterName);
holder.setHeldClass(filterClass);
handler.addFilter(holder);
return holder.getRegistration();
}
/* ------------------------------------------------------------ */
public void addServletMapping(String servletName, String[] urlPatterns)
/**
* @see javax.servlet.ServletContext#addFilter(java.lang.String, java.lang.String)
*/
public FilterRegistration.Dynamic addFilter(String filterName, String className)
{
if (isStarted())
throw new IllegalStateException();
ServletHandler handler = ServletContextHandler.this.getServletHandler();
ServletHolder holder= handler.newServletHolder();
holder.setName(servletName);
handler.addServlet(holder);
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
final FilterHolder holder= handler.newFilterHolder();
holder.setName(filterName);
holder.setClassName(className);
handler.addFilter(holder);
return holder.getRegistration();
}
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.ServletContext#addFilter(java.lang.String, javax.servlet.Filter)
*/
public FilterRegistration.Dynamic addFilter(String filterName, Filter filter)
{
if (isStarted())
throw new IllegalStateException();
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
final FilterHolder holder= handler.newFilterHolder();
holder.setName(filterName);
holder.setFilter(filter);
handler.addFilter(holder);
return holder.getRegistration();
}
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.ServletContext#addServlet(java.lang.String, java.lang.Class)
*/
public ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass)
{
if (!isStarting())
throw new IllegalStateException();
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
final ServletHolder holder= handler.newServletHolder();
holder.setName(servletName);
holder.setHeldClass(servletClass);
handler.addServlet(holder);
return holder.getRegistration();
}
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.ServletContext#addServlet(java.lang.String, java.lang.String)
*/
public ServletRegistration.Dynamic addServlet(String servletName, String className)
{
if (!isStarting())
throw new IllegalStateException();
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
final ServletHolder holder= handler.newServletHolder();
holder.setName(servletName);
holder.setClassName(className);
handler.addServlet(holder);
return holder.getRegistration();
}
/* ------------------------------------------------------------ */
public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet)
{
if (!isStarting())
throw new IllegalStateException();
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
final ServletHolder holder= handler.newServletHolder();
holder.setName(servletName);
holder.setServlet(servlet);
handler.addServlet(holder);
return holder.getRegistration();
}
/* ------------------------------------------------------------ */
public boolean setInitParameter(String name, String value)
{
// TODO other started conditions
if (!isStarting())
throw new IllegalStateException();
return super.setInitParameter(name,value);
}
/* ------------------------------------------------------------ */
public <T extends Filter> T createFilter(Class<T> c) throws ServletException
{
try
{
T f = c.newInstance();
if (_decorator!=null)
f=_decorator.decorateFilterInstance(f);
_created.add(f);
return f;
}
catch (InstantiationException e)
{
throw new ServletException(e);
}
catch (IllegalAccessException e)
{
throw new ServletException(e);
}
}
/* ------------------------------------------------------------ */
public <T extends Servlet> T createServlet(Class<T> c) throws ServletException
{
try
{
T s = c.newInstance();
if (_decorator!=null)
s=_decorator.decorateServletInstance(s);
_created.add(s);
return s;
}
catch (InstantiationException e)
{
throw new ServletException(e);
}
catch (IllegalAccessException e)
{
throw new ServletException(e);
}
}
public FilterRegistration getFilterRegistration(String filterName)
{
final FilterHolder holder=ServletContextHandler.this.getServletHandler().getFilter(filterName);
return (holder==null)?null:holder.getRegistration();
}
public Map<String, ? extends FilterRegistration> getFilterRegistrations()
{
HashMap<String, FilterRegistration> registrations = new HashMap<String, FilterRegistration>();
ServletHandler handler=ServletContextHandler.this.getServletHandler();
FilterHolder[] holders=handler.getFilters();
if (holders!=null)
{
for (FilterHolder holder : holders)
registrations.put(holder.getName(),holder.getRegistration());
}
return registrations;
}
public ServletRegistration getServletRegistration(String servletName)
{
final ServletHolder holder=ServletContextHandler.this.getServletHandler().getServlet(servletName);
return (holder==null)?null:holder.getRegistration();
}
public Map<String, ? extends ServletRegistration> getServletRegistrations()
{
HashMap<String, ServletRegistration> registrations = new HashMap<String, ServletRegistration>();
ServletHandler handler=ServletContextHandler.this.getServletHandler();
ServletHolder[] holders=handler.getServlets();
if (holders!=null)
{
for (ServletHolder holder : holders)
registrations.put(holder.getName(),holder.getRegistration());
}
return registrations;
}
public void addListener(String className)
{
// TODO other started conditions
if (!isStarting())
throw new IllegalStateException();
try
{
Class<? extends EventListener> clazz = getClassLoader()==null?Loader.loadClass(ContextHandler.class,className):getClassLoader().loadClass(className);
addListener(clazz);
}
catch (ClassNotFoundException e)
{
throw new IllegalArgumentException(e);
}
}
public <T extends EventListener> void addListener(T t)
{
if (!isStarting())
throw new IllegalStateException();
ServletContextHandler.this.addEventListener(t);
}
public void addListener(Class<? extends EventListener> listenerClass)
{
if (!isStarting())
throw new IllegalStateException();
try
{
EventListener l = createListener(listenerClass);
ServletContextHandler.this.addEventListener(l);
}
catch (ServletException e)
{
throw new IllegalStateException(e);
}
}
public <T extends EventListener> T createListener(Class<T> clazz) throws ServletException
{
try
{
T l = null;
try
{
l = clazz.newInstance();
}
catch (InstantiationException e)
{
throw new ServletException(e);
}
catch (IllegalAccessException e)
{
throw new ServletException(e);
}
if (_decorator!=null)
l=_decorator.decorateListenerInstance(l);
_created.add(l);
return l;
}
catch(ServletException e)
{
throw e;
}
catch(Exception e)
{
throw new ServletException(e);
}
}
public void declareRoles(String... roleNames)
{
if (!isStarting())
throw new IllegalStateException();
//Get a reference to the SecurityHandler, which must be ConstraintAware
if (_securityHandler != null && _securityHandler instanceof ConstraintAware)
{
HashSet<String> union = new HashSet<String>();
Set<String> existing = ((ConstraintAware)_securityHandler).getRoles();
if (existing != null)
union.addAll(existing);
union.addAll(Arrays.asList(roleNames));
((ConstraintSecurityHandler)_securityHandler).setRoles(union);
}
}
}
public interface Decorator
{
<T extends Filter> T decorateFilterInstance(T filter) throws ServletException;
<T extends Servlet> T decorateServletInstance(T servlet) throws ServletException;
<T extends EventListener> T decorateListenerInstance(T listener) throws ServletException;
void decorateFilterHolder(FilterHolder filter) throws ServletException;
void decorateServletHolder(ServletHolder servlet) throws ServletException;
void destroyServletInstance(Servlet s);
void destroyFilterInstance(Filter f);
void destroyListenerInstance(EventListener f);
}
}

View File

@ -16,12 +16,15 @@ package org.eclipse.jetty.servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jetty.server.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.RequestDispatcher;
@ -42,7 +45,6 @@ import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.security.IdentityService;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.DispatcherType;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
@ -73,7 +75,7 @@ public class ServletHandler extends ScopedHandler
public static final String __DEFAULT_SERVLET="default";
/* ------------------------------------------------------------ */
private ContextHandler _contextHandler;
private ServletContextHandler _contextHandler;
private ContextHandler.Context _servletContext;
private FilterHolder[] _filters;
private FilterMapping[] _filterMappings;
@ -85,14 +87,14 @@ public class ServletHandler extends ScopedHandler
private ServletHolder[] _servlets;
private ServletMapping[] _servletMappings;
private transient Map<String,FilterHolder> _filterNameMap= new HashMap<String,FilterHolder>();
private transient List<FilterMapping> _filterPathMappings;
private transient MultiMap<String> _filterNameMappings;
private final Map<String,FilterHolder> _filterNameMap= new HashMap<String,FilterHolder>();
private List<FilterMapping> _filterPathMappings;
private MultiMap<String> _filterNameMappings;
private transient Map<String,ServletHolder> _servletNameMap=new HashMap();
private transient PathMap _servletPathMap;
private final Map<String,ServletHolder> _servletNameMap=new HashMap<String,ServletHolder>();
private PathMap _servletPathMap;
protected transient ConcurrentHashMap _chainCache[];
protected ConcurrentHashMap<String,FilterChain> _chainCache[];
/* ------------------------------------------------------------ */
@ -130,7 +132,7 @@ public class ServletHandler extends ScopedHandler
throws Exception
{
_servletContext=ContextHandler.getCurrentContext();
_contextHandler=_servletContext==null?null:_servletContext.getContextHandler();
_contextHandler=(ServletContextHandler)(_servletContext==null?null:_servletContext.getContextHandler());
if (_contextHandler!=null)
{
@ -269,6 +271,7 @@ public class ServletHandler extends ScopedHandler
{
return _servletContext;
}
/* ------------------------------------------------------------ */
/**
* @return Returns the servletMappings.
@ -277,6 +280,30 @@ public class ServletHandler extends ScopedHandler
{
return _servletMappings;
}
/* ------------------------------------------------------------ */
/**
* @return Returns the servletMappings.
*/
public ServletMapping getServletMapping(String pattern)
{
if (_servletMappings!=null)
{
for (ServletMapping m:_servletMappings)
{
String[] paths=m.getPathSpecs();
if (paths!=null)
{
for (String path:paths)
{
if (pattern.equals(path))
return m;
}
}
}
}
return null;
}
/* ------------------------------------------------------------ */
/** Get Servlets.
@ -726,9 +753,9 @@ public class ServletHandler extends ScopedHandler
*/
public ServletHolder addServletWithMapping (Class<? extends Servlet> servlet,String pathSpec)
{
ServletHolder holder = newServletHolder(servlet);
ServletHolder holder = newServletHolder();
holder.setHeldClass(servlet);
setServlets((ServletHolder[])LazyList.addToArray(getServlets(), holder, ServletHolder.class));
addServletWithMapping(holder,pathSpec);
return holder;
@ -797,11 +824,82 @@ public class ServletHandler extends ScopedHandler
return new FilterHolder();
}
/* ------------------------------------------------------------ */
public FilterHolder getFilter(String name)
{
return (FilterHolder)_filterNameMap.get(name);
}
/* ------------------------------------------------------------ */
/** Convenience method to add a filter.
* @param filter class of filter to create
* @param pathSpec filter mappings for filter
* @param dispatches see {@link FilterMapping#setDispatches(int)}
* @return The filter holder.
*/
public FilterHolder addFilterWithMapping (Class<? extends Filter> filter,String pathSpec,EnumSet<DispatcherType> dispatches)
{
FilterHolder holder = newFilterHolder();
holder.setHeldClass(filter);
addFilterWithMapping(holder,pathSpec,dispatches);
return holder;
}
/* ------------------------------------------------------------ */
/** Convenience method to add a filter.
* @param className of filter
* @param pathSpec filter mappings for filter
* @param dispatches see {@link FilterMapping#setDispatches(int)}
* @return The filter holder.
*/
public FilterHolder addFilterWithMapping (String className,String pathSpec,EnumSet<DispatcherType> dispatches)
{
FilterHolder holder = newFilterHolder();
holder.setName(className+"-"+holder.hashCode());
holder.setClassName(className);
addFilterWithMapping(holder,pathSpec,dispatches);
return holder;
}
/* ------------------------------------------------------------ */
/** Convenience method to add a filter.
* @param holder filter holder to add
* @param pathSpec filter mappings for filter
* @param dispatches see {@link FilterMapping#setDispatches(int)}
*/
public void addFilterWithMapping (FilterHolder holder,String pathSpec,EnumSet<DispatcherType> dispatches)
{
FilterHolder[] holders = getFilters();
if (holders!=null)
holders = (FilterHolder[])holders.clone();
try
{
setFilters((FilterHolder[])LazyList.addToArray(holders, holder, FilterHolder.class));
FilterMapping mapping = new FilterMapping();
mapping.setFilterName(holder.getName());
mapping.setPathSpec(pathSpec);
mapping.setDispatcherTypes(dispatches);
setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), mapping, FilterMapping.class));
}
catch (RuntimeException e)
{
setFilters(holders);
throw e;
}
catch (Error e)
{
setFilters(holders);
throw e;
}
}
/* ------------------------------------------------------------ */
/** Convenience method to add a filter.
@ -870,6 +968,20 @@ public class ServletHandler extends ScopedHandler
}
/* ------------------------------------------------------------ */
/** Convenience method to add a filter with a mapping
* @param className
* @param pathSpec
* @param dispatches
* @return the filter holder created
* @deprecated use {@link #addFilterWithMapping(Class, String, int)} instead
*/
public FilterHolder addFilter (String className,String pathSpec,EnumSet<DispatcherType> dispatches)
{
return addFilterWithMapping(className, pathSpec, dispatches);
}
/* ------------------------------------------------------------ */
/**
* convenience method to add a filter and mapping
@ -1282,55 +1394,18 @@ public class ServletHandler extends ScopedHandler
}
/* ------------------------------------------------------------ */
/**
* Customize a servlet.
*
* Called before the servlet goes into service.
* Subclasses of ServletHandler should override
* this method.
*
* @param servlet
* @return the potentially customized servlet
* @throws Exception
*/
public Servlet customizeServlet (Servlet servlet)
throws Exception
void destroyServlet(Servlet servlet)
{
return servlet;
_contextHandler.destroyServlet(servlet);
}
/* ------------------------------------------------------------ */
public Servlet customizeServletDestroy (Servlet servlet)
throws Exception
void destroyFilter(Filter filter)
{
return servlet;
}
/* ------------------------------------------------------------ */
/**
* Customize a Filter.
*
* Called before the Filter goes into service.
* Subclasses of ServletHandler should override
* this method.
*
* @param filter The filter to customize.
* @return the potentially customized filter
* @throws Exception If there was a problem
*/
public Filter customizeFilter (Filter filter)
throws Exception
{
return filter;
}
/* ------------------------------------------------------------ */
public Filter customizeFilterDestroy (Filter filter)
throws Exception
{
return filter;
_contextHandler.destroyFilter(filter);
}
/* ------------------------------------------------------------ */
@Override

View File

@ -14,19 +14,26 @@
package org.eclipse.jetty.servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
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.Stack;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import org.eclipse.jetty.servlet.api.ServletRegistration;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.SingleThreadModel;
import javax.servlet.UnavailableException;
import org.eclipse.jetty.security.IdentityService;
import org.eclipse.jetty.security.RunAsToken;
import org.eclipse.jetty.server.Request;
@ -45,7 +52,7 @@ import org.eclipse.jetty.util.log.Log;
*
*
*/
public class ServletHolder extends Holder implements UserIdentity.Scope, Comparable
public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope, Comparable
{
/* ---------------------------------------------------------------- */
private int _initOrder;
@ -67,7 +74,9 @@ public class ServletHolder extends Holder implements UserIdentity.Scope, Compara
/** Constructor .
*/
public ServletHolder()
{}
{
}
/* ---------------------------------------------------------------- */
/** Constructor for existing servlet.
@ -80,9 +89,9 @@ public class ServletHolder extends Holder implements UserIdentity.Scope, Compara
/* ---------------------------------------------------------------- */
/** Constructor for existing servlet.
*/
public ServletHolder(Class servlet)
public ServletHolder(Class<? extends Servlet> servlet)
{
super(servlet);
setHeldClass(servlet);
}
/* ---------------------------------------------------------------- */
@ -124,6 +133,11 @@ public class ServletHolder extends Holder implements UserIdentity.Scope, Compara
_initOnStartup=true;
_initOrder = order;
}
public boolean isSetInitOrder()
{
return _initOnStartup;
}
/* ------------------------------------------------------------ */
/** Comparitor by init order.
@ -293,7 +307,7 @@ public class ServletHolder extends Holder implements UserIdentity.Scope, Compara
return;
Servlet servlet = ((Servlet)o);
servlet.destroy();
getServletHandler().customizeServletDestroy(servlet);
getServletHandler().destroyServlet(servlet);
}
/* ------------------------------------------------------------ */
@ -404,13 +418,9 @@ public class ServletHolder extends Holder implements UserIdentity.Scope, Compara
try
{
if (_servlet==null)
_servlet=(Servlet)newInstance();
_servlet=newInstance();
if (_config==null)
_config=new Config();
//handle any cusomizations of the servlet, such as @postConstruct
if (!(_servlet instanceof SingleThreadedWrapper))
_servlet = getServletHandler().customizeServlet(_servlet);
// Handle run as
if (_identityService!=null)
@ -468,22 +478,6 @@ public class ServletHolder extends Holder implements UserIdentity.Scope, Compara
return _roleMap;
}
/* ------------------------------------------------------------ */
public String getRunAsRole()
{
return _runAsRole;
}
/* ------------------------------------------------------------ */
/**
* Set the run-as role for this servlet
* @param role run-as role for this servlet
*/
public void setRunAsRole(String role)
{
_runAsRole=role;
}
/* ------------------------------------------------------------ */
/** Service a request with this servlet.
*/
@ -560,19 +554,92 @@ public class ServletHolder extends Holder implements UserIdentity.Scope, Compara
}
/* -------------------------------------------------------- */
/* -------------------------------------------------------- */
/* -------------------------------------------------------- */
public class Registration extends HolderRegistration implements ServletRegistration.Dynamic
{
public Set<String> addMapping(String... urlPatterns)
{
illegalStateIfContextStarted();
Set<String> clash=null;
for (String pattern : urlPatterns)
{
if (_servletHandler.getServletMapping(pattern)!=null)
{
if (clash==null)
clash=new HashSet<String>();
clash.add(pattern);
}
}
if (clash!=null)
return clash;
ServletMapping mapping = new ServletMapping();
mapping.setServletName(ServletHolder.this.getName());
mapping.setPathSpecs(urlPatterns);
_servletHandler.addServletMapping(mapping);
return Collections.emptySet();
}
public Collection<String> getMappings()
{
ServletMapping[] mappings =_servletHandler.getServletMappings();
List<String> patterns=new ArrayList<String>();
for (ServletMapping mapping : mappings)
{
if (!mapping.getServletName().equals(getName()))
continue;
String[] specs=mapping.getPathSpecs();
if (specs!=null && specs.length>0)
patterns.addAll(Arrays.asList(specs));
}
return patterns;
}
public String getRunAsRole()
{
return _runAsRole;
}
public void setLoadOnStartup(int loadOnStartup)
{
illegalStateIfContextStarted();
ServletHolder.this.setInitOrder(loadOnStartup);
}
public int getInitOrder()
{
return ServletHolder.this.getInitOrder();
}
public void setRunAsRole(String role)
{
_runAsRole = role;
}
}
public ServletRegistration.Dynamic getRegistration()
{
return new Registration();
}
/* -------------------------------------------------------- */
/* -------------------------------------------------------- */
/* -------------------------------------------------------- */
private class SingleThreadedWrapper implements Servlet
{
Stack _stack=new Stack();
Stack<Servlet> _stack=new Stack<Servlet>();
public void destroy()
{
synchronized(this)
{
while(_stack.size()>0)
try { ((Servlet)_stack.pop()).destroy(); } catch (Exception e) { Log.warn(e); }
try { (_stack.pop()).destroy(); } catch (Exception e) { Log.warn(e); }
}
}
@ -594,8 +661,7 @@ public class ServletHolder extends Holder implements UserIdentity.Scope, Compara
{
try
{
Servlet s = (Servlet) newInstance();
s = getServletHandler().customizeServlet(s);
Servlet s = newInstance();
s.init(config);
_stack.push(s);
}
@ -622,18 +688,13 @@ public class ServletHolder extends Holder implements UserIdentity.Scope, Compara
{
try
{
s = (Servlet) newInstance();
s = getServletHandler().customizeServlet(s);
s = newInstance();
s.init(_config);
}
catch (ServletException e)
{
throw e;
}
catch (IOException e)
{
throw e;
}
catch (Exception e)
{
throw new ServletException(e);
@ -653,7 +714,30 @@ public class ServletHolder extends Holder implements UserIdentity.Scope, Compara
}
}
}
}
/* ------------------------------------------------------------ */
/**
* @return
* @throws ServletException
* @throws IllegalAccessException
* @throws InstantiationException
*/
protected Servlet newInstance() throws ServletException, IllegalAccessException, InstantiationException
{
try
{
return ((ServletContextHandler.Context)getServletHandler().getServletContext()).createServlet(getHeldClass());
}
catch (ServletException se)
{
Throwable cause = se.getRootCause();
if (cause instanceof InstantiationException)
throw (InstantiationException)cause;
if (cause instanceof IllegalAccessException)
throw (IllegalAccessException)cause;
throw se;
}
}
}

View File

@ -0,0 +1,27 @@
package org.eclipse.jetty.servlet.api;
import java.util.Collection;
import java.util.EnumSet;
import org.eclipse.jetty.server.DispatcherType;
/**
* FilterRegistration
*
* Mimics the javax.servlet.FilterRegistration class to ease
* jetty-7/jetty-8 compatibility
*/
public interface FilterRegistration
{
public void addMappingForServletNames(EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter, String... servletNames);
public Collection<String> getServletNameMappings();
public void addMappingForUrlPatterns(EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter, String... urlPatterns);
public Collection<String> getUrlPatternMappings();
interface Dynamic extends FilterRegistration, Registration.Dynamic
{
}
}

View File

@ -0,0 +1,25 @@
package org.eclipse.jetty.servlet.api;
import java.util.Map;
import java.util.Set;
public interface Registration
{
public String getName();
public String getClassName();
public boolean setInitParameter(String name, String value);
public String getInitParameter(String name);
public Set<String> setInitParameters(Map<String, String> initParameters);
public Map<String, String> getInitParameters();
interface Dynamic extends Registration
{
public void setAsyncSupported(boolean isAsyncSupported);
}
}

View File

@ -0,0 +1,21 @@
package org.eclipse.jetty.servlet.api;
import java.util.Collection;
import java.util.Set;
public interface ServletRegistration
{
public Set<String> addMapping(String... urlPatterns);
public Collection<String> getMappings();
public String getRunAsRole();
interface Dynamic extends ServletRegistration, Registration.Dynamic
{
public void setLoadOnStartup(int loadOnStartup);
public void setRunAsRole(String roleName);
}
}

View File

@ -0,0 +1,29 @@
// ========================================================================
// Copyright (c) 2006-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.webapp;
import org.eclipse.jetty.util.resource.Resource;
/**
* DefaultsDescriptor
*
*
*/
public class DefaultsDescriptor extends Descriptor
{
public DefaultsDescriptor(Resource xml, MetaData processor)
{
super(xml, processor);
}
}

View File

@ -0,0 +1,290 @@
// ========================================================================
// Copyright (c) 2006-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.webapp;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.servlet.Servlet;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.xml.XmlParser;
/**
* Descriptor
*
* A web descriptor (web.xml/web-defaults.xml/web-overrides.xml).
*/
public class Descriptor
{
protected static XmlParser _parser;
public enum MetaDataComplete {NotSet, True, False};
protected Resource _xml;
protected XmlParser.Node _root;
protected MetaDataComplete _metaDataComplete;
protected int _majorVersion = 3; //default to container version
protected int _minorVersion = 0;
protected ArrayList<String> _classNames = new ArrayList<String>();
protected boolean _distributable;
protected boolean _validating;
protected MetaData _metaData;
protected boolean _isOrdered = false;
protected List<String> _ordering = new ArrayList<String>();
public static XmlParser newParser()
throws ClassNotFoundException
{
XmlParser xmlParser=new XmlParser();
//set up cache of DTDs and schemas locally
URL dtd22=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_2.dtd",true);
URL dtd23=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_3.dtd",true);
URL j2ee14xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/j2ee_1_4.xsd",true);
URL webapp24xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_4.xsd",true);
URL webapp25xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_5.xsd",true);
URL webapp30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_3_0.xsd",true);
URL webcommon30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-common_3_0.xsd",true);
URL webfragment30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-fragment_3_0.xsd",true);
URL schemadtd=Loader.getResource(Servlet.class,"javax/servlet/resources/XMLSchema.dtd",true);
URL xmlxsd=Loader.getResource(Servlet.class,"javax/servlet/resources/xml.xsd",true);
URL webservice11xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/j2ee_web_services_client_1_1.xsd",true);
URL webservice12xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/javaee_web_services_client_1_2.xsd",true);
URL datatypesdtd=Loader.getResource(Servlet.class,"javax/servlet/resources/datatypes.dtd",true);
URL jsp20xsd = null;
URL jsp21xsd = null;
try
{
Class jsp_page = Loader.loadClass(WebXmlConfiguration.class, "javax.servlet.jsp.JspPage");
jsp20xsd = jsp_page.getResource("/javax/servlet/resources/jsp_2_0.xsd");
jsp21xsd = jsp_page.getResource("/javax/servlet/resources/jsp_2_1.xsd");
}
catch (Exception e)
{
Log.ignore(e);
}
finally
{
if (jsp20xsd == null) jsp20xsd = Loader.getResource(Servlet.class, "javax/servlet/resources/jsp_2_0.xsd", true);
if (jsp21xsd == null) jsp21xsd = Loader.getResource(Servlet.class, "javax/servlet/resources/jsp_2_1.xsd", true);
}
redirect(xmlParser,"web-app_2_2.dtd",dtd22);
redirect(xmlParser,"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",dtd22);
redirect(xmlParser,"web.dtd",dtd23);
redirect(xmlParser,"web-app_2_3.dtd",dtd23);
redirect(xmlParser,"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",dtd23);
redirect(xmlParser,"XMLSchema.dtd",schemadtd);
redirect(xmlParser,"http://www.w3.org/2001/XMLSchema.dtd",schemadtd);
redirect(xmlParser,"-//W3C//DTD XMLSCHEMA 200102//EN",schemadtd);
redirect(xmlParser,"jsp_2_0.xsd",jsp20xsd);
redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/jsp_2_0.xsd",jsp20xsd);
redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/jsp_2_1.xsd",jsp21xsd);
redirect(xmlParser,"j2ee_1_4.xsd",j2ee14xsd);
redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/j2ee_1_4.xsd",j2ee14xsd);
redirect(xmlParser,"web-app_2_4.xsd",webapp24xsd);
redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd",webapp24xsd);
redirect(xmlParser,"web-app_2_5.xsd",webapp25xsd);
redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd",webapp25xsd);
redirect(xmlParser,"web-app_3_0.xsd",webapp30xsd);
redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd",webapp30xsd);
redirect(xmlParser,"web-common_3_0.xsd",webcommon30xsd);
redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-common_3_0.xsd",webcommon30xsd);
redirect(xmlParser,"web-fragment_3_0.xsd",webfragment30xsd);
redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd",webfragment30xsd);
redirect(xmlParser,"xml.xsd",xmlxsd);
redirect(xmlParser,"http://www.w3.org/2001/xml.xsd",xmlxsd);
redirect(xmlParser,"datatypes.dtd",datatypesdtd);
redirect(xmlParser,"http://www.w3.org/2001/datatypes.dtd",datatypesdtd);
redirect(xmlParser,"j2ee_web_services_client_1_1.xsd",webservice11xsd);
redirect(xmlParser,"http://www.ibm.com/webservices/xsd/j2ee_web_services_client_1_1.xsd",webservice11xsd);
redirect(xmlParser,"javaee_web_services_client_1_2.xsd",webservice12xsd);
redirect(xmlParser,"http://www.ibm.com/webservices/xsd/javaee_web_services_client_1_2.xsd",webservice12xsd);
return xmlParser;
}
protected static void redirect(XmlParser parser, String resource, URL source)
{
if (source != null) parser.redirectEntity(resource, source);
}
public Descriptor (Resource xml, MetaData md)
{
_xml = xml;
_metaData = md;
}
public void parse ()
throws Exception
{
if (_parser == null)
_parser = newParser();
if (_root == null)
{
//boolean oldValidating = _processor.getParser().getValidating();
//_processor.getParser().setValidating(_validating);
_root = _parser.parse(_xml.getURL().toString());
processVersion();
processOrdering();
//_processor.getParser().setValidating(oldValidating);
}
}
public MetaDataComplete getMetaDataComplete()
{
return _metaDataComplete;
}
public XmlParser.Node getRoot ()
{
return _root;
}
public int getMajorVersion ()
{
return _majorVersion;
}
public int getMinorVersion()
{
return _minorVersion;
}
public Resource getResource ()
{
return _xml;
}
public MetaData getMetaData()
{
return _metaData;
}
public void processVersion ()
{
String version = _root.getAttribute("version", "DTD");
if ("DTD".equals(version))
{
_majorVersion = 2;
_minorVersion = 3;
String dtd = _parser.getDTD();
if (dtd != null && dtd.indexOf("web-app_2_2") >= 0)
{
_majorVersion = 2;
_minorVersion = 2;
}
}
else
{
int dot = version.indexOf(".");
if (dot > 0)
{
_majorVersion = Integer.parseInt(version.substring(0,dot));
_minorVersion = Integer.parseInt(version.substring(dot+1));
}
}
if (_majorVersion < 2 && _minorVersion < 5)
_metaDataComplete = MetaDataComplete.True; // does not apply before 2.5
else
{
String s = (String)_root.getAttribute("metadata-complete");
if (s == null)
_metaDataComplete = MetaDataComplete.NotSet;
else
_metaDataComplete = Boolean.valueOf(s).booleanValue()?MetaDataComplete.True:MetaDataComplete.False;
}
Log.debug(_xml.toString()+": Calculated metadatacomplete = " + _metaDataComplete + " with version=" + version);
}
public void processOrdering ()
{
//Process the web.xml's optional <absolute-ordering> element
XmlParser.Node ordering = _root.get("absolute-ordering");
if (ordering == null)
return;
_isOrdered = true;
//If an absolute-ordering was already set, then ignore it in favour of this new one
// _processor.setOrdering(new AbsoluteOrdering());
Iterator iter = ordering.iterator();
XmlParser.Node node = null;
while (iter.hasNext())
{
Object o = iter.next();
if (!(o instanceof XmlParser.Node)) continue;
node = (XmlParser.Node) o;
if (node.getTag().equalsIgnoreCase("others"))
//((AbsoluteOrdering)_processor.getOrdering()).addOthers();
_ordering.add("others");
else if (node.getTag().equalsIgnoreCase("name"))
//((AbsoluteOrdering)_processor.getOrdering()).add(node.toString(false,true));
_ordering.add(node.toString(false,true));
}
}
public void addClassName (String className)
{
if (!_classNames.contains(className))
_classNames.add(className);
}
public ArrayList<String> getClassNames ()
{
return _classNames;
}
public void setDistributable (boolean distributable)
{
_distributable = distributable;
}
public boolean isDistributable()
{
return _distributable;
}
public void setValidating (boolean validating)
{
_validating = validating;
}
public boolean isOrdered()
{
return _isOrdered;
}
public List<String> getOrdering()
{
return _ordering;
}
}

View File

@ -0,0 +1,24 @@
// ========================================================================
// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.webapp;
/**
* DescriptorProcessor
*
*
*/
public interface DescriptorProcessor
{
public void process (Descriptor descriptor) throws Exception;
}

View File

@ -0,0 +1,68 @@
// ========================================================================
// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.webapp;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.log.Log;
/**
* DiscoveredAnnotation
*
* Represents an annotation that has been discovered
* by scanning source code of WEB-INF/classes and WEB-INF/lib jars.
*
*/
public abstract class DiscoveredAnnotation
{
protected WebAppContext _context;
protected String _className;
protected Class _clazz;
public abstract void apply();
public DiscoveredAnnotation (WebAppContext context, String className)
{
_context = context;
_className = className;
}
public Class getTargetClass()
{
if (_clazz != null)
return _clazz;
loadClass();
return _clazz;
}
private void loadClass ()
{
if (_clazz != null)
return;
if (_className == null)
return;
try
{
_clazz = Loader.loadClass(null, _className);
}
catch (Exception e)
{
Log.warn(e);
}
}
}

View File

@ -21,7 +21,7 @@ import org.eclipse.jetty.util.resource.Resource;
/**
* FragmentConfiguration
*
* This configuration supports some Servlet 3.0 features in jetty-7.
*
*
* Process web-fragments in jars
*/
@ -33,20 +33,14 @@ public class FragmentConfiguration implements Configuration
{
if (!context.isConfigurationDiscovered())
return;
MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA);
if (metaData == null)
throw new IllegalStateException("No metadata");
//find all web-fragment.xmls
findWebFragments(context, metaData);
WebXmlProcessor processor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR);
if (processor == null)
{
processor = new WebXmlProcessor (context);
context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, processor);
}
//parse web-fragment.xmls
parseWebFragments(context, processor);
//TODO for jetty-8/servletspec 3 we will need to merge the parsed web fragments into the
//effective pom in this preConfigure step
}
public void configure(WebAppContext context) throws Exception
@ -54,16 +48,12 @@ public class FragmentConfiguration implements Configuration
if (!context.isConfigurationDiscovered())
return;
//TODO for jetty-8/servletspec3 the fragments will not be separately processed here, but
//will be done by webXmlConfiguration when it processes the effective merged web.xml
WebXmlProcessor processor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR);
if (processor == null)
{
processor = new WebXmlProcessor (context);
context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, processor);
}
processor.processFragments();
MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA);
if (metaData == null)
throw new IllegalStateException("No metadata");
//order the fragments
metaData.orderFragments();
}
public void deconfigure(WebAppContext context) throws Exception
@ -78,20 +68,19 @@ public class FragmentConfiguration implements Configuration
/* ------------------------------------------------------------------------------- */
/**
* Look for any web.xml fragments in META-INF of jars in WEB-INF/lib
* Look for any web-fragment.xml fragments in META-INF of jars in WEB-INF/lib
*
* @throws Exception
*/
public void parseWebFragments (final WebAppContext context, final WebXmlProcessor processor) throws Exception
public void findWebFragments (final WebAppContext context, final MetaData metaData) throws Exception
{
List<Resource> frags = (List<Resource>)context.getAttribute(FRAGMENT_RESOURCES);
if (frags!=null)
{
for (Resource frag : frags)
{
processor.parseFragment(Resource.newResource("jar:"+frag.getURL()+"!/META-INF/web-fragment.xml"));
metaData.addFragment(frag, Resource.newResource("jar:"+frag.getURL()+"!/META-INF/web-fragment.xml"));
}
}
}
}

View File

@ -0,0 +1,162 @@
// ========================================================================
// Copyright (c) 2006-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.webapp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.xml.XmlParser;
/**
* Fragment
*
* A web-fragment.xml descriptor.
*/
public class FragmentDescriptor extends Descriptor
{
public static final String NAMELESS = "@@-NAMELESS-@@"; //prefix for nameless Fragments
public enum OtherType {None, Before, After};
protected int _counter = 0;
protected OtherType _otherType = OtherType.None;
protected List<String> _befores = new ArrayList<String>();
protected List<String> _afters = new ArrayList<String>();
protected String _name;
public FragmentDescriptor (Resource xml, MetaData processor)
throws Exception
{
super (xml, processor);
}
public String getName ()
{
return _name;
}
public void parse ()
throws Exception
{
super.parse();
processName();
}
public void processName ()
{
XmlParser.Node root = getRoot();
XmlParser.Node nameNode = root.get("name");
_name = NAMELESS+(_counter++);
if (nameNode != null)
{
String tmp = nameNode.toString(false,true);
if (tmp!=null && tmp.length()>0)
_name = tmp;
}
}
public void processOrdering ()
{
//Process a fragment jar's web-fragment.xml<ordering> elements
XmlParser.Node root = getRoot();
XmlParser.Node ordering = root.get("ordering");
if (ordering == null)
return; //No ordering for this fragment
_isOrdered = true;
processBefores(ordering);
processAfters(ordering);
}
public void processBefores (XmlParser.Node ordering)
{
//Process the <before> elements, looking for an <others/> clause and all of the <name> clauses
XmlParser.Node before = ordering.get("before");
if (before == null)
return;
Iterator iter = before.iterator();
XmlParser.Node node = null;
while (iter.hasNext())
{
Object o = iter.next();
if (!(o instanceof XmlParser.Node)) continue;
node = (XmlParser.Node) o;
if (node.getTag().equalsIgnoreCase("others"))
{
if (_otherType != OtherType.None)
throw new IllegalStateException("Duplicate <other> clause detected in "+_xml.getURI());
_otherType = OtherType.Before;
}
else if (node.getTag().equalsIgnoreCase("name"))
_befores.add(node.toString(false,true));
}
}
public void processAfters (XmlParser.Node ordering)
{
//Process the <after> elements, look for an <others/> clause and all of the <name/> clauses
XmlParser.Node after = ordering.get("after");
if (after == null)
return;
Iterator iter = after.iterator();
XmlParser.Node node = null;
while (iter.hasNext())
{
Object o = iter.next();
if (!(o instanceof XmlParser.Node)) continue;
node = (XmlParser.Node) o;
if (node.getTag().equalsIgnoreCase("others"))
{
if (_otherType != OtherType.After)
throw new IllegalStateException("Duplicate <other> clause detected in "+_xml.getURI());
_otherType = OtherType.After;
}
else if (node.getTag().equalsIgnoreCase("name"))
_afters.add(node.toString(false,true));
}
}
public List<String> getBefores()
{
return Collections.unmodifiableList(_befores);
}
public List<String> getAfters()
{
return Collections.unmodifiableList(_afters);
}
public OtherType getOtherType ()
{
return _otherType;
}
public List<String> getOrdering()
{
return null; //only used for absolute-ordering in Descriptor
}
}

View File

@ -0,0 +1,84 @@
// ========================================================================
// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.webapp;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.jetty.xml.XmlParser;
/**
* IterativeDescriptorProcessor
*
*
*/
public abstract class IterativeDescriptorProcessor implements DescriptorProcessor
{
public static final Class[] __signature = new Class[]{Descriptor.class, XmlParser.Node.class};
protected Map<String, Method> _visitors = new HashMap<String, Method>();
public abstract void start(Descriptor descriptor);
public abstract void end(Descriptor descriptor);
/**
* Register a method to be called back when visiting the node with the given name.
* The method must exist on a subclass of this class, and must have the signature:
* public void method (Descriptor descriptor, XmlParser.Node node)
* @param nodeName
* @param m
*/
public void registerVisitor(String nodeName, Method m)
{
_visitors.put(nodeName, m);
}
/**
* @see org.eclipse.jetty.webapp.DescriptorProcessor#process(org.eclipse.jetty.webapp.Descriptor)
*/
public void process(Descriptor descriptor)
throws Exception
{
if (descriptor == null)
return;
start(descriptor);
XmlParser.Node root = descriptor.getRoot();
Iterator iter = root.iterator();
XmlParser.Node node = null;
while (iter.hasNext())
{
Object o = iter.next();
if (!(o instanceof XmlParser.Node)) continue;
node = (XmlParser.Node) o;
visit(descriptor, node);
}
end(descriptor);
}
protected void visit (final Descriptor descriptor, final XmlParser.Node node)
throws Exception
{
String name = node.getTag();
Method m = _visitors.get(name);
if (m != null)
m.invoke(this, new Object[]{descriptor, node});
}
}

View File

@ -25,7 +25,7 @@ import org.eclipse.jetty.xml.XmlConfiguration;
*
* JettyWebConfiguration.
*
* Looks for Xmlconfiguration files in WEB-INF. Searches in order for the first of jetty6-web.xml, jetty-web.xml or web-jetty.xml
* Looks for Xmlconfiguration files in WEB-INF. Searches in order for the first of jettyX-web.xml, jetty-web.xml or web-jetty.xml
*
*
*

View File

@ -0,0 +1,911 @@
// ========================================================================
// Copyright (c) 2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.webapp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import org.eclipse.jetty.util.resource.Resource;
/**
* MetaData
*
*
*/
public class MetaData
{
public static final String METADATA = "org.eclipse.jetty.metaData";
public static final String METADATA_COMPLETE = "org.eclipse.jetty.metadataComplete";
public static final String WEBXML_MAJOR_VERSION = "org.eclipse.jetty.webXmlMajorVersion";
public static final String WEBXML_MINOR_VERSION = "org.eclipse.jetty.webXmlMinorVersion";
public static final String WEBXML_CLASSNAMES = "org.eclipse.jetty.webXmlClassNames";
public static final String ORDERED_LIBS = "javax.servlet.context.orderedLibs";
public enum Origin {NotSet, WebXml, WebDefaults, WebOverride, WebFragment, Annotation};
protected WebAppContext _context;
protected Map<String, OriginInfo> _origins = new HashMap<String,OriginInfo>();
protected Descriptor _webDefaultsRoot;
protected Descriptor _webXmlRoot;
protected Descriptor _webOverrideRoot;
protected List<DiscoveredAnnotation> _annotations = new ArrayList<DiscoveredAnnotation>();
protected List<DescriptorProcessor> _descriptorProcessors = new ArrayList<DescriptorProcessor>();
protected List<FragmentDescriptor> _webFragmentRoots = new ArrayList<FragmentDescriptor>();
protected Map<String,FragmentDescriptor> _webFragmentNameMap = new HashMap<String,FragmentDescriptor>();
protected Map<Resource, FragmentDescriptor> _webFragmentResourceMap = new HashMap<Resource, FragmentDescriptor>();
protected Map<Resource, List<DiscoveredAnnotation>> _webFragmentAnnotations = new HashMap<Resource, List<DiscoveredAnnotation>>();
protected List<Resource> _orderedResources;
protected Ordering _ordering;//can be set to RelativeOrdering by web-default.xml, web.xml, web-override.xml
protected StandardDescriptorProcessor _standardDescriptorProcessor;
public static class OriginInfo
{
protected String name;
protected Origin origin;
protected Descriptor descriptor;
public OriginInfo (String n, Descriptor d)
{
name = n;
descriptor = d;
if (d == null)
throw new IllegalArgumentException("No descriptor");
if (d instanceof FragmentDescriptor)
origin = Origin.WebFragment;
if (d instanceof OverrideDescriptor)
origin = Origin.WebOverride;
if (d instanceof DefaultsDescriptor)
origin = Origin.WebDefaults;
origin = Origin.WebXml;
}
public OriginInfo (String n)
{
name = n;
origin = Origin.Annotation;
}
public OriginInfo(String n, Origin o)
{
name = n;
origin = o;
}
public String getName()
{
return name;
}
public Origin getOriginType()
{
return origin;
}
public Descriptor getDescriptor()
{
return descriptor;
}
}
/**
* Ordering
*
*
*/
public interface Ordering
{
public List<Resource> order(List<Resource> fragments);
public boolean isAbsolute ();
public boolean hasOther();
}
/**
* AbsoluteOrdering
*
* An <absolute-order> element in web.xml
*/
public class AbsoluteOrdering implements Ordering
{
public static final String OTHER = "@@-OTHER-@@";
protected List<String> _order = new ArrayList<String>();
protected boolean _hasOther = false;
/**
* Order the list of jars in WEB-INF/lib according to the ordering declarations in the descriptors
* @see org.eclipse.jetty.webapp.MetaData.Ordering#order(java.util.List)
*/
public List<Resource> order(List<Resource> jars)
{
List<Resource> orderedList = new ArrayList<Resource>();
List<Resource> tmp = new ArrayList<Resource>(jars);
//1. put everything into the list of named others, and take the named ones out of there,
//assuming we will want to use the <other> clause
Map<String,FragmentDescriptor> others = new HashMap(getNamedFragments());
//2. for each name, take out of the list of others, add to tail of list
int index = -1;
for (String item:_order)
{
if (!item.equals(OTHER))
{
FragmentDescriptor f = others.remove(item);
if (f != null)
{
Resource jar = getJarForFragment(item);
orderedList.add(jar); //take from others and put into final list in order, ignoring duplicate names
//remove resource from list for resource matching name of descriptor
tmp.remove(jar);
}
}
else
index = orderedList.size(); //remember the index at which we want to add in all the others
}
//3. if <other> was specified, insert rest of the fragments
if (_hasOther)
{
orderedList.addAll((index < 0? 0: index), tmp);
}
return orderedList;
}
public boolean isAbsolute()
{
return true;
}
public void add (String name)
{
_order.add(name);
}
public void addOthers ()
{
if (_hasOther)
throw new IllegalStateException ("Duplicate <other> element in absolute ordering");
_hasOther = true;
_order.add(OTHER);
}
public boolean hasOther ()
{
return _hasOther;
}
}
/**
* RelativeOrdering
*
* A set of <order> elements in web-fragment.xmls.
*/
public class RelativeOrdering implements Ordering
{
protected LinkedList<Resource> _beforeOthers = new LinkedList<Resource>();
protected LinkedList<Resource> _afterOthers = new LinkedList<Resource>();
protected LinkedList<Resource> _noOthers = new LinkedList<Resource>();
/**
* Order the list of jars according to the ordering declared
* in the various web-fragment.xml files.
* @see org.eclipse.jetty.webapp.MetaData.Ordering#order(java.util.List)
*/
public List<Resource> order(List<Resource> jars)
{
//for each jar, put it into the ordering according to the fragment ordering
for (Resource jar:jars)
{
//check if the jar has a fragment descriptor
FragmentDescriptor descriptor = _webFragmentResourceMap.get(jar);
if (descriptor != null)
{
switch (descriptor.getOtherType())
{
case None:
{
((RelativeOrdering)_ordering).addNoOthers(jar);
break;
}
case Before:
{
((RelativeOrdering)_ordering).addBeforeOthers(jar);
break;
}
case After:
{
((RelativeOrdering)_ordering).addAfterOthers(jar);
break;
}
}
}
else
{
//jar fragment has no descriptor, but there is a relative ordering in place, so it must be part of the others
((RelativeOrdering)_ordering).addNoOthers(jar);
}
}
//now apply the ordering
List<Resource> orderedList = new ArrayList<Resource>();
int maxIterations = 2;
boolean done = false;
do
{
//1. order the before-others according to any explicit before/after relationships
boolean changesBefore = orderList(_beforeOthers);
//2. order the after-others according to any explicit before/after relationships
boolean changesAfter = orderList(_afterOthers);
//3. order the no-others according to their explicit before/after relationships
boolean changesNone = orderList(_noOthers);
//we're finished on a clean pass through with no ordering changes
done = (!changesBefore && !changesAfter && !changesNone);
}
while (!done && (--maxIterations >0));
//4. merge before-others + no-others +after-others
if (!done)
throw new IllegalStateException("Circular references for fragments");
for (Resource r: _beforeOthers)
orderedList.add(r);
for (Resource r: _noOthers)
orderedList.add(r);
for(Resource r: _afterOthers)
orderedList.add(r);
return orderedList;
}
public boolean isAbsolute ()
{
return false;
}
public boolean hasOther ()
{
return !_beforeOthers.isEmpty() || !_afterOthers.isEmpty();
}
public void addBeforeOthers (Resource r)
{
_beforeOthers.addLast(r);
}
public void addAfterOthers (Resource r)
{
_afterOthers.addLast(r);
}
public void addNoOthers (Resource r)
{
_noOthers.addLast(r);
}
protected boolean orderList (LinkedList<Resource> list)
{
//Take a copy of the list so we can iterate over it and at the same time do random insertions
boolean changes = false;
List<Resource> iterable = new ArrayList(list);
Iterator<Resource> itor = iterable.iterator();
while (itor.hasNext())
{
Resource r = itor.next();
FragmentDescriptor f = getFragment(r);
if (f == null)
{
//no fragment for this resource so cannot have any ordering directives
continue;
}
//Handle any explicit <before> relationships for the fragment we're considering
List<String> befores = f.getBefores();
if (befores != null && !befores.isEmpty())
{
for (String b: befores)
{
//Fragment we're considering must be before b
//Check that we are already before it, if not, move us so that we are.
//If the name does not exist in our list, then get it out of the no-other list
if (!isBefore(list, f.getName(), b))
{
//b is not already before name, move it so that it is
int idx1 = getIndexOf(list, f.getName());
int idx2 = getIndexOf(list, b);
//if b is not in the same list
if (idx2 < 0)
{
changes = true;
// must be in the noOthers list or it would have been an error
Resource bResource = getJarForFragment(b);
if (bResource != null)
{
//If its in the no-others list, insert into this list so that we are before it
if (_noOthers.remove(bResource))
{
insert(list, idx1+1, b);
}
}
}
else
{
//b is in the same list but b is before name, so swap it around
list.remove(idx1);
insert(list, idx2, f.getName());
changes = true;
}
}
}
}
//Handle any explicit <after> relationships
List<String> afters = f.getAfters();
if (afters != null && !afters.isEmpty())
{
for (String a: afters)
{
//Check that fragment we're considering is after a, moving it if possible if its not
if (!isAfter(list, f.getName(), a))
{
//name is not after a, move it
int idx1 = getIndexOf(list, f.getName());
int idx2 = getIndexOf(list, a);
//if a is not in the same list as name
if (idx2 < 0)
{
changes = true;
//take it out of the noOthers list and put it in the right place in this list
Resource aResource = getJarForFragment(a);
if (aResource != null)
{
if (_noOthers.remove(aResource))
{
insert(list,idx1, aResource);
}
}
}
else
{
//a is in the same list as name, but in the wrong place, so move it
list.remove(idx2);
insert(list,idx1, a);
changes = true;
}
}
//Name we're considering must be after this name
//Check we're already after it, if not, move us so that we are.
//If the name does not exist in our list, then get it out of the no-other list
}
}
}
return changes;
}
/**
* Is fragment with name a before fragment with name b?
* @param list
* @param fragNameA
* @param fragNameB
* @return
*/
protected boolean isBefore (List<Resource> list, String fragNameA, String fragNameB)
{
//check if a and b are already in the same list, and b is already
//before a
int idxa = getIndexOf(list, fragNameA);
int idxb = getIndexOf(list, fragNameB);
if (idxb >=0 && idxb < idxa)
{
//a and b are in the same list but a is not before b
return false;
}
if (idxb < 0)
{
//a and b are not in the same list, but it is still possible that a is before
//b, depending on which list we're examining
if (list == _beforeOthers)
{
//The list we're looking at is the beforeOthers.If b is in the _afterOthers or the _noOthers, then by
//definition a is before it
return true;
}
else if (list == _afterOthers)
{
//The list we're looking at is the afterOthers, then a will be the tail of
//the final list. If b is in the beforeOthers list, then b will be before a and an error.
if (_beforeOthers.contains(fragNameB))
throw new IllegalStateException("Incorrect relationship: "+fragNameA+" before "+fragNameB);
else
return false; //b could be moved to the list
}
}
//a and b are in the same list and a is already before b
return true;
}
/**
* Is fragment name "a" after fragment name "b"?
* @param list
* @param fragNameA
* @param fragNameB
* @return
*/
protected boolean isAfter(List<Resource> list, String fragNameA, String fragNameB)
{
int idxa = getIndexOf(list, fragNameA);
int idxb = getIndexOf(list, fragNameB);
if (idxb >=0 && idxa < idxb)
{
//a and b are both in the same list, but a is before b
return false;
}
if (idxb < 0)
{
//a and b are in different lists. a could still be after b depending on which list it is in.
if (list == _afterOthers)
{
//The list we're looking at is the afterOthers. If b is in the beforeOthers or noOthers then
//by definition a is after b because a is in the afterOthers list.
return true;
}
else if (list == _beforeOthers)
{
//The list we're looking at is beforeOthers, and contains a and will be before
//everything else in the final ist. If b is in the afterOthers list, then a cannot be before b.
if (_afterOthers.contains(fragNameB))
throw new IllegalStateException("Incorrect relationship: "+fragNameB+" after "+fragNameA);
else
return false; //b could be moved from noOthers list
}
}
return true; //a and b in the same list, a is after b
}
/**
* Insert the resource matching the fragName into the list of resources
* at the location indicated by index.
*
* @param list
* @param index
* @param fragName
*/
protected void insert(List<Resource> list, int index, String fragName)
{
Resource jar = getJarForFragment(fragName);
if (jar == null)
throw new IllegalStateException("No jar for insertion");
insert(list, index, jar);
}
protected void insert(List<Resource> list, int index, Resource resource)
{
if (list == null)
throw new IllegalStateException("List is null for insertion");
//add it at the end
if (index > list.size())
list.add(resource);
else
list.add(index, resource);
}
protected void remove (List<Resource> resources, Resource r)
{
if (resources == null)
return;
resources.remove(r);
}
protected int getIndexOf(List<Resource> resources, String fragmentName)
{
FragmentDescriptor fd = getFragment(fragmentName);
if (fd == null)
return -1;
Resource r = getJarForFragment(fragmentName);
if (r == null)
return -1;
return resources.indexOf(r);
}
}
public MetaData (WebAppContext context) throws ClassNotFoundException
{
_context = context;
}
public WebAppContext getContext()
{
return _context;
}
public void setDefaults (Resource webDefaults)
throws Exception
{
_webDefaultsRoot = new DefaultsDescriptor(webDefaults, this);
_webDefaultsRoot.parse();
if (_webDefaultsRoot.isOrdered())
{
if (_ordering == null)
_ordering = new AbsoluteOrdering();
List<String> order = _webDefaultsRoot.getOrdering();
for (String s:order)
{
if (s.equalsIgnoreCase("others"))
((AbsoluteOrdering)_ordering).addOthers();
else
((AbsoluteOrdering)_ordering).add(s);
}
}
}
public void setWebXml (Resource webXml)
throws Exception
{
_webXmlRoot = new Descriptor(webXml, this);
_webXmlRoot.parse();
if (_webXmlRoot.getMetaDataComplete() == Descriptor.MetaDataComplete.True)
_context.setAttribute(METADATA_COMPLETE, Boolean.TRUE);
else
_context.setAttribute(METADATA_COMPLETE, Boolean.FALSE);
_context.setAttribute(WEBXML_CLASSNAMES, _webXmlRoot.getClassNames());
if (_webXmlRoot.isOrdered())
{
if (_ordering == null)
_ordering = new AbsoluteOrdering();
List<String> order = _webXmlRoot.getOrdering();
for (String s:order)
{
if (s.equalsIgnoreCase("others"))
((AbsoluteOrdering)_ordering).addOthers();
else
((AbsoluteOrdering)_ordering).add(s);
}
}
}
public void setOverride (Resource override)
throws Exception
{
_webOverrideRoot = new OverrideDescriptor(override, this);
_webOverrideRoot.setValidating(false);
_webOverrideRoot.parse();
if (_webOverrideRoot.getMetaDataComplete() == Descriptor.MetaDataComplete.True)
_context.setAttribute(METADATA_COMPLETE, Boolean.TRUE);
else if (_webOverrideRoot.getMetaDataComplete() == Descriptor.MetaDataComplete.False)
_context.setAttribute(METADATA_COMPLETE, Boolean.FALSE);
if (_webOverrideRoot.isOrdered())
{
if (_ordering == null)
_ordering = new AbsoluteOrdering();
List<String> order = _webOverrideRoot.getOrdering();
for (String s:order)
{
if (s.equalsIgnoreCase("others"))
((AbsoluteOrdering)_ordering).addOthers();
else
((AbsoluteOrdering)_ordering).add(s);
}
}
}
/**
* Add a web-fragment.xml
*
* @param jarResource the jar the fragment is contained in
* @param xmlResource the resource representing the xml file
* @throws Exception
*/
public void addFragment (Resource jarResource, Resource xmlResource)
throws Exception
{
Boolean metaComplete = (Boolean)_context.getAttribute(METADATA_COMPLETE);
if (metaComplete != null && metaComplete.booleanValue())
return; //do not process anything else if web.xml/web-override.xml set metadata-complete
//Metadata-complete is not set, or there is no web.xml
FragmentDescriptor descriptor = new FragmentDescriptor(xmlResource, this);
_webFragmentResourceMap.put(jarResource, descriptor);
_webFragmentRoots.add(descriptor);
descriptor.parse();
if (descriptor.getName() != null)
_webFragmentNameMap.put(descriptor.getName(), descriptor);
//If web.xml has specified an absolute ordering, ignore any relative ordering in the fragment
if (_ordering != null && _ordering.isAbsolute())
return;
if (_ordering == null && descriptor.isOrdered())
_ordering = new RelativeOrdering();
}
/**
* Annotations not associated with a WEB-INF/lib fragment jar.
* These are from WEB-INF/classes or the ??container path??
* @param annotations
*/
public void addDiscoveredAnnotations(List<DiscoveredAnnotation> annotations)
{
_annotations.addAll(annotations);
}
public void addDiscoveredAnnotations(Resource resource, List<DiscoveredAnnotation> annotations)
{
_webFragmentAnnotations.put(resource, new ArrayList<DiscoveredAnnotation>(annotations));
}
public void addDescriptorProcessor(DescriptorProcessor p)
{
_descriptorProcessors.add(p);
}
public void orderFragments ()
{
//if we have already ordered them don't do it again
if (_orderedResources != null)
return;
if (_ordering != null)
{
//Get the jars in WEB-INF/lib according to the order specified
_orderedResources = _ordering.order((List<Resource>)_context.getAttribute(WebInfConfiguration.WEB_INF_JAR_RESOURCES));
_context.setAttribute(WebInfConfiguration.WEB_INF_ORDERED_JAR_RESOURCES, _orderedResources);
List<String> orderedJars = new ArrayList<String>();
for (Resource webInfJar:_orderedResources)
{
//get just the name of the jar file
String fullname = webInfJar.getName();
int i = fullname.indexOf(".jar");
int j = fullname.lastIndexOf("/", i);
orderedJars.add(fullname.substring(j+1,i+4));
}
_context.setAttribute(ORDERED_LIBS, orderedJars);
}
else
_orderedResources = new ArrayList<Resource>((List<Resource>)_context.getAttribute(WebInfConfiguration.WEB_INF_JAR_RESOURCES));
}
/**
* Resolve all servlet/filter/listener metadata from all sources: descriptors and annotations.
*
*/
public void resolve ()
throws Exception
{
//TODO - apply all descriptors and annotations in order:
//apply descriptorProcessors to web-defaults.xml
//apply descriptorProcessors to web.xml
//apply descriptorProcessors to web-override.xml
//apply discovered annotations from container path
//apply discovered annotations from WEB-INF/classes
//for the ordering of the jars in WEB-INF/lib:
// +apply descriptorProcessors to web-fragment.xml
// +apply discovered annotations
for (DescriptorProcessor p:_descriptorProcessors)
{
p.process(getWebDefault());
p.process(getWebXml());
p.process(getOverrideWeb());
}
for (DiscoveredAnnotation a:_annotations)
a.apply();
List<Resource> resources = getOrderedResources();
for (Resource r:resources)
{
FragmentDescriptor fd = _webFragmentResourceMap.get(r);
if (fd != null)
{
for (DescriptorProcessor p:_descriptorProcessors)
{
p.process(fd);
}
}
List<DiscoveredAnnotation> fragAnnotations = _webFragmentAnnotations.get(r);
if (fragAnnotations != null)
{
for (DiscoveredAnnotation a:fragAnnotations)
a.apply();
}
}
}
public boolean isDistributable ()
{
boolean distributable = (
(_webDefaultsRoot != null && _webDefaultsRoot.isDistributable())
|| (_webXmlRoot != null && _webXmlRoot.isDistributable())
|| (_webOverrideRoot != null && _webOverrideRoot.isDistributable()));
List<Resource> orderedResources = getOrderedResources();
for (Resource r: orderedResources)
{
FragmentDescriptor d = _webFragmentResourceMap.get(r);
if (d!=null)
distributable = distributable && d.isDistributable();
}
return distributable;
}
public Descriptor getWebXml ()
{
return _webXmlRoot;
}
public Descriptor getOverrideWeb ()
{
return _webOverrideRoot;
}
public Descriptor getWebDefault ()
{
return _webDefaultsRoot;
}
public List<FragmentDescriptor> getFragments ()
{
return _webFragmentRoots;
}
public List<Resource> getOrderedResources ()
{
return _orderedResources;
}
public List<FragmentDescriptor> getOrderedFragments ()
{
List<FragmentDescriptor> list = new ArrayList<FragmentDescriptor>();
if (_orderedResources == null)
return list;
for (Resource r:_orderedResources)
{
FragmentDescriptor fd = _webFragmentResourceMap.get(r);
if (fd != null)
list.add(fd);
}
return list;
}
public Ordering getOrdering()
{
return _ordering;
}
public void setOrdering (Ordering o)
{
_ordering = o;
}
public FragmentDescriptor getFragment (Resource jar)
{
return _webFragmentResourceMap.get(jar);
}
public FragmentDescriptor getFragment(String name)
{
return _webFragmentNameMap.get(name);
}
public Resource getJarForFragment (String name)
{
FragmentDescriptor f = getFragment(name);
if (f == null)
return null;
Resource jar = null;
for (Resource r: _webFragmentResourceMap.keySet())
{
if (_webFragmentResourceMap.get(r).equals(f))
jar = r;
}
return jar;
}
public Map<String,FragmentDescriptor> getNamedFragments ()
{
return Collections.unmodifiableMap(_webFragmentNameMap);
}
public Origin getOrigin (String name)
{
OriginInfo x = _origins.get(name);
if (x == null)
return Origin.NotSet;
return x.getOriginType();
}
public Descriptor getOriginDescriptor (String name)
{
OriginInfo o = _origins.get(name);
if (o == null)
return null;
return o.getDescriptor();
}
public void setOrigin (String name, Descriptor d)
{
OriginInfo x = new OriginInfo (name, d);
_origins.put(name, x);
}
public void setOrigin (String name)
{
if (name == null)
return;
OriginInfo x = new OriginInfo (name, Origin.Annotation);
_origins.put(name, x);
}
}

View File

@ -0,0 +1,29 @@
// ========================================================================
// Copyright (c) 2006-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.webapp;
import org.eclipse.jetty.util.resource.Resource;
/**
* OverrideDescriptor
*
*
*/
public class OverrideDescriptor extends Descriptor
{
public OverrideDescriptor(Resource xml, MetaData processor)
{
super(xml, processor);
}
}

View File

@ -45,7 +45,8 @@ import org.eclipse.jetty.xml.XmlParser;
* &lt;/bile&gt;
*
*
*
* TODO - this has been superceded by the new TldScanner in jasper which uses ServletContainerInitializer to
* find all the listeners in tag libs and register them.
*/
public class TagLibConfiguration implements Configuration
{

View File

@ -371,11 +371,16 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
// Prepare for configuration
// Prepare for configuration
//Make a new MetaData to hold descriptor and annotation metadata
MetaData metadata = new MetaData(this);
setAttribute(MetaData.METADATA, metadata);
for (int i=0;i<_configurations.length;i++)
_configurations[i].preConfigure(this);
super.doStart();
// Clean up after configuration
for (int i=0;i<_configurations.length;i++)
@ -986,12 +991,12 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
protected void startContext()
throws Exception
{
// Configure webapp
for (int i=0;i<_configurations.length;i++)
_configurations[i].configure(this);
//resolve the metadata
((MetaData)getAttribute(MetaData.METADATA)).resolve();
super.startContext();
}

View File

@ -23,6 +23,7 @@ public class WebInfConfiguration implements Configuration
public static final String TEMPDIR_CREATED = "org.eclipse.jetty.tmpdirCreated";
public static final String CONTAINER_JAR_RESOURCES = "org.eclipse.jetty.containerJars";
public static final String WEB_INF_JAR_RESOURCES = "org.eclipse.jetty.webInfJars";
public static final String WEB_INF_ORDERED_JAR_RESOURCES = "org.eclipse.jetty.webInfOrderedJars";
public static final String CONTAINER_JAR_PATTERN = "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern";
public static final String WEBINF_JAR_PATTERN = "org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern";
@ -96,6 +97,7 @@ public class WebInfConfiguration implements Configuration
}
};
List<Resource> jars = findJars(context);
//Convert to uris for matching
URI[] uris = null;
if (jars != null)

View File

@ -1,5 +1,5 @@
// ========================================================================
// Copyright (c) 2003-2009 Mort Bay Consulting Pty. Ltd.
// Copyright (c) 2003-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
@ -34,52 +34,50 @@ public class WebXmlConfiguration implements Configuration
/* ------------------------------------------------------------------------------- */
/**
* Process webdefaults.xml
*
*
*
*/
public void preConfigure (WebAppContext context) throws Exception
{
// cannot configure if the context is already started
if (context.isStarted())
{
if (Log.isDebugEnabled())
{
Log.debug("Cannot configure webapp after it is started");
}
return;
}
//Get or create a processor to handle webdefaults, web.xml and the fragments
WebXmlProcessor processor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR);
if (processor == null)
{
processor = new WebXmlProcessor (context);
context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, processor);
}
//handle webdefault.xml
MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA);
if (metaData == null)
throw new IllegalStateException("No metadata");
//parse webdefault.xml
String defaultsDescriptor = context.getDefaultsDescriptor();
if (defaultsDescriptor != null && defaultsDescriptor.length() > 0)
{
Resource dftResource = Resource.newSystemResource(defaultsDescriptor);
if (dftResource == null)
dftResource = context.newResource(defaultsDescriptor);
processor.parseDefaults (dftResource);
processor.processDefaults();
metaData.setDefaults (dftResource);
}
//parse, but don't process web.xml
Resource webxml = findWebXml(context);
if (webxml != null)
{
processor.parseWebXml(webxml);
metaData.setWebXml(webxml);
}
//parse but don't process override-web.xml
String overrideDescriptor = context.getOverrideDescriptor();
if (overrideDescriptor != null && overrideDescriptor.length() > 0)
{
Resource orideResource = Resource.newSystemResource(overrideDescriptor);
if (orideResource == null)
orideResource = context.newResource(overrideDescriptor);
metaData.setOverride(orideResource);
}
}
/* ------------------------------------------------------------------------------- */
/**
* Process web.xml, web-fragment.xml(s), override-web.xml
* Process web-default.xml, web.xml, override-web.xml
*
*/
public void configure (WebAppContext context) throws Exception
@ -90,35 +88,35 @@ public class WebXmlConfiguration implements Configuration
if (Log.isDebugEnabled()) Log.debug("Cannot configure webapp after it is started");
return;
}
WebXmlProcessor processor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR);
if (processor == null)
{
processor = new WebXmlProcessor (context);
context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, processor);
}
//process web.xml (the effective web.xml???)
processor.processWebXml();
MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA);
if (metaData == null)
throw new IllegalStateException("No metadata");
metaData.addDescriptorProcessor(new StandardDescriptorProcessor());
//process override-web.xml
String overrideDescriptor = context.getOverrideDescriptor();
if (overrideDescriptor != null && overrideDescriptor.length() > 0)
/*
StandardDescriptorProcessor descriptorProcessor = (StandardDescriptorProcessor)context.getAttribute(StandardDescriptorProcessor.STANDARD_PROCESSOR);
if (descriptorProcessor == null)
{
Resource orideResource = Resource.newSystemResource(overrideDescriptor);
if (orideResource == null)
orideResource = context.newResource(overrideDescriptor);
processor.parseOverride(orideResource);
processor.processOverride();
descriptorProcessor = new StandardDescriptorProcessor(metaData);
context.setAttribute(StandardDescriptorProcessor.STANDARD_PROCESSOR, descriptorProcessor);
}
//process web-default.xml
descriptorProcessor.process(metaData.getWebDefault());
//process web.xml
descriptorProcessor.process(metaData.getWebXml());
//process override-web.xml
descriptorProcessor.process(metaData.getOverrideWeb());
*/
}
public void postConfigure(WebAppContext context) throws Exception
{
context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, null);
context.setAttribute(WebXmlProcessor.METADATA_COMPLETE, null);
context.setAttribute(WebXmlProcessor.WEBXML_VERSION, null);
context.setAttribute(WebXmlProcessor.WEBXML_CLASSNAMES, null);
context.setAttribute(MetaData.WEBXML_CLASSNAMES, null);
}
/* ------------------------------------------------------------------------------- */

View File

@ -0,0 +1,939 @@
// ========================================================================
// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.webapp;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.MetaData.AbsoluteOrdering;
import org.eclipse.jetty.webapp.MetaData.RelativeOrdering;
/**
* OrderingTest
*
*
*/
public class OrderingTest extends TestCase
{
public class TestResource extends Resource
{
public String _name;
public TestResource (String name)
{
_name =name;
}
/**
* @see org.eclipse.jetty.util.resource.Resource#addPath(java.lang.String)
*/
public Resource addPath(String path) throws IOException, MalformedURLException
{
// TODO Auto-generated method stub
return null;
}
/**
* @see org.eclipse.jetty.util.resource.Resource#delete()
*/
public boolean delete() throws SecurityException
{
// TODO Auto-generated method stub
return false;
}
/**
* @see org.eclipse.jetty.util.resource.Resource#exists()
*/
public boolean exists()
{
// TODO Auto-generated method stub
return false;
}
/**
* @see org.eclipse.jetty.util.resource.Resource#getFile()
*/
public File getFile() throws IOException
{
// TODO Auto-generated method stub
return null;
}
/**
* @see org.eclipse.jetty.util.resource.Resource#getInputStream()
*/
public InputStream getInputStream() throws IOException
{
// TODO Auto-generated method stub
return null;
}
/**
* @see org.eclipse.jetty.util.resource.Resource#getName()
*/
public String getName()
{
return _name;
}
/**
* @see org.eclipse.jetty.util.resource.Resource#getOutputStream()
*/
public OutputStream getOutputStream() throws IOException, SecurityException
{
// TODO Auto-generated method stub
return null;
}
/**
* @see org.eclipse.jetty.util.resource.Resource#getURL()
*/
public URL getURL()
{
// TODO Auto-generated method stub
return null;
}
/**
* @see org.eclipse.jetty.util.resource.Resource#isContainedIn(org.eclipse.jetty.util.resource.Resource)
*/
public boolean isContainedIn(Resource r) throws MalformedURLException
{
// TODO Auto-generated method stub
return false;
}
/**
* @see org.eclipse.jetty.util.resource.Resource#isDirectory()
*/
public boolean isDirectory()
{
// TODO Auto-generated method stub
return false;
}
/**
* @see org.eclipse.jetty.util.resource.Resource#lastModified()
*/
public long lastModified()
{
// TODO Auto-generated method stub
return 0;
}
/**
* @see org.eclipse.jetty.util.resource.Resource#length()
*/
public long length()
{
// TODO Auto-generated method stub
return 0;
}
/**
* @see org.eclipse.jetty.util.resource.Resource#list()
*/
public String[] list()
{
// TODO Auto-generated method stub
return null;
}
/**
* @see org.eclipse.jetty.util.resource.Resource#release()
*/
public void release()
{
// TODO Auto-generated method stub
}
/**
* @see org.eclipse.jetty.util.resource.Resource#renameTo(org.eclipse.jetty.util.resource.Resource)
*/
public boolean renameTo(Resource dest) throws SecurityException
{
// TODO Auto-generated method stub
return false;
}
}
public void testRelativeOrdering0 ()
throws Exception
{
//Example from ServletSpec p.70
WebAppContext wac = new WebAppContext();
MetaData metaData = new MetaData(wac);
List<Resource> resources = new ArrayList<Resource>();
metaData._ordering = metaData.new RelativeOrdering();
//A: after others, after C
TestResource jar1 = new TestResource("A");
resources.add(jar1);
TestResource r1 = new TestResource("A/web-fragment.xml");
FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData);
f1._name = "A";
metaData._webFragmentNameMap.put(f1._name, f1);
metaData._webFragmentResourceMap.put(jar1, f1);
f1._otherType = FragmentDescriptor.OtherType.After;
//((RelativeOrdering)metaData._ordering).addAfterOthers(r1);
f1._afters.add("C");
//B: before others
TestResource jar2 = new TestResource("B");
resources.add(jar2);
TestResource r2 = new TestResource("B/web-fragment.xml");
FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData);
f2._name="B";
metaData._webFragmentNameMap.put(f2._name, f2);
metaData._webFragmentResourceMap.put(jar2, f2);
f2._otherType = FragmentDescriptor.OtherType.Before;
//((RelativeOrdering)metaData._ordering).addBeforeOthers(r2);
//C: after others
TestResource jar3 = new TestResource("C");
resources.add(jar3);
TestResource r3 = new TestResource("C/web-fragment.xml");
FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData);
f3._name="C";
metaData._webFragmentNameMap.put(f3._name, f3);
metaData._webFragmentResourceMap.put(jar3, f3);
f3._otherType = FragmentDescriptor.OtherType.After;
//((RelativeOrdering)metaData._ordering).addAfterOthers(r3);
//D: no ordering
TestResource jar4 = new TestResource("D");
resources.add(jar4);
TestResource r4 = new TestResource("D/web-fragment.xml");
FragmentDescriptor f4 = new FragmentDescriptor(r4, metaData);
f4._name="D";
metaData._webFragmentNameMap.put(f4._name, f4);
metaData._webFragmentResourceMap.put(jar4, f4);
f4._otherType = FragmentDescriptor.OtherType.None;
//((RelativeOrdering)metaData._ordering).addNoOthers(r4);
//E: no ordering
TestResource jar5 = new TestResource("E");
resources.add(jar5);
TestResource r5 = new TestResource("E/web-fragment.xml");
FragmentDescriptor f5 = new FragmentDescriptor(r5, metaData);
f5._name="E";
metaData._webFragmentNameMap.put(f5._name, f5);
metaData._webFragmentResourceMap.put(jar5, f5);
f5._otherType = FragmentDescriptor.OtherType.None;
//((RelativeOrdering)metaData._ordering).addNoOthers(r5);
//F: before others, before B
TestResource jar6 = new TestResource("F");
resources.add(jar6);
TestResource r6 = new TestResource("F/web-fragment.xml");
FragmentDescriptor f6 = new FragmentDescriptor(r6, metaData);
f6._name="F";
metaData._webFragmentNameMap.put(f6._name, f6);
metaData._webFragmentResourceMap.put(jar6,f6);
f6._otherType = FragmentDescriptor.OtherType.Before;
//((RelativeOrdering)metaData._ordering).addBeforeOthers(r6);
f6._befores.add("B");
//
// p.70 outcome: F, B, D, E, C, A
//
String[] outcomes = {"FBDECA"};
List<Resource> orderedList = metaData._ordering.order(resources);
String result = "";
for (Resource r:orderedList)
result+=(((TestResource)r)._name);
if (!checkResult(result, outcomes))
fail("No outcome matched "+result);
}
public void testRelativeOrdering1 ()
throws Exception
{
List<Resource> resources = new ArrayList<Resource>();
WebAppContext wac = new WebAppContext();
MetaData metaData = new MetaData(wac);
metaData._ordering = metaData.new RelativeOrdering();
//Example from ServletSpec p.70-71
//No name: after others, before C
TestResource jar1 = new TestResource("plain");
resources.add(jar1);
TestResource r1 = new TestResource("plain/web-fragment.xml");
FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData);
f1._name = FragmentDescriptor.NAMELESS+"1";
metaData._webFragmentNameMap.put(f1._name, f1);
metaData._webFragmentResourceMap.put(jar1,f1);
f1._otherType = FragmentDescriptor.OtherType.After;
//((RelativeOrdering)metaData._ordering).addAfterOthers(f1);
f1._befores.add("C");
//B: before others
TestResource jar2 = new TestResource("B");
resources.add(jar2);
TestResource r2 = new TestResource("B/web-fragment.xml");
FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData);
f2._name="B";
metaData._webFragmentNameMap.put(f2._name, f2);
metaData._webFragmentResourceMap.put(jar2,f2);
f2._otherType = FragmentDescriptor.OtherType.Before;
//((RelativeOrdering)metaData._ordering).addBeforeOthers(f2);
//C: no ordering
TestResource jar3 = new TestResource("C");
resources.add(jar3);
TestResource r3 = new TestResource("C/web-fragment.xml");
FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData);
f3._name="C";
metaData._webFragmentNameMap.put(f3._name, f3);
metaData._webFragmentResourceMap.put(jar3,f3);
//((RelativeOrdering)metaData._ordering).addNoOthers(f3);
f3._otherType = FragmentDescriptor.OtherType.None;
//D: after others
TestResource jar4 = new TestResource("D");
resources.add(jar4);
TestResource r4 = new TestResource("D/web-fragment.xml");
FragmentDescriptor f4 = new FragmentDescriptor(r4, metaData);
f4._name="D";
metaData._webFragmentNameMap.put(f4._name, f4);
metaData._webFragmentResourceMap.put(jar4,f4);
//((RelativeOrdering)metaData._ordering).addAfterOthers(f4);
f4._otherType = FragmentDescriptor.OtherType.After;
//E: before others
TestResource jar5 = new TestResource("E");
resources.add(jar5);
TestResource r5 = new TestResource("E/web-fragment.xml");
FragmentDescriptor f5 = new FragmentDescriptor(r5, metaData);
f5._name="E";
metaData._webFragmentNameMap.put(f5._name, f5);
metaData._webFragmentResourceMap.put(jar5,f5);
//((RelativeOrdering)metaData._ordering).addBeforeOthers(f5);
f5._otherType = FragmentDescriptor.OtherType.Before;
//F: no ordering
TestResource jar6 = new TestResource("F");
resources.add(jar6);
TestResource r6 = new TestResource("F/web-fragment.xml");
FragmentDescriptor f6 = new FragmentDescriptor(r6, metaData);
f6._name="F";
metaData._webFragmentNameMap.put(f6._name, f6);
metaData._webFragmentResourceMap.put(jar6,f6);
//((RelativeOrdering)metaData._ordering).addNoOthers(f6);
f6._otherType = FragmentDescriptor.OtherType.None;
List<Resource> orderedList = metaData._ordering.order(resources);
// p.70-71 Possible outcomes are:
// B, E, F, noname, C, D
// B, E, F, noname, D, C
// E, B, F, noname, C, D
// E, B, F, noname, D, C
// E, B, F, D, noname, C
//
String[] outcomes = {"BEFplainCD",
"BEFplainDC",
"EBFplainCD",
"EBFplainDC",
"EBFDplain"};
String orderedNames = "";
for (Resource r:orderedList)
orderedNames+=(((TestResource)r)._name);
if (!checkResult(orderedNames, outcomes))
fail("No outcome matched "+orderedNames);
}
public void testRelativeOrdering2 ()
throws Exception
{
List<Resource> resources = new ArrayList<Resource>();
WebAppContext wac = new WebAppContext();
MetaData metaData = new MetaData(wac);
metaData._ordering = metaData.new RelativeOrdering();
//Example from Spec p. 71-72
//A: after B
TestResource jar1 = new TestResource("A");
resources.add(jar1);
TestResource r1 = new TestResource("A/web-fragment.xml");
FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData);
f1._name = "A";
metaData._webFragmentNameMap.put(f1._name, f1);
metaData._webFragmentResourceMap.put(jar1, f1);
//((RelativeOrdering)metaData._ordering).addNoOthers(f1);
f1._otherType = FragmentDescriptor.OtherType.None;
f1._afters.add("B");
//B: no order
TestResource jar2 = new TestResource("B");
resources.add(jar2);
TestResource r2 = new TestResource("B/web-fragment.xml");
FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData);
f2._name="B";
metaData._webFragmentNameMap.put(f2._name, f2);
metaData._webFragmentResourceMap.put(jar2, f2);
//((RelativeOrdering)metaData._ordering).addNoOthers(f2);
f2._otherType = FragmentDescriptor.OtherType.None;
//C: before others
TestResource jar3 = new TestResource("C");
resources.add(jar3);
TestResource r3 = new TestResource("C/web-fragment.xml");
FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData);
f3._name="C";
metaData._webFragmentNameMap.put(f3._name, f3);
metaData._webFragmentResourceMap.put(jar3,f3);
//((RelativeOrdering)metaData._ordering).addBeforeOthers(f3);
f3._otherType = FragmentDescriptor.OtherType.Before;
//D: no order
TestResource jar4 = new TestResource("D");
resources.add(jar4);
TestResource r4 = new TestResource("D/web-fragment.xml");
FragmentDescriptor f4 = new FragmentDescriptor(r4, metaData);
f4._name="D";
metaData._webFragmentNameMap.put(f4._name, f4);
metaData._webFragmentResourceMap.put(jar4, f4);
//((RelativeOrdering)metaData._ordering).addNoOthers(f4);
f4._otherType = FragmentDescriptor.OtherType.None;
//
// p.71-72 possible outcomes are:
// C,B,D,A
// C,D,B,A
// C,B,A,D
//
String[] outcomes = {"CBDA",
"CDBA",
"CBAD"};
List<Resource> orderedList = metaData._ordering.order(resources);
String result = "";
for (Resource r:orderedList)
result+=(((TestResource)r)._name);
if (!checkResult(result, outcomes))
fail ("No outcome matched "+result);
}
public void testRelativeOrdering3 ()
throws Exception
{
List<Resource> resources = new ArrayList<Resource>();
WebAppContext wac = new WebAppContext();
MetaData metaData = new MetaData(wac);
metaData._ordering = metaData.new RelativeOrdering();
//A: after others, before C
TestResource jar1 = new TestResource("A");
resources.add(jar1);
TestResource r1 = new TestResource("A/web-fragment.xml");
FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData);
f1._name = "A";
metaData._webFragmentNameMap.put(f1._name, f1);
metaData._webFragmentResourceMap.put(jar1, f1);
//((RelativeOrdering)metaData._ordering).addAfterOthers(f1);
f1._otherType = FragmentDescriptor.OtherType.After;
f1._befores.add("C");
//B: before others, before C
TestResource jar2 = new TestResource("B");
resources.add(jar2);
TestResource r2 = new TestResource("B/web-fragment.xml");
FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData);
f2._name="B";
metaData._webFragmentNameMap.put(f2._name, f2);
metaData._webFragmentResourceMap.put(jar2,f2);
//((RelativeOrdering)metaData._ordering).addBeforeOthers(f2);
f2._otherType = FragmentDescriptor.OtherType.Before;
f2._befores.add("C");
//C: no ordering
TestResource jar3 = new TestResource("C");
resources.add(jar3);
TestResource r3 = new TestResource("C/web-fragment.xml");
FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData);
f3._name="C";
metaData._webFragmentNameMap.put(f3._name, f3);
metaData._webFragmentResourceMap.put(jar3,f3);
//((RelativeOrdering)metaData._ordering).addNoOthers(f3);
f3._otherType = FragmentDescriptor.OtherType.None;
//result: BAC
String[] outcomes = {"BAC"};
List<Resource> orderedList = metaData._ordering.order(resources);
String result = "";
for (Resource r:orderedList)
result+=(((TestResource)r)._name);
if (!checkResult(result, outcomes))
fail ("No outcome matched "+result);
}
public void testCircular1 ()
throws Exception
{
//A: after B
//B: after A
List<Resource> resources = new ArrayList<Resource>();
WebAppContext wac = new WebAppContext();
MetaData metaData = new MetaData(wac);
metaData._ordering = metaData.new RelativeOrdering();
//A: after B
TestResource jar1 = new TestResource("A");
resources.add(jar1);
TestResource r1 = new TestResource("A/web-fragment.xml");
FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData);
f1._name = "A";
metaData._webFragmentNameMap.put(f1._name, f1);
metaData._webFragmentResourceMap.put(jar1, f1);
//((RelativeOrdering)metaData._ordering).addNoOthers(f1);
f1._otherType = FragmentDescriptor.OtherType.None;
f1._afters.add("B");
//B: after A
TestResource jar2 = new TestResource("B");
resources.add(jar2);
TestResource r2 = new TestResource("B/web-fragment.xml");
FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData);
f2._name="B";
metaData._webFragmentNameMap.put(f2._name, f2);
metaData._webFragmentResourceMap.put(jar2, f2);
//((RelativeOrdering)metaData._ordering).addNoOthers(f2);
f2._otherType = FragmentDescriptor.OtherType.None;
f2._afters.add("A");
try
{
List<Resource> orderedList = metaData._ordering.order(resources);
fail("No circularity detected");
}
catch (Exception e)
{
assertTrue (e instanceof IllegalStateException);
}
}
public void testInvalid1 ()
throws Exception
{
List<Resource> resources = new ArrayList<Resource>();
WebAppContext wac = new WebAppContext();
MetaData metaData = new MetaData(wac);
metaData._ordering = metaData.new RelativeOrdering();
//A: after others, before C
TestResource jar1 = new TestResource("A");
resources.add(jar1);
TestResource r1 = new TestResource("A/web-fragment.xml");
FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData);
f1._name = "A";
metaData._webFragmentNameMap.put(f1._name, f1);
metaData._webFragmentResourceMap.put(jar1,f1);
//((RelativeOrdering)metaData._ordering).addAfterOthers(r1);
f1._otherType = FragmentDescriptor.OtherType.After;
f1._befores.add("C");
//B: before others, after C
TestResource jar2 = new TestResource("B");
resources.add(jar2);
TestResource r2 = new TestResource("B/web-fragment.xml");
FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData);
f2._name="B";
metaData._webFragmentNameMap.put(f2._name, f2);
metaData._webFragmentResourceMap.put(jar2,f2);
//((RelativeOrdering)metaData._ordering).addBeforeOthers(r2);
f2._otherType = FragmentDescriptor.OtherType.Before;
f2._afters.add("C");
//C: no ordering
TestResource jar3 = new TestResource("C");
resources.add(jar3);
TestResource r3 = new TestResource("C/web-fragment.xml");
FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData);
f3._name="C";
metaData._webFragmentNameMap.put(f3._name, f3);
metaData._webFragmentResourceMap.put(jar3,f3);
//((RelativeOrdering)metaData._ordering).addNoOthers(r3);
f3._otherType = FragmentDescriptor.OtherType.None;
try
{
List<Resource> orderedList = metaData._ordering.order(resources);
String result = "";
for (Resource r:orderedList)
result +=((TestResource)r)._name;
System.err.println("Invalid Result = "+result);
fail("A and B have an impossible relationship to C");
}
catch (Exception e)
{
assertTrue (e instanceof IllegalStateException);
}
}
public void testAbsoluteOrdering1 ()
throws Exception
{
//
// A,B,C,others
//
List<Resource> resources = new ArrayList<Resource>();
WebAppContext wac = new WebAppContext();
MetaData metaData = new MetaData(wac);
metaData._ordering = metaData.new AbsoluteOrdering();
((AbsoluteOrdering)metaData._ordering).add("A");
((AbsoluteOrdering)metaData._ordering).add("B");
((AbsoluteOrdering)metaData._ordering).add("C");
((AbsoluteOrdering)metaData._ordering).addOthers();
TestResource jar1 = new TestResource("A");
resources.add(jar1);
TestResource r1 = new TestResource("A/web-fragment.xml");
FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData);
f1._name = "A";
metaData._webFragmentNameMap.put(f1._name, f1);
metaData._webFragmentResourceMap.put(jar1,f1);
TestResource jar2 = new TestResource("B");
resources.add(jar2);
TestResource r2 = new TestResource("B/web-fragment.xml");
FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData);
f2._name="B";
metaData._webFragmentNameMap.put(f2._name, f2);
metaData._webFragmentResourceMap.put(jar2, f2);
TestResource jar3 = new TestResource("C");
resources.add(jar3);
TestResource r3 = new TestResource("C/web-fragment.xml");
FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData);
f3._name="C";
metaData._webFragmentNameMap.put(f3._name, f3);
metaData._webFragmentResourceMap.put(jar3, f3);
TestResource jar4 = new TestResource("D");
resources.add(jar4);
TestResource r4 = new TestResource("D/web-fragment.xml");
FragmentDescriptor f4 = new FragmentDescriptor((Resource)null, metaData);
f4._name="D";
metaData._webFragmentNameMap.put(f4._name, f4);
metaData._webFragmentResourceMap.put(jar4, f4);
TestResource jar5 = new TestResource("E");
resources.add(jar5);
TestResource r5 = new TestResource("E/web-fragment.xml");
FragmentDescriptor f5 = new FragmentDescriptor((Resource)null, metaData);
f5._name="E";
metaData._webFragmentNameMap.put(f5._name, f5);
metaData._webFragmentResourceMap.put(jar5, f5);
TestResource jar6 = new TestResource("plain");
resources.add(jar6);
TestResource r6 = new TestResource ("plain/web-fragment.xml");
FragmentDescriptor f6 = new FragmentDescriptor((Resource)null, metaData);
f6._name=FragmentDescriptor.NAMELESS+"1";
metaData._webFragmentNameMap.put(f6._name, f6);
metaData._webFragmentResourceMap.put(jar6, f6);
List<Resource> list = metaData._ordering.order(resources);
String[] outcomes = {"ABCDEplain"};
String result = "";
for (Resource r:list)
result += ((TestResource)r)._name;
if (!checkResult(result, outcomes))
fail("No outcome matched "+result);
}
public void testAbsoluteOrdering2 ()
throws Exception
{
// C,B,A
List<Resource> resources = new ArrayList<Resource>();
WebAppContext wac = new WebAppContext();
MetaData metaData = new MetaData(wac);
metaData._ordering = metaData.new AbsoluteOrdering();
((AbsoluteOrdering)metaData._ordering).add("C");
((AbsoluteOrdering)metaData._ordering).add("B");
((AbsoluteOrdering)metaData._ordering).add("A");
TestResource jar1 = new TestResource("A");
resources.add(jar1);
TestResource r1 = new TestResource("A/web-fragment.xml");
FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData);
f1._name = "A";
metaData._webFragmentNameMap.put(f1._name, f1);
metaData._webFragmentResourceMap.put(jar1,f1);
TestResource jar2 = new TestResource("B");
resources.add(jar2);
TestResource r2 = new TestResource("B/web-fragment.xml");
FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData);
f2._name="B";
metaData._webFragmentNameMap.put(f2._name, f2);
metaData._webFragmentResourceMap.put(jar2,f2);
TestResource jar3 = new TestResource("C");
resources.add(jar3);
TestResource r3 = new TestResource("C/web-fragment.xml");
FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData);
f3._name="C";
metaData._webFragmentNameMap.put(f3._name, f3);
metaData._webFragmentResourceMap.put(jar3,f3);
TestResource jar4 = new TestResource("D");
resources.add(jar4);
TestResource r4 = new TestResource("D/web-fragment.xml");
FragmentDescriptor f4 = new FragmentDescriptor(r4, metaData);
f4._name="D";
metaData._webFragmentNameMap.put(f4._name, f4);
metaData._webFragmentResourceMap.put(jar4,f4);
TestResource jar5 = new TestResource("E");
resources.add(jar5);
TestResource r5 = new TestResource("E/web-fragment.xml");
FragmentDescriptor f5 = new FragmentDescriptor(r5, metaData);
f5._name="E";
metaData._webFragmentNameMap.put(f5._name, f5);
metaData._webFragmentResourceMap.put(jar5,f5);
TestResource jar6 = new TestResource("plain");
resources.add(jar6);
TestResource r6 = new TestResource("plain/web-fragment.xml");
FragmentDescriptor f6 = new FragmentDescriptor(r6, metaData);
f6._name=FragmentDescriptor.NAMELESS+"1";
metaData._webFragmentNameMap.put(f6._name, f6);
metaData._webFragmentResourceMap.put(jar6,f6);
List<Resource> list = metaData._ordering.order(resources);
String[] outcomes = {"CBA"};
String result = "";
for (Resource r:list)
result += ((TestResource)r)._name;
if (!checkResult(result, outcomes))
fail("No outcome matched "+result);
}
public void testAbsoluteOrdering3 ()
throws Exception
{
//empty <absolute-ordering>
WebAppContext wac = new WebAppContext();
MetaData metaData = new MetaData(wac);
metaData._ordering = metaData.new AbsoluteOrdering();
List<Resource> resources = new ArrayList<Resource>();
resources.add(new TestResource("A"));
resources.add(new TestResource("B"));
List<Resource> list = metaData._ordering.order(resources);
assertTrue(list.isEmpty());
}
public void testRelativeOrderingWithPlainJars ()
throws Exception
{
//B,A,C other jars with no fragments
List<Resource> resources = new ArrayList<Resource>();
WebAppContext wac = new WebAppContext();
MetaData metaData = new MetaData(wac);
metaData._ordering = metaData.new RelativeOrdering();
//A: after others, before C
TestResource jar1 = new TestResource("A");
resources.add(jar1);
TestResource r1 = new TestResource("A/web-fragment.xml");
FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData);
f1._name = "A";
metaData._webFragmentNameMap.put(f1._name, f1);
metaData._webFragmentResourceMap.put(jar1, f1);
//((RelativeOrdering)metaData._ordering).addAfterOthers(f1);
f1._otherType = FragmentDescriptor.OtherType.After;
f1._befores.add("C");
//B: before others, before C
TestResource jar2 = new TestResource("B");
resources.add(jar2);
TestResource r2 = new TestResource("B/web-fragment.xml");
FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData);
f2._name="B";
metaData._webFragmentNameMap.put(f2._name, f2);
metaData._webFragmentResourceMap.put(jar2,f2);
//((RelativeOrdering)metaData._ordering).addBeforeOthers(f2);
f2._otherType = FragmentDescriptor.OtherType.Before;
f2._befores.add("C");
//C: after A
TestResource jar3 = new TestResource("C");
resources.add(jar3);
TestResource r3 = new TestResource("C/web-fragment.xml");
FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData);
f3._name="C";
metaData._webFragmentNameMap.put(f3._name, f3);
metaData._webFragmentResourceMap.put(jar3,f3);
//((RelativeOrdering)metaData._ordering).addNoOthers(f3);
f3._otherType = FragmentDescriptor.OtherType.None;
f3._afters.add("A");
//No fragment jar 1
TestResource r4 = new TestResource("plain1");
resources.add(r4);
//No fragment jar 2
TestResource r5 = new TestResource("plain2");
resources.add(r5);
//result: BAC
String[] outcomes = {"Bplain1plain2AC"};
List<Resource> orderedList = metaData._ordering.order(resources);
String result = "";
for (Resource r:orderedList)
result+=(((TestResource)r)._name);
if (!checkResult(result, outcomes))
fail ("No outcome matched "+result);
}
public void testAbsoluteOrderingWithPlainJars()
throws Exception
{
//
// A,B,C,others
//
List<Resource> resources = new ArrayList<Resource>();
WebAppContext wac = new WebAppContext();
MetaData metaData = new MetaData(wac);
metaData._ordering = metaData.new AbsoluteOrdering();
((AbsoluteOrdering)metaData._ordering).add("A");
((AbsoluteOrdering)metaData._ordering).add("B");
((AbsoluteOrdering)metaData._ordering).add("C");
((AbsoluteOrdering)metaData._ordering).addOthers();
TestResource jar1 = new TestResource("A");
resources.add(jar1);
TestResource r1 = new TestResource("A/web-fragment.xml");
FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData);
f1._name = "A";
metaData._webFragmentNameMap.put(f1._name, f1);
metaData._webFragmentResourceMap.put(jar1,f1);
TestResource jar2 = new TestResource("B");
resources.add(jar2);
TestResource r2 = new TestResource("B/web-fragment.xml");
FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData);
f2._name="B";
metaData._webFragmentNameMap.put(f2._name, f2);
metaData._webFragmentResourceMap.put(jar2, f2);
TestResource jar3 = new TestResource("C");
resources.add(jar3);
TestResource r3 = new TestResource("C/web-fragment.xml");
FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData);
f3._name="C";
metaData._webFragmentNameMap.put(f3._name, f3);
metaData._webFragmentResourceMap.put(jar3, f3);
TestResource jar4 = new TestResource("D");
resources.add(jar4);
TestResource r4 = new TestResource("D/web-fragment.xml");
FragmentDescriptor f4 = new FragmentDescriptor((Resource)null, metaData);
f4._name="D";
metaData._webFragmentNameMap.put(f4._name, f4);
metaData._webFragmentResourceMap.put(jar4, f4);
TestResource jar5 = new TestResource("E");
resources.add(jar5);
TestResource r5 = new TestResource("E/web-fragment.xml");
FragmentDescriptor f5 = new FragmentDescriptor((Resource)null, metaData);
f5._name="E";
metaData._webFragmentNameMap.put(f5._name, f5);
metaData._webFragmentResourceMap.put(jar5, f5);
TestResource jar6 = new TestResource("plain");
resources.add(jar6);
TestResource r6 = new TestResource("plain/web-fragment.xml");
FragmentDescriptor f6 = new FragmentDescriptor((Resource)null, metaData);
f6._name=FragmentDescriptor.NAMELESS+"1";
metaData._webFragmentNameMap.put(f6._name, f6);
metaData._webFragmentResourceMap.put(jar6, f6);
//plain jar
TestResource r7 = new TestResource("plain1");
resources.add(r7);
TestResource r8 = new TestResource("plain2");
resources.add(r8);
List<Resource> list = metaData._ordering.order(resources);
String[] outcomes = {"ABCDEplainplain1plain2"};
String result = "";
for (Resource r:list)
result += ((TestResource)r)._name;
if (!checkResult(result, outcomes))
fail("No outcome matched "+result);
}
public boolean checkResult (String result, String[] outcomes)
{
boolean matched = false;
for (String s:outcomes)
{
if (s.equals(result))
matched = true;
}
return matched;
}
}