New Configuration structure. This structure will be modified in jetty-8 to accommodate servlet spec3. This checkin moves jetty-7 closer to that final structure. Configuration now consists of 3 phases: preConfigure(), configure() and postConfigure(). All Configurations can now be chained together rather than having to override/replace existing Configurations.

git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@230 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
Jan Bartel 2009-05-19 07:40:36 +00:00
parent c236945c53
commit 688fbac7aa
19 changed files with 2582 additions and 2148 deletions

View File

@ -141,7 +141,7 @@ public class AnnotationProcessor
{ {
for (Class clazz:_finder.getClassesForAnnotation(RunAs.class)) for (Class clazz:_finder.getClassesForAnnotation(RunAs.class))
{ {
if (!javax.servlet.Servlet.class.isAssignableFrom(clazz) && !(_pojoInstances.containsKey(clazz))) if (!javax.servlet.Servlet.class.isAssignableFrom(clazz))
{ {
Log.debug("Ignoring runAs notation on on-servlet class "+clazz.getName()); Log.debug("Ignoring runAs notation on on-servlet class "+clazz.getName());
continue; continue;
@ -611,8 +611,7 @@ public class AnnotationProcessor
javax.servlet.ServletRequestListener.class.isAssignableFrom(c) || javax.servlet.ServletRequestListener.class.isAssignableFrom(c) ||
javax.servlet.ServletRequestAttributeListener.class.isAssignableFrom(c) || javax.servlet.ServletRequestAttributeListener.class.isAssignableFrom(c) ||
javax.servlet.http.HttpSessionListener.class.isAssignableFrom(c) || javax.servlet.http.HttpSessionListener.class.isAssignableFrom(c) ||
javax.servlet.http.HttpSessionAttributeListener.class.isAssignableFrom(c) || javax.servlet.http.HttpSessionAttributeListener.class.isAssignableFrom(c))
(_pojoInstances.get(c) != null))
isServlet=true; isServlet=true;
@ -620,26 +619,7 @@ public class AnnotationProcessor
} }
/**
* Get an already-created instance of a pojo, or create one
* otherwise.
* @param clazz
* @return
* @throws InstantiationException
* @throws IllegalAccessException
*/
private Object getPojoInstanceFor (Class clazz)
throws InstantiationException, IllegalAccessException
{
Object instance = _pojoInstances.get(clazz);
if (instance == null)
{
instance = clazz.newInstance();
_pojoInstances.put(clazz, instance);
}
return instance;
}
private static boolean isEnvEntryType (Class type) private static boolean isEnvEntryType (Class type)
{ {
boolean result = false; boolean result = false;

View File

@ -14,13 +14,17 @@
package org.eclipse.jetty.annotations; package org.eclipse.jetty.annotations;
import java.util.EventListener; import java.util.EventListener;
import java.util.List;
import org.eclipse.jetty.plus.servlet.ServletHandler;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.FilterMapping; import org.eclipse.jetty.servlet.FilterMapping;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.ServletMapping; import org.eclipse.jetty.servlet.ServletMapping;
import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.LazyList;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.webapp.WebAppContext;
/** /**
* Configuration * Configuration
@ -42,7 +46,7 @@ public class Configuration extends org.eclipse.jetty.plus.webapp.Configuration
/** /**
* @see org.eclipse.jetty.plus.webapp.AbstractConfiguration#parseAnnotations() * @see org.eclipse.jetty.plus.webapp.AbstractConfiguration#parseAnnotations()
*/ */
public void parseAnnotations() throws Exception public void parseAnnotations(final WebAppContext context) throws Exception
{ {
/* /*
* TODO Need to also take account of hidden classes on system classpath that should never * TODO Need to also take account of hidden classes on system classpath that should never
@ -67,20 +71,20 @@ public class Configuration extends org.eclipse.jetty.plus.webapp.Configuration
//if no pattern for the container path is defined, then by default scan NOTHING //if no pattern for the container path is defined, then by default scan NOTHING
Log.debug("Scanning system jars"); Log.debug("Scanning system jars");
finder.find(getWebAppContext().getClassLoader().getParent(), true, getWebAppContext().getInitParameter(__container_pattern), false, finder.find(context.getClassLoader().getParent(), true, context.getInitParameter(__container_pattern), false,
new ClassNameResolver () new ClassNameResolver ()
{ {
public boolean isExcluded (String name) public boolean isExcluded (String name)
{ {
if (getWebAppContext().isSystemClass(name)) return false; if (context.isSystemClass(name)) return false;
if (getWebAppContext().isServerClass(name)) return true; if (context.isServerClass(name)) return true;
return false; return false;
} }
public boolean shouldOverride (String name) public boolean shouldOverride (String name)
{ {
//looking at system classpath //looking at system classpath
if (getWebAppContext().isParentLoaderPriority()) if (context.isParentLoaderPriority())
return true; return true;
return false; return false;
} }
@ -88,58 +92,67 @@ public class Configuration extends org.eclipse.jetty.plus.webapp.Configuration
Log.debug("Scanning WEB-INF/lib jars"); Log.debug("Scanning WEB-INF/lib jars");
//if no pattern for web-inf/lib is defined, then by default scan everything in it //if no pattern for web-inf/lib is defined, then by default scan everything in it
finder.find (getWebAppContext().getClassLoader(), false, getWebAppContext().getInitParameter(__web_inf_pattern), true, finder.find (context.getClassLoader(), false, context.getInitParameter(__web_inf_pattern), true,
new ClassNameResolver() new ClassNameResolver()
{ {
public boolean isExcluded (String name) public boolean isExcluded (String name)
{ {
if (getWebAppContext().isSystemClass(name)) return true; if (context.isSystemClass(name)) return true;
if (getWebAppContext().isServerClass(name)) return false; if (context.isServerClass(name)) return false;
return false; return false;
} }
public boolean shouldOverride (String name) 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? //looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp?
if (getWebAppContext().isParentLoaderPriority()) if (context.isParentLoaderPriority())
return false; return false;
return true; return true;
} }
}); });
Log.debug("Scanning classes in WEB-INF/classes"); Log.debug("Scanning classes in WEB-INF/classes");
finder.find(_context.getWebInf().addPath("classes/"), finder.find(context.getWebInf().addPath("classes/"),
new ClassNameResolver() new ClassNameResolver()
{ {
public boolean isExcluded (String name) public boolean isExcluded (String name)
{ {
if (getWebAppContext().isSystemClass(name)) return true; if (context.isSystemClass(name)) return true;
if (getWebAppContext().isServerClass(name)) return false; if (context.isServerClass(name)) return false;
return false; return false;
} }
public boolean shouldOverride (String name) 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? //looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp?
if (getWebAppContext().isParentLoaderPriority()) if (context.isParentLoaderPriority())
return false; return false;
return true; return true;
} }
}); });
AnnotationProcessor processor = new AnnotationProcessor(getWebAppContext(), finder, _runAsCollection, _injections, _callbacks, ServletHandler servletHandler = (ServletHandler)context.getServletHandler();
LazyList.getList(_servlets), LazyList.getList(_filters), LazyList.getList(_listeners), List filters = LazyList.array2List(servletHandler.getFilters());
LazyList.getList(_servletMappings), LazyList.getList(_filterMappings)); List filterMappings = LazyList.array2List(servletHandler.getFilterMappings());
List servlets = LazyList.array2List(servletHandler.getServlets());
List servletMappings = LazyList.array2List(servletHandler.getServletMappings());
List listeners = LazyList.array2List(context.getEventListeners());
AnnotationProcessor processor = new AnnotationProcessor(context, finder, _runAsCollection, _injections, _callbacks,
servlets, filters,listeners,
servletMappings, filterMappings);
processor.process(); processor.process();
_servlets = processor.getServlets();
_filters = processor.getFilters(); servlets = processor.getServlets();
_servletMappings = processor.getServletMappings(); filters = processor.getFilters();
_filterMappings = processor.getFilterMappings(); servletMappings = processor.getServletMappings();
_listeners = processor.getListeners(); filterMappings = processor.getFilterMappings();
_servletHandler.setFilters((FilterHolder[])LazyList.toArray(_filters,FilterHolder.class)); listeners = processor.getListeners();
_servletHandler.setFilterMappings((FilterMapping[])LazyList.toArray(_filterMappings,FilterMapping.class));
_servletHandler.setServlets((ServletHolder[])LazyList.toArray(_servlets,ServletHolder.class)); servletHandler.setFilters((FilterHolder[])LazyList.toArray(filters,FilterHolder.class));
_servletHandler.setServletMappings((ServletMapping[])LazyList.toArray(_servletMappings,ServletMapping.class)); servletHandler.setFilterMappings((FilterMapping[])LazyList.toArray(filterMappings,FilterMapping.class));
getWebAppContext().setEventListeners((EventListener[])LazyList.toArray(_listeners,EventListener.class)); servletHandler.setServlets((ServletHolder[])LazyList.toArray(servlets,ServletHolder.class));
servletHandler.setServletMappings((ServletMapping[])LazyList.toArray(servletMappings,ServletMapping.class));
context.setEventListeners((EventListener[])LazyList.toArray(listeners,EventListener.class));
} }
} }

View File

@ -42,6 +42,9 @@
<!-- =========================================================== --> <!-- =========================================================== -->
<Array id="plusConfig" type="java.lang.String"> <Array id="plusConfig" type="java.lang.String">
<Item>org.eclipse.jetty.webapp.WebInfConfiguration</Item> <Item>org.eclipse.jetty.webapp.WebInfConfiguration</Item>
<Item>org.eclipse.jetty.webapp.WebXmlConfiguration</Item>
<Item>org.eclipse.jetty.webapp.MetaInfConfiguration</Item>
<Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item>
<Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item> <Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>
<Item>org.eclipse.jetty.plus.webapp.Configuration</Item> <Item>org.eclipse.jetty.plus.webapp.Configuration</Item>
<Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item> <Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>

View File

@ -201,6 +201,7 @@ public abstract class NamingEntry
objectName.addAll(0, prefix); objectName.addAll(0, prefix);
objectNameString = objectName.toString(); objectNameString = objectName.toString();
NamingUtil.bind(ic, objectNameString, objectToBind); NamingUtil.bind(ic, objectNameString, objectToBind);
System.err.println("Bound: "+objectName.toString()+" to "+objectToBind);
} }
} }

View File

@ -239,7 +239,7 @@ public class NamingEntryUtil
if (scope==null) if (scope==null)
return ""; return "";
String str = scope.toString(); String str = scope.getClass().getName()+"@"+scope.hashCode();
str=str.replace('/', '_').replace(' ', '_'); str=str.replace('/', '_').replace(' ', '_');
return str; return str;
} }

View File

@ -31,8 +31,10 @@ import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebXmlConfiguration; import org.eclipse.jetty.webapp.WebXmlConfiguration;
import org.eclipse.jetty.webapp.WebXmlProcessor;
import org.eclipse.jetty.xml.XmlParser; import org.eclipse.jetty.xml.XmlParser;
@ -42,22 +44,348 @@ import org.eclipse.jetty.xml.XmlParser;
* *
* *
*/ */
public abstract class AbstractConfiguration extends WebXmlConfiguration public abstract class AbstractConfiguration implements Configuration
{ {
protected LifeCycleCallbackCollection _callbacks = new LifeCycleCallbackCollection(); protected LifeCycleCallbackCollection _callbacks = new LifeCycleCallbackCollection();
protected InjectionCollection _injections = new InjectionCollection(); protected InjectionCollection _injections = new InjectionCollection();
protected RunAsCollection _runAsCollection = new RunAsCollection(); protected RunAsCollection _runAsCollection = new RunAsCollection();
protected SecurityHandler _securityHandler; protected SecurityHandler _securityHandler;
public abstract void bindEnvEntry (String name, Object value) throws Exception; public abstract void bindEnvEntry (WebAppContext context, String name, Object value) throws Exception;
public abstract void bindResourceRef (String name, Class type) throws Exception; public abstract void bindResourceRef (WebAppContext context, String name, Class type) throws Exception;
public abstract void bindResourceEnvRef (String name, Class type) throws Exception; public abstract void bindResourceEnvRef (WebAppContext context, String name, Class type) throws Exception;
public abstract void bindUserTransaction () throws Exception; public abstract void bindUserTransaction (WebAppContext context) throws Exception;
public abstract void bindMessageDestinationRef (WebAppContext context, String name, Class type) throws Exception;
protected abstract void parseAnnotations (WebAppContext context) throws Exception;
public class PlusWebXmlProcessor
{
WebAppContext _context;
public PlusWebXmlProcessor (WebAppContext context)
{
_context = context;
}
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;
}
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;
}
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
* @return the type of the injectable
*/
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;
}
// 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.setTargetClass(clazz);
injection.setJndiName(jndiName);
injection.setTarget(clazz, targetName, valueClass);
_injections.add(injection);
}
catch (ClassNotFoundException e)
{
Log.warn("Couldn't load injection target class "+targetClassName);
}
}
}
}
public abstract void bindMessageDestinationRef (String name, Class type) throws Exception;
/** /**
@ -68,388 +396,82 @@ public abstract class AbstractConfiguration extends WebXmlConfiguration
super(); super();
} }
public void setWebAppContext (WebAppContext context) public void preConfigure (WebAppContext context)
throws Exception
{ {
super.setWebAppContext(context); //set up our special ServletHandler to remember injections and lifecycle callbacks
//set up our special ServletHandler to remember injections and lifecycle callbacks
ServletHandler servletHandler = new ServletHandler(); ServletHandler servletHandler = new ServletHandler();
_securityHandler = getWebAppContext().getSecurityHandler(); _securityHandler = context.getSecurityHandler();
org.eclipse.jetty.servlet.ServletHandler existingHandler = getWebAppContext().getServletHandler(); org.eclipse.jetty.servlet.ServletHandler existingHandler = context.getServletHandler();
servletHandler.setFilterMappings(existingHandler.getFilterMappings()); servletHandler.setFilterMappings(existingHandler.getFilterMappings());
servletHandler.setFilters(existingHandler.getFilters()); servletHandler.setFilters(existingHandler.getFilters());
servletHandler.setServlets(existingHandler.getServlets()); servletHandler.setServlets(existingHandler.getServlets());
servletHandler.setServletMappings(existingHandler.getServletMappings()); servletHandler.setServletMappings(existingHandler.getServletMappings());
getWebAppContext().setServletHandler(servletHandler); context.setServletHandler(servletHandler);
_securityHandler.setHandler(servletHandler); _securityHandler.setHandler(servletHandler);
}
public void configureDefaults ()
throws Exception
{
super.configureDefaults();
} }
public void configureWebApp () public void configure (WebAppContext context)
throws Exception throws Exception
{ {
super.configureWebApp(); bindUserTransaction(context);
bindUserTransaction();
WebXmlProcessor webXmlProcessor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.__web_processor);
if (webXmlProcessor == null)
throw new IllegalStateException ("No processor for web xml");
//parse classes for annotations, if necessary
if (!webXmlProcessor.isMetaDataComplete())
{
if (Log.isDebugEnabled()) Log.debug("Processing annotations");
parseAnnotations(context);
}
//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());
//TODO: can web-fragment contain resource-ref and injection-targets?
for (XmlParser.Node frag: webXmlProcessor.getFragments())
plusProcessor.process(frag);
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(_injections);
((ServletHandler)context.getServletHandler()).setCallbacks(_callbacks);
//do any injects on the listeners that were created and then
//also callback any postConstruct lifecycle methods
injectAndCallPostConstructCallbacks(context);
} }
public void deconfigureWebApp() public void deconfigure (WebAppContext context)
throws Exception throws Exception
{ {
//call any preDestroy methods on the listeners //call any preDestroy methods on the listeners
callPreDestroyCallbacks(); callPreDestroyCallbacks(context);
super.deconfigureWebApp();
} }
public void configure(String webXml)
throws Exception
{
//parse web.xml
super.configure(webXml);
//parse classes for annotations, if necessary
if (!_metaDataComplete)
{
if (Log.isDebugEnabled()) Log.debug("Processing annotations");
parseAnnotations();
}
//do any injects on the listeners that were created and then
//also callback any postConstruct lifecycle methods
injectAndCallPostConstructCallbacks();
}
protected void initialize(XmlParser.Node config) protected void injectAndCallPostConstructCallbacks(WebAppContext context)
throws ClassNotFoundException,UnavailableException
{
super.initialize(config);
//configure injections and callbacks to be called by the FilterHolder and ServletHolder
//when they lazily instantiate the Filter/Servlet.
((ServletHandler)getWebAppContext().getServletHandler()).setInjections(_injections);
((ServletHandler)getWebAppContext().getServletHandler()).setCallbacks(_callbacks);
}
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);
}
else
{
super.initWebXmlElement(element, 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(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 = getWebAppContext().loadClass(type);
initInjection (node, jndiName, typeClass);
bindResourceRef(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 = getWebAppContext().loadClass(type);
initInjection (node, jndiName, typeClass);
bindResourceEnvRef(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 = getWebAppContext().loadClass(type);
initInjection(node, jndiName, typeClass);
bindMessageDestinationRef(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;
}
try
{
Class clazz = getWebAppContext().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;
}
try
{
Class clazz = getWebAppContext().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
* @return the type of the injectable
*/
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;
}
// 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 = getWebAppContext().loadClass(targetClassName);
Injection injection = new Injection();
injection.setTargetClass(clazz);
injection.setJndiName(jndiName);
injection.setTarget(clazz, targetName, valueClass);
_injections.add(injection);
}
catch (ClassNotFoundException e)
{
Log.warn("Couldn't load injection target class "+targetClassName);
}
}
}
/**
* Parse all classes that are mentioned in web.xml (servlets, filters, listeners)
* for annotations.
*
*
*
* @throws Exception
*/
protected abstract void parseAnnotations () throws Exception;
protected void injectAndCallPostConstructCallbacks()
throws Exception throws Exception
{ {
//look thru the servlets to apply any runAs annotations //look thru the servlets to apply any runAs annotations
//NOTE: that any run-as in web.xml will already have been applied //NOTE: that any run-as in web.xml will already have been applied
ServletHolder[] holders = getWebAppContext().getServletHandler().getServlets(); ServletHolder[] holders = context.getServletHandler().getServlets();
for (int i=0;holders!=null && i<holders.length;i++) for (int i=0;holders!=null && i<holders.length;i++)
{ {
_runAsCollection.setRunAs(holders[i], _securityHandler); _runAsCollection.setRunAs(holders[i], _securityHandler);
} }
EventListener[] listeners = getWebAppContext().getEventListeners(); EventListener[] listeners = context.getEventListeners();
for (int i=0;listeners!=null && i<listeners.length;i++) for (int i=0;listeners!=null && i<listeners.length;i++)
{ {
_injections.inject(listeners[i]); _injections.inject(listeners[i]);
@ -458,10 +480,10 @@ public abstract class AbstractConfiguration extends WebXmlConfiguration
} }
protected void callPreDestroyCallbacks () protected void callPreDestroyCallbacks (WebAppContext context)
throws Exception throws Exception
{ {
EventListener[] listeners = getWebAppContext().getEventListeners(); EventListener[] listeners = context.getEventListeners();
for (int i=0; listeners!=null && i<listeners.length;i++) for (int i=0; listeners!=null && i<listeners.length;i++)
{ {
_callbacks.callPreDestroyCallback(listeners[i]); _callbacks.callPreDestroyCallback(listeners[i]);

View File

@ -26,6 +26,7 @@ import org.eclipse.jetty.plus.jndi.NamingEntry;
import org.eclipse.jetty.plus.jndi.NamingEntryUtil; import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
import org.eclipse.jetty.plus.jndi.Transaction; import org.eclipse.jetty.plus.jndi.Transaction;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.webapp.WebAppContext;
/** /**
@ -50,7 +51,7 @@ public class Configuration extends AbstractConfiguration
* @param value * @param value
* @throws Exception * @throws Exception
*/ */
public void bindEnvEntry(String name, Object value) throws Exception public void bindEnvEntry(WebAppContext context, String name, Object value) throws Exception
{ {
InitialContext ic = null; InitialContext ic = null;
boolean bound = false; boolean bound = false;
@ -90,10 +91,10 @@ public class Configuration extends AbstractConfiguration
* @param name * @param name
* @throws Exception * @throws Exception
*/ */
public void bindResourceRef(String name, Class typeClass) public void bindResourceRef(WebAppContext context, String name, Class typeClass)
throws Exception throws Exception
{ {
bindEntry(name, typeClass); bindEntry(context, name, typeClass);
} }
/** /**
@ -101,20 +102,20 @@ public class Configuration extends AbstractConfiguration
* @param name * @param name
* @throws Exception * @throws Exception
*/ */
public void bindResourceEnvRef(String name, Class typeClass) public void bindResourceEnvRef(WebAppContext context, String name, Class typeClass)
throws Exception throws Exception
{ {
bindEntry(name, typeClass); bindEntry(context, name, typeClass);
} }
public void bindMessageDestinationRef(String name, Class typeClass) public void bindMessageDestinationRef(WebAppContext context, String name, Class typeClass)
throws Exception throws Exception
{ {
bindEntry(name, typeClass); bindEntry(context, name, typeClass);
} }
public void bindUserTransaction () public void bindUserTransaction (WebAppContext context)
throws Exception throws Exception
{ {
try try
@ -127,38 +128,38 @@ public class Configuration extends AbstractConfiguration
} }
} }
public void configureClassLoader () public void preConfigure (WebAppContext context)
throws Exception throws Exception
{ {
super.configureClassLoader(); super.preConfigure(context);
} }
public void configure (WebAppContext context)
throws Exception
{
super.configure (context);
}
public void configureDefaults () public void postConfigure (WebAppContext context)
throws Exception throws Exception
{ {
super.configureDefaults(); //lock this webapp's java:comp namespace as per J2EE spec
}
public void configureWebApp ()
throws Exception
{
super.configureWebApp();
//lock this webapp's java:comp namespace as per J2EE spec
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(getWebAppContext().getClassLoader()); Thread.currentThread().setContextClassLoader(context.getClassLoader());
lockCompEnv(); lockCompEnv();
Thread.currentThread().setContextClassLoader(oldLoader); Thread.currentThread().setContextClassLoader(oldLoader);
} }
public void deconfigureWebApp() throws Exception public void deconfigure (WebAppContext context) throws Exception
{ {
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(getWebAppContext().getClassLoader()); Thread.currentThread().setContextClassLoader(context.getClassLoader());
unlockCompEnv(); unlockCompEnv();
_key = null;
Thread.currentThread().setContextClassLoader(oldLoader); Thread.currentThread().setContextClassLoader(oldLoader);
super.deconfigureWebApp(); super.deconfigure (context);
} }
protected void lockCompEnv () protected void lockCompEnv ()
@ -185,7 +186,7 @@ public class Configuration extends AbstractConfiguration
/** /**
* @see org.eclipse.jetty.plus.webapp.AbstractConfiguration#parseAnnotations() * @see org.eclipse.jetty.plus.webapp.AbstractConfiguration#parseAnnotations()
*/ */
public void parseAnnotations() throws Exception public void parseAnnotations(WebAppContext context) throws Exception
{ {
//see org.eclipse.jetty.annotations.Configuration instead //see org.eclipse.jetty.annotations.Configuration instead
} }
@ -205,7 +206,7 @@ public class Configuration extends AbstractConfiguration
* @param typeClass * @param typeClass
* @throws Exception * @throws Exception
*/ */
private void bindEntry (String name, Class typeClass) private void bindEntry (WebAppContext context, String name, Class typeClass)
throws Exception throws Exception
{ {
String nameInEnvironment = name; String nameInEnvironment = name;
@ -213,7 +214,7 @@ public class Configuration extends AbstractConfiguration
//check if the name in web.xml has been mapped to something else //check if the name in web.xml has been mapped to something else
//check a context-specific naming environment first //check a context-specific naming environment first
Object scope = getWebAppContext(); Object scope = context;
NamingEntry ne = NamingEntryUtil.lookupNamingEntry(scope, name); NamingEntry ne = NamingEntryUtil.lookupNamingEntry(scope, name);
if (ne!=null && (ne instanceof Link)) if (ne!=null && (ne instanceof Link))
@ -221,33 +222,38 @@ public class Configuration extends AbstractConfiguration
//if we found a mapping, get out name it is mapped to in the environment //if we found a mapping, get out name it is mapped to in the environment
nameInEnvironment = (String)((Link)ne).getObjectToBind(); nameInEnvironment = (String)((Link)ne).getObjectToBind();
Link l = (Link)ne; Link l = (Link)ne;
System.err.println("Link, with nameInEnvironment="+nameInEnvironment);
} }
//try finding that mapped name in the webapp's environment first //try finding that mapped name in the webapp's environment first
scope = getWebAppContext(); System.err.println("Trying to find "+nameInEnvironment+" in webapp scope");
scope = context;
bound = NamingEntryUtil.bindToENC(scope, name, nameInEnvironment); bound = NamingEntryUtil.bindToENC(scope, name, nameInEnvironment);
if (bound) if (bound)
return; return;
System.err.println("Trying to find "+nameInEnvironment+" in server scope");
//try the server's environment //try the server's environment
scope = getWebAppContext().getServer(); scope = context.getServer();
bound = NamingEntryUtil.bindToENC(scope, name, nameInEnvironment); bound = NamingEntryUtil.bindToENC(scope, name, nameInEnvironment);
if (bound) if (bound)
return; return;
System.err.println("Trying to find "+nameInEnvironment+" in jvm scope");
//try the jvm environment //try the jvm environment
bound = NamingEntryUtil.bindToENC(null, name, nameInEnvironment); bound = NamingEntryUtil.bindToENC(null, name, nameInEnvironment);
if (bound) if (bound)
return; return;
System.err.println("Didn't find "+nameInEnvironment+" anywhere - looking for "+typeClass.getName()+"/default in server or jvm scope");
//There is no matching resource so try a default name. //There is no matching resource so try a default name.
//The default name syntax is: the [res-type]/default //The default name syntax is: the [res-type]/default
//eg javax.sql.DataSource/default //eg javax.sql.DataSource/default
nameInEnvironment = typeClass.getName()+"/default"; nameInEnvironment = typeClass.getName()+"/default";
//First try the server scope //First try the server scope
NamingEntry defaultNE = NamingEntryUtil.lookupNamingEntry(getWebAppContext().getServer(), nameInEnvironment); NamingEntry defaultNE = NamingEntryUtil.lookupNamingEntry(context.getServer(), nameInEnvironment);
if (defaultNE==null) if (defaultNE==null)
defaultNE = NamingEntryUtil.lookupNamingEntry(null, nameInEnvironment); defaultNE = NamingEntryUtil.lookupNamingEntry(null, nameInEnvironment);

View File

@ -40,67 +40,37 @@ import org.eclipse.jetty.xml.XmlConfiguration;
*/ */
public class EnvConfiguration implements Configuration public class EnvConfiguration implements Configuration
{ {
private WebAppContext webAppContext;
private Context compCtx; private Context compCtx;
private Context envCtx; private Context envCtx;
private URL jettyEnvXmlUrl; private URL jettyEnvXmlUrl;
protected void createEnvContext ()
throws NamingException
{
Context context = new InitialContext();
compCtx = (Context)context.lookup ("java:comp");
envCtx = compCtx.createSubcontext("env");
if (Log.isDebugEnabled())
Log.debug("Created java:comp/env for webapp "+getWebAppContext().getContextPath());
}
/**
* @see org.eclipse.jetty.webapp.Configuration#setWebAppContext(org.eclipse.jetty.webapp.WebAppContext)
* @param context
*/
public void setWebAppContext(WebAppContext context)
{
this.webAppContext = context;
}
public void setJettyEnvXml (URL url) public void setJettyEnvXml (URL url)
{ {
this.jettyEnvXmlUrl = url; this.jettyEnvXmlUrl = url;
} }
/**
* @see org.eclipse.jetty.webapp.Configuration#getWebAppContext()
*/
public WebAppContext getWebAppContext()
{
return webAppContext;
}
/**
* @see org.eclipse.jetty.webapp.Configuration#configureClassLoader()
* @throws Exception
*/
public void configureClassLoader() throws Exception
{
}
/** /**
* @see org.eclipse.jetty.webapp.Configuration#configureDefaults() * @see org.eclipse.jetty.webapp.Configuration#configureDefaults()
* @throws Exception * @throws Exception
*/ */
public void configureDefaults() throws Exception public void preConfigure (WebAppContext context) throws Exception
{ {
//create a java:comp/env //create a java:comp/env
createEnvContext(); createEnvContext();
if (Log.isDebugEnabled())
Log.debug("Created java:comp/env for webapp "+context.getContextPath());
} }
/** /**
* @see org.eclipse.jetty.webapp.Configuration#configureWebApp()
* @throws Exception * @throws Exception
*/ */
public void configureWebApp() throws Exception public void configure (WebAppContext context) throws Exception
{ {
//check to see if an explicit file has been set, if not, //check to see if an explicit file has been set, if not,
//look in WEB-INF/jetty-env.xml //look in WEB-INF/jetty-env.xml
@ -109,7 +79,7 @@ public class EnvConfiguration implements Configuration
//look for a file called WEB-INF/jetty-env.xml //look for a file called WEB-INF/jetty-env.xml
//and process it if it exists //and process it if it exists
org.eclipse.jetty.util.resource.Resource web_inf = getWebAppContext().getWebInf(); org.eclipse.jetty.util.resource.Resource web_inf = context.getWebInf();
if(web_inf!=null && web_inf.isDirectory()) if(web_inf!=null && web_inf.isDirectory())
{ {
org.eclipse.jetty.util.resource.Resource jettyEnv = web_inf.addPath("jetty-env.xml"); org.eclipse.jetty.util.resource.Resource jettyEnv = web_inf.addPath("jetty-env.xml");
@ -119,38 +89,48 @@ public class EnvConfiguration implements Configuration
} }
} }
} }
//apply the jetty-env.xml file
if (jettyEnvXmlUrl != null) if (jettyEnvXmlUrl != null)
{ {
System.err.println("Applying "+jettyEnvXmlUrl);
XmlConfiguration configuration = new XmlConfiguration(jettyEnvXmlUrl); XmlConfiguration configuration = new XmlConfiguration(jettyEnvXmlUrl);
configuration.configure(getWebAppContext()); configuration.configure(context);
} }
//add java:comp/env entries for any EnvEntries that have been defined so far //add java:comp/env entries for any EnvEntries that have been defined so far
bindEnvEntries(); bindEnvEntries(context);
} }
public void postConfigure(WebAppContext context) throws Exception
{
// TODO Auto-generated method stub
}
/** /**
* Remove all jndi setup * Remove all jndi setup
* @see org.eclipse.jetty.webapp.Configuration#deconfigureWebApp() * @see org.eclipse.jetty.webapp.Configuration#deconfigureWebApp()
* @throws Exception * @throws Exception
*/ */
public void deconfigureWebApp() throws Exception public void deconfigure (WebAppContext context) throws Exception
{ {
//get rid of any bindings for comp/env for webapp //get rid of any bindings for comp/env for webapp
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(webAppContext.getClassLoader()); Thread.currentThread().setContextClassLoader(context.getClassLoader());
compCtx.destroySubcontext("env"); compCtx.destroySubcontext("env");
//unbind any NamingEntries that were configured in this webapp's name space //unbind any NamingEntries that were configured in this webapp's name space
try try
{ {
Context scopeContext = NamingEntryUtil.getContextForScope(getWebAppContext()); Context scopeContext = NamingEntryUtil.getContextForScope(context);
scopeContext.destroySubcontext(NamingEntry.__contextName); scopeContext.destroySubcontext(NamingEntry.__contextName);
} }
catch (NameNotFoundException e) catch (NameNotFoundException e)
{ {
Log.ignore(e); Log.ignore(e);
Log.debug("No naming entries configured in environment for webapp "+getWebAppContext()); Log.debug("No naming entries configured in environment for webapp "+context);
} }
Thread.currentThread().setContextClassLoader(oldLoader); Thread.currentThread().setContextClassLoader(oldLoader);
} }
@ -162,7 +142,7 @@ public class EnvConfiguration implements Configuration
* We first bind EnvEntries declared in Server scope, then WebAppContext scope. * We first bind EnvEntries declared in Server scope, then WebAppContext scope.
* @throws NamingException * @throws NamingException
*/ */
public void bindEnvEntries () public void bindEnvEntries (WebAppContext context)
throws NamingException throws NamingException
{ {
Log.debug("Binding env entries from the jvm scope"); Log.debug("Binding env entries from the jvm scope");
@ -179,7 +159,7 @@ public class EnvConfiguration implements Configuration
Log.debug("Binding env entries from the server scope"); Log.debug("Binding env entries from the server scope");
scope = getWebAppContext().getServer(); scope = context.getServer();
list = NamingEntryUtil.lookupNamingEntries(scope, EnvEntry.class); list = NamingEntryUtil.lookupNamingEntries(scope, EnvEntry.class);
itor = list.iterator(); itor = list.iterator();
while (itor.hasNext()) while (itor.hasNext())
@ -191,7 +171,7 @@ public class EnvConfiguration implements Configuration
} }
Log.debug("Binding env entries from the context scope"); Log.debug("Binding env entries from the context scope");
scope = getWebAppContext(); scope = context;
list = NamingEntryUtil.lookupNamingEntries(scope, EnvEntry.class); list = NamingEntryUtil.lookupNamingEntries(scope, EnvEntry.class);
itor = list.iterator(); itor = list.iterator();
while (itor.hasNext()) while (itor.hasNext())
@ -202,4 +182,12 @@ public class EnvConfiguration implements Configuration
NamingUtil.bind(envCtx, namingEntryName.toString(), ee);//also save the EnvEntry in the context so we can check it later NamingUtil.bind(envCtx, namingEntryName.toString(), ee);//also save the EnvEntry in the context so we can check it later
} }
} }
protected void createEnvContext ()
throws NamingException
{
Context context = new InitialContext();
compCtx = (Context)context.lookup ("java:comp");
envCtx = compCtx.createSubcontext("env");
}
} }

View File

@ -67,11 +67,11 @@ public class TestConfiguration extends TestCase
assertNotNull(NamingEntryUtil.lookupNamingEntry(wac, "zzz/e")); assertNotNull(NamingEntryUtil.lookupNamingEntry(wac, "zzz/e"));
Configuration config = new Configuration(); Configuration config = new Configuration();
config.setWebAppContext(wac);
EnvConfiguration envConfig = new EnvConfiguration(); EnvConfiguration envConfig = new EnvConfiguration();
envConfig.setWebAppContext(wac);
envConfig.configureDefaults(); envConfig.preConfigure(wac);
envConfig.bindEnvEntries(); envConfig.bindEnvEntries(wac);
String val = (String)ic.lookup("java:comp/env/xxx/a"); String val = (String)ic.lookup("java:comp/env/xxx/a");
assertEquals("900", val); //webapp naming overrides server assertEquals("900", val); //webapp naming overrides server
@ -95,20 +95,20 @@ public class TestConfiguration extends TestCase
ne = (NamingEntry)ic.lookup("java:comp/env/"+NamingEntry.__contextName+"/zzz/e"); ne = (NamingEntry)ic.lookup("java:comp/env/"+NamingEntry.__contextName+"/zzz/e");
assertNotNull(ne); assertNotNull(ne);
config.bindEnvEntry("foo", "99"); config.bindEnvEntry(wac, "foo", "99");
assertEquals("99",ic.lookup( "java:comp/env/foo")); assertEquals("99",ic.lookup( "java:comp/env/foo"));
config.bindEnvEntry("xxx/a", "7"); config.bindEnvEntry(wac, "xxx/a", "7");
assertEquals("900", ic.lookup("java:comp/env/xxx/a")); //webapp overrides web.xml assertEquals("900", ic.lookup("java:comp/env/xxx/a")); //webapp overrides web.xml
config.bindEnvEntry("yyy/b", "7"); config.bindEnvEntry(wac, "yyy/b", "7");
assertEquals("910", ic.lookup("java:comp/env/yyy/b"));//webapp overrides web.xml assertEquals("910", ic.lookup("java:comp/env/yyy/b"));//webapp overrides web.xml
config.bindEnvEntry("zzz/c", "7"); config.bindEnvEntry(wac,"zzz/c", "7");
assertEquals("7", ic.lookup("java:comp/env/zzz/c"));//webapp does NOT override web.xml assertEquals("7", ic.lookup("java:comp/env/zzz/c"));//webapp does NOT override web.xml
config.bindEnvEntry("zzz/d", "7"); config.bindEnvEntry(wac,"zzz/d", "7");
assertEquals("7", ic.lookup("java:comp/env/zzz/d"));//server does NOT override web.xml assertEquals("7", ic.lookup("java:comp/env/zzz/d"));//server does NOT override web.xml
config.bindEnvEntry("zzz/e", "7"); config.bindEnvEntry(wac,"zzz/e", "7");
assertEquals("7", ic.lookup("java:comp/env/zzz/e"));//webapp does NOT override web.xml assertEquals("7", ic.lookup("java:comp/env/zzz/e"));//webapp does NOT override web.xml
config.bindEnvEntry("zzz/f", "7"); config.bindEnvEntry(wac,"zzz/f", "7");
assertEquals("500", ic.lookup("java:comp/env/zzz/f"));//server overrides web.xml assertEquals("500", ic.lookup("java:comp/env/zzz/f"));//server overrides web.xml
((Context)ic.lookup("java:comp")).destroySubcontext("env"); ((Context)ic.lookup("java:comp")).destroySubcontext("env");

View File

@ -17,61 +17,39 @@ package org.eclipse.jetty.webapp;
/* ------------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------------- */
/** Base Class for WebApplicationContext Configuration. /** Base Class for WebApplicationContext Configuration.
* This class can be extended to customize or extend the configuration * This class can be extended to customize or extend the configuration
* of the WebApplicationContext. If WebApplicationContext.setConfiguration is not * of the WebApplicationContext.
* called, then an XMLConfiguration instance is created.
*
*
*/ */
public interface Configuration public interface Configuration
{ {
/* ------------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------------- */
/** Set up a context on which to perform the configuration. /** Set up for configuration.
* @param context
*/
public void setWebAppContext (WebAppContext context);
/* ------------------------------------------------------------------------------- */
/** Get the context on which the configuration is performed.
*/
public WebAppContext getWebAppContext();
/* ------------------------------------------------------------------------------- */
/** Configure ClassPath.
* This method is called to configure the context ClassLoader. It is called just
* after a new WebAppClassLoader is constructed and before it has been used.
* Class paths may be added, options changed or the loader totally replaced.
* @throws Exception * @throws Exception
*/ */
public void configureClassLoader() public void preConfigure (WebAppContext context) throws Exception;
throws Exception;
/* ------------------------------------------------------------------------------- */
/** Configure Defaults.
* This method is called to intialize the context to the containers default configuration.
* Typically this would mean application of the webdefault.xml file.
* @throws Exception
*/
public void configureDefaults()
throws Exception;
/* ------------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------------- */
/** Configure WebApp. /** Configure WebApp.
* This method is called to apply the standard and vendor deployment descriptors. *
* Typically this is web.xml and jetty-web.xml.
* @throws Exception * @throws Exception
*/ */
public void configureWebApp() public void configure (WebAppContext context) throws Exception;
throws Exception;
/* ------------------------------------------------------------------------------- */
/** Clear down after configuration.
* @throws Exception
*/
public void postConfigure (WebAppContext context) throws Exception;
/* ------------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------------- */
/** DeConfigure WebApp. /** DeConfigure WebApp.
* This method is called to undo all configuration done to this webapphandler. This is * This method is called to undo all configuration done. This is
* called to allow the context to work correctly over a stop/start cycle * called to allow the context to work correctly over a stop/start cycle
* @throws Exception * @throws Exception
*/ */
public void deconfigureWebApp() public void deconfigure (WebAppContext context) throws Exception;
throws Exception;
} }

View File

@ -0,0 +1,125 @@
// ========================================================================
// 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.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.regex.Pattern;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.resource.Resource;
/**
* FragmentConfiguration
*
* Process web-fragments in jars
*/
public class FragmentConfiguration implements Configuration
{
public void preConfigure(WebAppContext context) throws Exception
{
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
{
//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();
}
public void deconfigure(WebAppContext context) throws Exception
{
// TODO Auto-generated method stub
}
public void postConfigure(WebAppContext context) throws Exception
{
// TODO Auto-generated method stub
}
/* ------------------------------------------------------------------------------- */
/**
* Look for any web.xml fragments in META-INF of jars in WEB-INF/lib
*
* @throws Exception
*/
public void parseWebFragments (final WebAppContext context, final WebXmlProcessor processor) throws Exception
{
// Check to see if a specific search pattern has been set.
String tmp = (String) context.getInitParameter("org.eclipse.jetty.webapp.WebXmlFragmentPattern");
Pattern webFragPattern = (tmp == null ? null : Pattern.compile(tmp));
List<URL> urls = (List<URL>)context.getAttribute(MetaInfConfiguration.__webFragJars);
JarScanner fragScanner = new JarScanner()
{
public void processEntry(URL jarUrl, JarEntry entry)
{
try
{
String name = entry.getName();
if (name.toLowerCase().equals("meta-inf/web-fragment.xml"))
{
Resource webXmlFrag = context.newResource("jar:" + jarUrl + "!/" + name);
Log.debug("web.xml fragment found {}", webXmlFrag);
// Process web.xml
// web-fragment
// servlet
// servlet-mapping
// filter
// filter-mapping
// listener
processor.parseFragment(webXmlFrag.getURL());
}
}
catch (Exception e)
{
Log.warn("Problem processing jar entry " + entry, e);
}
}
};
//process only the jars that have web fragments in them, according to the pattern provided
if (urls != null)
fragScanner.scan(webFragPattern, urls.toArray(new URL[urls.size()]), true);
else
{
if (Log.isDebugEnabled()) Log.debug("No jars with web-fragments");
}
}
}

View File

@ -43,6 +43,60 @@ public abstract class JarScanner
public abstract void processEntry (URL jarUrl, JarEntry entry); public abstract void processEntry (URL jarUrl, JarEntry entry);
/**
* Find jar names from the provided list matching a pattern.
*
* If the pattern is null and isNullInclusive is true, then
* all jar names will match.
*
* A pattern is a set of acceptable jar names. Each acceptable
* jar name is a regex. Each regex can be separated by either a
* "," or a "|". If you use a "|" this or's together the jar
* name patterns. This means that ordering of the matches is
* unimportant to you. If instead, you want to match particular
* jar names, and you want to match them in order, you should
* separate the regexs with "," instead.
*
* Eg "aaa-.*\\.jar|bbb-.*\\.jar"
* Will iterate over the jar names and match
* in any order.
*
* Eg "aaa-*\\.jar,bbb-.*\\.jar"
* Will iterate over the jar names, matching
* all those starting with "aaa-" first, then "bbb-".
*
* @param pattern
* @param loader
* @param isNullInclusive if true, an empty pattern means all names match, if false, none match
* @throws Exception
*/
public void scan (Pattern pattern, URL[] urls, boolean isNullInclusive)
throws Exception
{
if (urls!=null)
{
String[] patterns = (pattern==null?null:pattern.pattern().split(","));
List<Pattern> subPatterns = new ArrayList<Pattern>();
for (int i=0; patterns!=null && i<patterns.length;i++)
subPatterns.add(Pattern.compile(patterns[i]));
if (subPatterns.isEmpty())
subPatterns.add(pattern);
if (subPatterns.isEmpty())
{
processJars(null, urls, isNullInclusive);
}
else
{
//for each subpattern, iterate over all the urls, processing those that match
for (Pattern p : subPatterns)
{
processJars(p, urls, isNullInclusive);
}
}
}
}
/** /**
* Find jar names from the classloader matching a pattern. * Find jar names from the classloader matching a pattern.

View File

@ -29,46 +29,22 @@ import org.eclipse.jetty.xml.XmlConfiguration;
*/ */
public class JettyWebXmlConfiguration implements Configuration public class JettyWebXmlConfiguration implements Configuration
{ {
private WebAppContext _context; public void preConfigure(WebAppContext context) throws Exception
{
// TODO Auto-generated method stub
}
/** /**
* @see Configuration#setWebAppContext * Configure
*/
public void setWebAppContext (WebAppContext context)
{
_context = context;
}
public WebAppContext getWebAppContext ()
{
return _context;
}
/** configureClassPath
* Not used.
* @see Configuration#configureClassLoader
*/
public void configureClassLoader () throws Exception
{
}
/** configureDefaults
* Not used.
* @see Configuration#configureDefaults
*/
public void configureDefaults () throws Exception
{
}
/** configureWebApp
* Apply web-jetty.xml configuration * Apply web-jetty.xml configuration
* @see Configuration#configureWebApp() * @see Configuration#configure(WebAppContext)
*/ */
public void configureWebApp () throws Exception public void configure (WebAppContext context) throws Exception
{ {
//cannot configure if the _context is already started //cannot configure if the _context is already started
if (_context.isStarted()) if (context.isStarted())
{ {
if (Log.isDebugEnabled()){Log.debug("Cannot configure webapp after it is started");} if (Log.isDebugEnabled()){Log.debug("Cannot configure webapp after it is started");}
return; return;
@ -77,7 +53,7 @@ public class JettyWebXmlConfiguration implements Configuration
if(Log.isDebugEnabled()) if(Log.isDebugEnabled())
Log.debug("Configuring web-jetty.xml"); Log.debug("Configuring web-jetty.xml");
Resource web_inf=getWebAppContext().getWebInf(); Resource web_inf = context.getWebInf();
// handle any WEB-INF descriptors // handle any WEB-INF descriptors
if(web_inf!=null&&web_inf.isDirectory()) if(web_inf!=null&&web_inf.isDirectory())
{ {
@ -91,31 +67,35 @@ public class JettyWebXmlConfiguration implements Configuration
if(jetty.exists()) if(jetty.exists())
{ {
// No server classes while configuring // No server classes while configuring
String[] old_server_classes = _context.getServerClasses(); String[] old_server_classes = context.getServerClasses();
try try
{ {
_context.setServerClasses(null); context.setServerClasses(null);
if(Log.isDebugEnabled()) if(Log.isDebugEnabled())
Log.debug("Configure: "+jetty); Log.debug("Configure: "+jetty);
XmlConfiguration jetty_config=new XmlConfiguration(jetty.getURL()); XmlConfiguration jetty_config=new XmlConfiguration(jetty.getURL());
jetty_config.configure(getWebAppContext()); jetty_config.configure(context);
} }
finally finally
{ {
if (_context.getServerClasses()==null) if (context.getServerClasses()==null)
_context.setServerClasses(old_server_classes); context.setServerClasses(old_server_classes);
} }
} }
} }
} }
/** deconfigureWebApp public void postConfigure(WebAppContext context) throws Exception
* @see Configuration#deconfigureWebApp()
*/
public void deconfigureWebApp () throws Exception
{ {
// TODO Auto-generated method stub
} }
public void deconfigure(WebAppContext context) throws Exception
{
// TODO Auto-generated method stub
}
} }

View File

@ -0,0 +1,140 @@
// ========================================================================
// 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.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.resource.Resource;
/**
* MetaInfConfiguration
*
* Scan META-INF of all jars in WEB-INF/lib to find:
* <ul>
* <li>tlds
* <li>web-fragment.xml
* <li>resources
* </ul>
*/
public class MetaInfConfiguration implements Configuration
{
public static final String __tldJars = "org.eclipse.jetty.tlds";
public static final String __webFragJars = "org.eclipse.jetty.webFragments";
public static final String __metaResourceJars = "org.eclipse.jetty.metaResources";
public void preConfigure(final WebAppContext context) throws Exception
{
//Find all jars in WEB-INF
Resource web_inf = context.getWebInf();
Resource web_inf_lib = web_inf.addPath("/lib");
List<URL> urls = new ArrayList<URL>();
if (web_inf_lib.exists() && web_inf_lib.isDirectory())
{
String[] files=web_inf_lib.list();
for (int f=0;files!=null && f<files.length;f++)
{
try
{
Resource file = web_inf_lib.addPath(files[f]);
String fnlc = file.getName().toLowerCase();
int dot = fnlc.lastIndexOf('.');
String extension = (dot < 0 ? null : fnlc.substring(dot));
if (extension != null && (extension.equals(".jar") || extension.equals(".zip")))
{
urls.add(file.getURL());
}
}
catch (Exception ex)
{
Log.warn(Log.EXCEPTION,ex);
}
}
}
final List<URL> tldJars = new ArrayList<URL>();
final List<URL> webFragJars = new ArrayList<URL>();
final List<URL> metaResourceJars = new ArrayList<URL>();
JarScanner fragScanner = new JarScanner()
{
public void processEntry(URL jarUrl, JarEntry entry)
{
try
{
String name = entry.getName().toLowerCase();
if (name.startsWith("meta-inf"))
{
if (name.equals("meta-inf/web-fragment.xml"))
{
addJar(jarUrl, webFragJars);
}
else if (name.endsWith(".tld"))
{
addJar(jarUrl, tldJars);
}
else if (name.equals("meta-inf/resources"))
{
addJar(jarUrl, metaResourceJars);
}
}
}
catch (Exception e)
{
Log.warn("Problem processing jar entry " + entry, e);
}
}
};
fragScanner.scan(null, urls.toArray(new URL[urls.size()]), true);
context.setAttribute(__tldJars, tldJars);
context.setAttribute(__webFragJars, webFragJars);
context.setAttribute(__metaResourceJars, metaResourceJars);
}
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 addJar (URL jarUrl, List<URL> list)
{
if (!list.contains(jarUrl))
list.add(jarUrl);
}
}

View File

@ -14,9 +14,11 @@
package org.eclipse.jetty.webapp; package org.eclipse.jetty.webapp;
import java.net.URL; import java.net.URL;
import java.util.ArrayList;
import java.util.EventListener; import java.util.EventListener;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -50,14 +52,24 @@ public class TagLibConfiguration implements Configuration
{ {
public static final String __web_inf_pattern = "org.eclipse.jetty.webapp.WebInfIncludeTLDJarPattern"; public static final String __web_inf_pattern = "org.eclipse.jetty.webapp.WebInfIncludeTLDJarPattern";
public static final String __container_pattern = "org.eclipse.jetty.server.webapp.ContainerIncludeTLDJarPattern"; public static final String __container_pattern = "org.eclipse.jetty.server.webapp.ContainerIncludeTLDJarPattern";
WebAppContext _context;
public class TagLibJarScanner extends JarScanner /**
* TagLibJarScanner
*
* Scan jars for META-INF/*.tlds
*/
public class TagLibJarScanner extends JarScanner
{ {
Set _tlds; Set _tlds;
WebAppContext _context;
public TagLibJarScanner (WebAppContext context)
{
_context = context;
}
public void setTldSet (Set tlds) public void setTldSet (Set tlds)
{ {
@ -88,52 +100,164 @@ public class TagLibConfiguration implements Configuration
} }
} }
/* ------------------------------------------------------------ */
public void setWebAppContext(WebAppContext context)
{
_context=context;
}
/* ------------------------------------------------------------ */
public WebAppContext getWebAppContext()
{
return _context;
}
/* ------------------------------------------------------------ */
public void configureClassLoader() throws Exception
{
}
/* ------------------------------------------------------------ */
/*
* @see org.eclipse.jetty.servlet.WebAppContext.Configuration#configureDefaults()
*/
public void configureDefaults() throws Exception
{
}
/* ------------------------------------------------------------ */ public class TldProcessor
/* {
* @see org.eclipse.jetty.servlet.WebAppContext.Configuration#configureWebApp() public static final String __taglib_processor = "org.eclipse.jetty.tagLibProcessor";
*/ XmlParser _parser;
public void configureWebApp() throws Exception WebAppContext _context;
{ List<XmlParser.Node> _roots = new ArrayList<XmlParser.Node>();
Set tlds = new HashSet();
// Find tld's from web.xml public TldProcessor (WebAppContext context)
// When the XMLConfigurator (or other configurator) parsed the web.xml, throws Exception
// It should have created aliases for all TLDs. So search resources aliases
// for aliases ending in tld
if (_context.getResourceAliases()!=null &&
_context.getBaseResource()!=null &&
_context.getBaseResource().exists())
{ {
Iterator iter=_context.getResourceAliases().values().iterator(); _context = context;
createParser();
}
private void createParser ()
throws Exception
{
// Create a TLD parser
_parser = new XmlParser(false);
URL taglib11=null;
URL taglib12=null;
URL taglib20=null;
URL taglib21=null;
try
{
Class jsp_page = Loader.loadClass(WebXmlConfiguration.class,"javax.servlet.jsp.JspPage");
taglib11=jsp_page.getResource("javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd");
taglib12=jsp_page.getResource("javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd");
taglib20=jsp_page.getResource("javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd");
taglib21=jsp_page.getResource("javax/servlet/jsp/resources/web-jsptaglibrary_2_1.xsd");
}
catch(Exception e)
{
Log.ignore(e);
}
finally
{
if(taglib11==null)
taglib11=Loader.getResource(Servlet.class,"javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd",true);
if(taglib12==null)
taglib12=Loader.getResource(Servlet.class,"javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd",true);
if(taglib20==null)
taglib20=Loader.getResource(Servlet.class,"javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd",true);
if(taglib21==null)
taglib21=Loader.getResource(Servlet.class,"javax/servlet/jsp/resources/web-jsptaglibrary_2_1.xsd",true);
}
if(taglib11!=null)
{
_parser.redirectEntity("web-jsptaglib_1_1.dtd",taglib11);
_parser.redirectEntity("web-jsptaglibrary_1_1.dtd",taglib11);
}
if(taglib12!=null)
{
_parser.redirectEntity("web-jsptaglib_1_2.dtd",taglib12);
_parser.redirectEntity("web-jsptaglibrary_1_2.dtd",taglib12);
}
if(taglib20!=null)
{
_parser.redirectEntity("web-jsptaglib_2_0.xsd",taglib20);
_parser.redirectEntity("web-jsptaglibrary_2_0.xsd",taglib20);
}
if(taglib21!=null)
{
_parser.redirectEntity("web-jsptaglib_2_1.xsd",taglib21);
_parser.redirectEntity("web-jsptaglibrary_2_1.xsd",taglib21);
}
_parser.setXpath("/taglib/listener/listener-class");
}
public XmlParser.Node parse (Resource tld)
throws Exception
{
XmlParser.Node root;
try
{
//xerces on apple appears to sometimes close the zip file instead
//of the inputstream, so try opening the input stream, but if
//that doesn't work, fallback to opening a new url
root = _parser.parse(tld.getInputStream());
}
catch (Exception e)
{
root = _parser.parse(tld.getURL().toString());
}
if (root==null)
{
Log.warn("No TLD root in {}",tld);
}
else
_roots.add(root);
return root;
}
public void processRoots ()
{
for (XmlParser.Node root: _roots)
process(root);
}
public void process (XmlParser.Node root)
{
for (int i=0;i<root.size();i++)
{
Object o=root.get(i);
if (o instanceof XmlParser.Node)
{
XmlParser.Node node = (XmlParser.Node)o;
if ("listener".equals(node.getTag()))
{
String className=node.getString("listener-class",false,true);
if (Log.isDebugEnabled()) Log.debug("listener="+className);
try
{
Class listenerClass = _context.loadClass(className);
EventListener l = (EventListener)listenerClass.newInstance();
_context.addEventListener(l);
}
catch(Exception e)
{
Log.warn("Could not instantiate listener "+className+": "+e);
Log.debug(e);
}
catch(Error e)
{
Log.warn("Could not instantiate listener "+className+": "+e);
Log.debug(e);
}
}
}
}
}
}
public void preConfigure(WebAppContext context) throws Exception
{
Set tlds = new HashSet();
// Find tld's from web.xml
// When web.xml was processed, it should have created aliases for all TLDs. So search resources aliases
// for aliases ending in tld
if (context.getResourceAliases()!=null &&
context.getBaseResource()!=null &&
context.getBaseResource().exists())
{
Iterator iter=context.getResourceAliases().values().iterator();
while(iter.hasNext()) while(iter.hasNext())
{ {
String location = (String)iter.next(); String location = (String)iter.next();
@ -141,14 +265,14 @@ public class TagLibConfiguration implements Configuration
{ {
if (!location.startsWith("/")) if (!location.startsWith("/"))
location="/WEB-INF/"+location; location="/WEB-INF/"+location;
Resource l=_context.getBaseResource().addPath(location); Resource l=context.getBaseResource().addPath(location);
tlds.add(l); tlds.add(l);
} }
} }
} }
// Look for any tlds in WEB-INF directly. // Look for any tlds in WEB-INF directly.
Resource web_inf = _context.getWebInf(); Resource web_inf = context.getWebInf();
if (web_inf!=null) if (web_inf!=null)
{ {
String[] contents = web_inf.list(); String[] contents = web_inf.list();
@ -156,13 +280,14 @@ public class TagLibConfiguration implements Configuration
{ {
if (contents[i]!=null && contents[i].toLowerCase().endsWith(".tld")) if (contents[i]!=null && contents[i].toLowerCase().endsWith(".tld"))
{ {
Resource l=_context.getWebInf().addPath(contents[i]); Resource l=context.getWebInf().addPath(contents[i]);
tlds.add(l); tlds.add(l);
} }
} }
} }
// Look for tlds in any jars // Look for tlds in any jars
//Use an opt-in style: //Use an opt-in style:
// //
@ -181,81 +306,33 @@ public class TagLibConfiguration implements Configuration
// else // else
// examine only files matching pattern // examine only files matching pattern
// //
String tmp = _context.getInitParameter(__web_inf_pattern); String tmp = context.getInitParameter(__web_inf_pattern);
Pattern webInfPattern = (tmp==null?null:Pattern.compile(tmp)); Pattern webInfPattern = (tmp==null?null:Pattern.compile(tmp));
tmp = _context.getInitParameter(__container_pattern); tmp = context.getInitParameter(__container_pattern);
Pattern containerPattern = (tmp==null?null:Pattern.compile(tmp)); Pattern containerPattern = (tmp==null?null:Pattern.compile(tmp));
TagLibJarScanner tldScanner = new TagLibJarScanner(); List<URL> tldJars = (List<URL>)context.getAttribute(MetaInfConfiguration.__tldJars);
TagLibJarScanner tldScanner = new TagLibJarScanner(context);
try try
{ {
tldScanner.setTldSet(tlds); tldScanner.setTldSet(tlds);
tldScanner.scan(webInfPattern, Thread.currentThread().getContextClassLoader(), true, false); //scan the jars we know have META-INF/tld files
if (tldJars != null)
tldScanner.scan(webInfPattern, tldJars.toArray(new URL[tldJars.size()]), true);
//scan the parent loader for tld files
tldScanner.scan(containerPattern, Thread.currentThread().getContextClassLoader().getParent(), false, true); tldScanner.scan(containerPattern, Thread.currentThread().getContextClassLoader().getParent(), false, true);
} }
catch (Exception e) catch (Exception e)
{ {
Log.warn(e); Log.warn(e);
} }
// Create a processor for the tlds and save it
// Create a TLD parser TldProcessor processor = new TldProcessor (context);
XmlParser parser = new XmlParser(false); context.setAttribute(TldProcessor.__taglib_processor, processor);
// Parse the tlds into memory
URL taglib11=null;
URL taglib12=null;
URL taglib20=null;
URL taglib21=null;
try
{
Class jsp_page = Loader.loadClass(WebXmlConfiguration.class,"javax.servlet.jsp.JspPage");
taglib11=jsp_page.getResource("javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd");
taglib12=jsp_page.getResource("javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd");
taglib20=jsp_page.getResource("javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd");
taglib21=jsp_page.getResource("javax/servlet/jsp/resources/web-jsptaglibrary_2_1.xsd");
}
catch(Exception e)
{
Log.ignore(e);
}
finally
{
if(taglib11==null)
taglib11=Loader.getResource(Servlet.class,"javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd",true);
if(taglib12==null)
taglib12=Loader.getResource(Servlet.class,"javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd",true);
if(taglib20==null)
taglib20=Loader.getResource(Servlet.class,"javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd",true);
if(taglib21==null)
taglib21=Loader.getResource(Servlet.class,"javax/servlet/jsp/resources/web-jsptaglibrary_2_1.xsd",true);
}
if(taglib11!=null)
{
parser.redirectEntity("web-jsptaglib_1_1.dtd",taglib11);
parser.redirectEntity("web-jsptaglibrary_1_1.dtd",taglib11);
}
if(taglib12!=null)
{
parser.redirectEntity("web-jsptaglib_1_2.dtd",taglib12);
parser.redirectEntity("web-jsptaglibrary_1_2.dtd",taglib12);
}
if(taglib20!=null)
{
parser.redirectEntity("web-jsptaglib_2_0.xsd",taglib20);
parser.redirectEntity("web-jsptaglibrary_2_0.xsd",taglib20);
}
if(taglib21!=null)
{
parser.redirectEntity("web-jsptaglib_2_1.xsd",taglib21);
parser.redirectEntity("web-jsptaglibrary_2_1.xsd",taglib21);
}
parser.setXpath("/taglib/listener/listener-class");
// Parse all the discovered TLDs
Iterator iter = tlds.iterator(); Iterator iter = tlds.iterator();
while (iter.hasNext()) while (iter.hasNext())
{ {
@ -263,57 +340,7 @@ public class TagLibConfiguration implements Configuration
{ {
Resource tld = (Resource)iter.next(); Resource tld = (Resource)iter.next();
if (Log.isDebugEnabled()) Log.debug("TLD="+tld); if (Log.isDebugEnabled()) Log.debug("TLD="+tld);
processor.parse(tld);
XmlParser.Node root;
try
{
//xerces on apple appears to sometimes close the zip file instead
//of the inputstream, so try opening the input stream, but if
//that doesn't work, fallback to opening a new url
root = parser.parse(tld.getInputStream());
}
catch (Exception e)
{
root = parser.parse(tld.getURL().toString());
}
if (root==null)
{
Log.warn("No TLD root in {}",tld);
continue;
}
for (int i=0;i<root.size();i++)
{
Object o=root.get(i);
if (o instanceof XmlParser.Node)
{
XmlParser.Node node = (XmlParser.Node)o;
if ("listener".equals(node.getTag()))
{
String className=node.getString("listener-class",false,true);
if (Log.isDebugEnabled()) Log.debug("listener="+className);
try
{
Class listenerClass=getWebAppContext().loadClass(className);
EventListener l=(EventListener)listenerClass.newInstance();
_context.addEventListener(l);
}
catch(Exception e)
{
Log.warn("Could not instantiate listener "+className+": "+e);
Log.debug(e);
}
catch(Error e)
{
Log.warn("Could not instantiate listener "+className+": "+e);
Log.debug(e);
}
}
}
}
} }
catch(Exception e) catch(Exception e)
{ {
@ -321,11 +348,31 @@ public class TagLibConfiguration implements Configuration
} }
} }
} }
public void configure (WebAppContext context) throws Exception
{
TldProcessor processor = (TldProcessor)context.getAttribute(TldProcessor.__taglib_processor);
if (processor == null)
{
Log.warn("No TldProcessor configured, skipping tld processing");
return;
}
public void deconfigureWebApp() throws Exception //Create listeners from the parsed tld trees
{ processor.processRoots();
} }
public void postConfigure(WebAppContext context) throws Exception
{
// TODO Auto-generated method stub
}
public void deconfigure(WebAppContext context) throws Exception
{
// TODO Auto-generated method stub
}
} }

View File

@ -73,6 +73,8 @@ public class WebAppContext extends ServletContextHandler
{ {
"org.eclipse.jetty.webapp.WebInfConfiguration", "org.eclipse.jetty.webapp.WebInfConfiguration",
"org.eclipse.jetty.webapp.WebXmlConfiguration", "org.eclipse.jetty.webapp.WebXmlConfiguration",
"org.eclipse.jetty.webapp.MetaInfConfiguration",
"org.eclipse.jetty.webapp.FragmentConfiguration",
"org.eclipse.jetty.webapp.JettyWebXmlConfiguration", "org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.webapp.TagLibConfiguration" "org.eclipse.jetty.webapp.TagLibConfiguration"
} ; } ;
@ -107,7 +109,6 @@ public class WebAppContext extends ServletContextHandler
"org.slf4j." // hide slf4j "org.slf4j." // hide slf4j
}; };
private File _tmpDir; private File _tmpDir;
private boolean _isExistingTmpDir;
private String _war; private String _war;
private String _extraClasspath; private String _extraClasspath;
private Throwable _unavailableException; private Throwable _unavailableException;
@ -296,9 +297,7 @@ public class WebAppContext extends ServletContextHandler
// Setup configurations // Setup configurations
loadConfigurations(); loadConfigurations();
for (int i=0;i<_configurations.length;i++)
_configurations[i].setWebAppContext(this);
// Configure classloader // Configure classloader
_ownClassLoader=false; _ownClassLoader=false;
if (getClassLoader()==null) if (getClassLoader()==null)
@ -319,19 +318,17 @@ public class WebAppContext extends ServletContextHandler
loader=loader.getParent(); loader=loader.getParent();
} }
} }
// Prepare for configuration
for (int i=0;i<_configurations.length;i++) for (int i=0;i<_configurations.length;i++)
_configurations[i].configureClassLoader(); _configurations[i].preConfigure(this);
getTempDirectory();
if (_tmpDir!=null && !_isExistingTmpDir && !isTempWorkDirectory())
{
File sentinel = new File(_tmpDir, ".active");
if(!sentinel.exists())
sentinel.mkdir();
}
super.doStart(); super.doStart();
// Clean up after configuration
for (int i=0;i<_configurations.length;i++)
_configurations[i].postConfigure(this);
if (isLogUrlOnStart()) if (isLogUrlOnStart())
dumpUrl(); dumpUrl();
@ -373,9 +370,9 @@ public class WebAppContext extends ServletContextHandler
try try
{ {
// Configure classloader
for (int i=_configurations.length;i-->0;) for (int i=_configurations.length;i-->0;)
_configurations[i].deconfigureWebApp(); _configurations[i].deconfigure(this);
_configurations=null; _configurations=null;
// restore security handler // restore security handler
@ -384,13 +381,6 @@ public class WebAppContext extends ServletContextHandler
_sessionHandler.setHandler(_securityHandler); _sessionHandler.setHandler(_securityHandler);
_securityHandler.setHandler(_servletHandler); _securityHandler.setHandler(_servletHandler);
} }
// delete temp directory if we had to create it or if it isn't called work
if (_tmpDir!=null && !_isExistingTmpDir && !isTempWorkDirectory()) //_tmpDir!=null && !"work".equals(_tmpDir.getName()))
{
IO.delete(_tmpDir);
_tmpDir=null;
}
} }
finally finally
{ {
@ -540,186 +530,7 @@ public class WebAppContext extends ServletContextHandler
} }
/* ------------------------------------------------------------ */
/**
* Get a temporary directory in which to unpack the war etc etc.
* The algorithm for determining this is to check these alternatives
* in the order shown:
*
* <p>A. Try to use an explicit directory specifically for this webapp:</p>
* <ol>
* <li>
* Iff an explicit directory is set for this webapp, use it. Do NOT set
* delete on exit.
* </li>
* <li>
* Iff javax.servlet.context.tempdir context attribute is set for
* this webapp && exists && writeable, then use it. Do NOT set delete on exit.
* </li>
* </ol>
*
* <p>B. Create a directory based on global settings. The new directory
* will be called "Jetty_"+host+"_"+port+"__"+context+"_"+virtualhost
* Work out where to create this directory:
* <ol>
* <li>
* Iff $(jetty.home)/work exists create the directory there. Do NOT
* set delete on exit. Do NOT delete contents if dir already exists.
* </li>
* <li>
* Iff WEB-INF/work exists create the directory there. Do NOT set
* delete on exit. Do NOT delete contents if dir already exists.
* </li>
* <li>
* Else create dir in $(java.io.tmpdir). Set delete on exit. Delete
* contents if dir already exists.
* </li>
* </ol>
*
* @return
*/
public File getTempDirectory()
{
if (_tmpDir!=null && _tmpDir.isDirectory() && _tmpDir.canWrite())
return _tmpDir;
// Initialize temporary directory
//
// I'm afraid that this is very much black magic.
// but if you can think of better....
Object t = getAttribute(TEMPDIR);
if (t!=null && (t instanceof File))
{
_tmpDir=(File)t;
if (_tmpDir.isDirectory() && _tmpDir.canWrite())
return _tmpDir;
}
if (t!=null && (t instanceof String))
{
try
{
_tmpDir=new File((String)t);
if (_tmpDir.isDirectory() && _tmpDir.canWrite())
{
if(Log.isDebugEnabled())Log.debug("Converted to File "+_tmpDir+" for "+this);
setAttribute(TEMPDIR,_tmpDir);
return _tmpDir;
}
}
catch(Exception e)
{
Log.warn(Log.EXCEPTION,e);
}
}
// No tempdir so look for a work directory to use as tempDir base
File work=null;
try
{
File w=new File(System.getProperty("jetty.home"),"work");
if (w.exists() && w.canWrite() && w.isDirectory())
work=w;
else if (getBaseResource()!=null)
{
Resource web_inf = getWebInf();
if (web_inf !=null && web_inf.exists())
{
w=new File(web_inf.getFile(),"work");
if (w.exists() && w.canWrite() && w.isDirectory())
work=w;
}
}
}
catch(Exception e)
{
Log.ignore(e);
}
// No tempdir set so make one!
try
{
String temp = getCanonicalNameForWebAppTmpDir();
if (work!=null)
_tmpDir=new File(work,temp);
else
{
_tmpDir=new File(System.getProperty("java.io.tmpdir"),temp);
if (_tmpDir.exists())
{
if(Log.isDebugEnabled())Log.debug("Delete existing temp dir "+_tmpDir+" for "+this);
if (!IO.delete(_tmpDir))
{
if(Log.isDebugEnabled())Log.debug("Failed to delete temp dir "+_tmpDir);
}
if (_tmpDir.exists())
{
String old=_tmpDir.toString();
_tmpDir=File.createTempFile(temp+"_","");
if (_tmpDir.exists())
_tmpDir.delete();
Log.warn("Can't reuse "+old+", using "+_tmpDir);
}
}
}
if (!_tmpDir.exists())
_tmpDir.mkdir();
//if not in a dir called "work" then we want to delete it on jvm exit
if (!isTempWorkDirectory())
_tmpDir.deleteOnExit();
if(Log.isDebugEnabled())Log.debug("Created temp dir "+_tmpDir+" for "+this);
}
catch(Exception e)
{
_tmpDir=null;
Log.ignore(e);
}
if (_tmpDir==null)
{
try{
// that didn't work, so try something simpler (ish)
_tmpDir=File.createTempFile("JettyContext","");
if (_tmpDir.exists())
_tmpDir.delete();
_tmpDir.mkdir();
_tmpDir.deleteOnExit();
if(Log.isDebugEnabled())Log.debug("Created temp dir "+_tmpDir+" for "+this);
}
catch(IOException e)
{
Log.warn("tmpdir",e); System.exit(1);
}
}
setAttribute(TEMPDIR,_tmpDir);
return _tmpDir;
}
/**
* Check if the _tmpDir itself is called "work", or if the _tmpDir
* is in a directory called "work".
* @return
*/
public boolean isTempWorkDirectory ()
{
if (_tmpDir == null)
return false;
if (_tmpDir.getName().equalsIgnoreCase("work"))
return true;
File t = _tmpDir.getParentFile();
if (t == null)
return false;
return (t.getName().equalsIgnoreCase("work"));
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
@ -735,7 +546,8 @@ public class WebAppContext extends ServletContextHandler
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
public Resource getWebInf() throws IOException public Resource getWebInf() throws IOException
{ {
resolveWebApp(); if (super.getBaseResource() == null)
return null;
// Iw there a WEB-INF directory? // Iw there a WEB-INF directory?
Resource web_inf= super.getBaseResource().addPath("WEB-INF/"); Resource web_inf= super.getBaseResource().addPath("WEB-INF/");
@ -813,104 +625,8 @@ public class WebAppContext extends ServletContextHandler
return super.toString()+(_war==null?"":(","+_war)); return super.toString()+(_war==null?"":(","+_war));
} }
/* ------------------------------------------------------------ */
/** Resolve Web App directory
* If the BaseResource has not been set, use the war resource to
* derive a webapp resource (expanding WAR if required).
*/
protected void resolveWebApp() throws IOException
{
Resource web_app = super.getBaseResource();
if (web_app == null)
{
if (_war==null || _war.length()==0)
_war=getResourceBase();
// Set dir or WAR
web_app= newResource(_war);
// Accept aliases for WAR files
if (web_app.getAlias() != null)
{
Log.debug(web_app + " anti-aliased to " + web_app.getAlias());
web_app= newResource(web_app.getAlias());
}
if (Log.isDebugEnabled())
Log.debug("Try webapp=" + web_app + ", exists=" + web_app.exists() + ", directory=" + web_app.isDirectory());
// Is the WAR usable directly?
if (web_app.exists() && !web_app.isDirectory() && !web_app.toString().startsWith("jar:"))
{
// No - then lets see if it can be turned into a jar URL.
Resource jarWebApp= newResource("jar:" + web_app + "!/");
if (jarWebApp.exists() && jarWebApp.isDirectory())
{
web_app= jarWebApp;
}
}
// If we should extract or the URL is still not usable
if (web_app.exists() && (
(_copyDir && web_app.getFile()!= null && web_app.getFile().isDirectory())
||
(_extractWAR && web_app.getFile()!= null && !web_app.getFile().isDirectory())
||
(_extractWAR && web_app.getFile() == null)
||
!web_app.isDirectory()
))
{
// Then extract it if necessary.
File extractedWebAppDir= new File(getTempDirectory(), "webapp");
if (web_app.getFile()!=null && web_app.getFile().isDirectory())
{
// Copy directory
Log.info("Copy " + web_app.getFile() + " to " + extractedWebAppDir);
IO.copyDir(web_app.getFile(),extractedWebAppDir);
}
else
{
if (!extractedWebAppDir.exists())
{
//it hasn't been extracted before so extract it
extractedWebAppDir.mkdir();
Log.info("Extract " + _war + " to " + extractedWebAppDir);
JarResource.extract(web_app, extractedWebAppDir, false);
}
else
{
//only extract if the war file is newer
if (web_app.lastModified() > extractedWebAppDir.lastModified())
{
extractedWebAppDir.delete();
extractedWebAppDir.mkdir();
Log.info("Extract " + _war + " to " + extractedWebAppDir);
JarResource.extract(web_app, extractedWebAppDir, false);
}
}
}
web_app= Resource.newResource(extractedWebAppDir.getCanonicalPath());
}
// Now do we have something usable?
if (!web_app.exists() || !web_app.isDirectory())
{
Log.warn("Web application not found " + _war);
throw new java.io.FileNotFoundException(_war);
}
if (Log.isDebugEnabled())
Log.debug("webapp=" + web_app);
// ResourcePath
super.setBaseResource(web_app);
}
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
@ -1112,8 +828,6 @@ public class WebAppContext extends ServletContextHandler
dir.mkdir(); dir.mkdir();
dir.deleteOnExit(); dir.deleteOnExit();
} }
else if (dir != null)
_isExistingTmpDir = true;
if (dir!=null && ( !dir.exists() || !dir.isDirectory() || !dir.canWrite())) if (dir!=null && ( !dir.exists() || !dir.isDirectory() || !dir.canWrite()))
throw new IllegalArgumentException("Bad temp directory: "+dir); throw new IllegalArgumentException("Bad temp directory: "+dir);
@ -1122,6 +836,11 @@ public class WebAppContext extends ServletContextHandler
setAttribute(TEMPDIR,_tmpDir); setAttribute(TEMPDIR,_tmpDir);
} }
public File getTempDirectory ()
{
return _tmpDir;
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* @param war The war to set as a file name or URL * @param war The war to set as a file name or URL
@ -1175,120 +894,14 @@ public class WebAppContext extends ServletContextHandler
protected void startContext() protected void startContext()
throws Exception throws Exception
{ {
// Configure defaults
for (int i=0;i<_configurations.length;i++)
_configurations[i].configureDefaults();
// Is there a WEB-INF work directory
Resource web_inf=getWebInf();
if (web_inf!=null)
{
Resource work= web_inf.addPath("work");
if (work.exists()
&& work.isDirectory()
&& work.getFile() != null
&& work.getFile().canWrite()
&& getAttribute(TEMPDIR) == null)
setAttribute(TEMPDIR, work.getFile());
}
// Configure webapp // Configure webapp
for (int i=0;i<_configurations.length;i++) for (int i=0;i<_configurations.length;i++)
_configurations[i].configureWebApp(); _configurations[i].configure(this);
super.startContext(); super.startContext();
} }
/**
* Create a canonical name for a webapp tmp directory.
* The form of the name is:
* "Jetty_"+host+"_"+port+"__"+resourceBase+"_"+context+"_"+virtualhost+base36 hashcode of whole string
*
* host and port uniquely identify the server
* context and virtual host uniquely identify the webapp
* @return
*/
private String getCanonicalNameForWebAppTmpDir ()
{
StringBuffer canonicalName = new StringBuffer();
canonicalName.append("Jetty");
//get the host and the port from the first connector
Connector[] connectors = getServer().getConnectors();
//Get the host
canonicalName.append("_");
String host = (connectors==null||connectors[0]==null?"":connectors[0].getHost());
if (host == null)
host = "0.0.0.0";
canonicalName.append(host.replace('.', '_'));
//Get the port
canonicalName.append("_");
//try getting the real port being listened on
int port = (connectors==null||connectors[0]==null?0:connectors[0].getLocalPort());
//if not available (eg no connectors or connector not started),
//try getting one that was configured.
if (port < 0)
port = connectors[0].getPort();
canonicalName.append(port);
//Resource base
canonicalName.append("_");
try
{
Resource resource = super.getBaseResource();
if (resource == null)
{
if (_war==null || _war.length()==0)
resource=newResource(getResourceBase());
// Set dir or WAR
resource= newResource(_war);
}
String tmp = URIUtil.decodePath(resource.getURL().getPath());
if (tmp.endsWith("/"))
tmp = tmp.substring(0, tmp.length()-1);
if (tmp.endsWith("!"))
tmp = tmp.substring(0, tmp.length() -1);
//get just the last part which is the filename
int i = tmp.lastIndexOf("/");
canonicalName.append(tmp.substring(i+1, tmp.length()));
}
catch (Exception e)
{
Log.warn("Can't generate resourceBase as part of webapp tmp dir name", e);
}
//Context name
canonicalName.append("_");
String contextPath = getContextPath();
contextPath=contextPath.replace('/','_');
contextPath=contextPath.replace('\\','_');
canonicalName.append(contextPath);
//Virtual host (if there is one)
canonicalName.append("_");
String[] vhosts = getVirtualHosts();
canonicalName.append((vhosts==null||vhosts[0]==null?"":vhosts[0]));
//base36 hash of the whole string for uniqueness
String hash = Integer.toString(canonicalName.toString().hashCode(),36);
canonicalName.append("_");
canonicalName.append(hash);
// sanitize
for (int i=0;i<canonicalName.length();i++)
{
char c=canonicalName.charAt(i);
if (!Character.isJavaIdentifierPart(c))
canonicalName.setCharAt(i,'.');
}
return canonicalName.toString();
}
} }

View File

@ -1,94 +1,484 @@
// ========================================================================
// Copyright (c) 2003-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; package org.eclipse.jetty.webapp;
import java.io.File;
import java.io.IOException;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.resource.JarResource;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
/* ------------------------------------------------------------------------------- */
/**
* Configure class path from a WEB-INF directory found within a contexts resource base.
*
*
*/
public class WebInfConfiguration implements Configuration public class WebInfConfiguration implements Configuration
{ {
protected WebAppContext _context; public static final String TEMPDIR_CREATED = "org.eclipse.jetty.tmpdirCreated";
public WebInfConfiguration() public void preConfigure(WebAppContext context) throws Exception
{ {
} //Make a temp directory for the webapp if one is not already set
resolveTempDirectory(context);
//Extract webapp if necessary
unpack (context);
/* ------------------------------------------------------------------------------- */ File work = findWorkDirectory(context);
public void setWebAppContext (WebAppContext context) if (work != null)
makeTempDirectory(work, context, false);
}
public void postConfigure(WebAppContext context) throws Exception
{ {
_context = context; // TODO Auto-generated method stub
}
/* ------------------------------------------------------------------------------- */
public WebAppContext getWebAppContext()
{
return _context;
} }
/* ------------------------------------------------------------------------------- */ public void configure(WebAppContext context) throws Exception
/** Configure ClassPath.
* This method is called before the context ClassLoader is created.
* Paths and libraries should be added to the context using the setClassPath,
* addClassPath and addClassPaths methods. The default implementation looks
* for WEB-INF/classes, WEB-INF/lib/*.zip and WEB-INF/lib/*.jar
* @throws Exception
*/
public void configureClassLoader()
throws Exception
{ {
//cannot configure if the context is already started //cannot configure if the context is already started
if (_context.isStarted()) if (context.isStarted())
{ {
if (Log.isDebugEnabled()){Log.debug("Cannot configure webapp after it is started");} if (Log.isDebugEnabled()){Log.debug("Cannot configure webapp "+context+" after it is started");}
return; return;
} }
Resource web_inf=_context.getWebInf(); Resource web_inf = context.getWebInf();
// Add WEB-INF classes and lib classpaths // Add WEB-INF classes and lib classpaths
if (web_inf != null && web_inf.isDirectory() && _context.getClassLoader() instanceof WebAppClassLoader) if (web_inf != null && web_inf.isDirectory() && context.getClassLoader() instanceof WebAppClassLoader)
{ {
// Look for classes directory // Look for classes directory
Resource classes= web_inf.addPath("classes/"); Resource classes= web_inf.addPath("classes/");
if (classes.exists()) if (classes.exists())
((WebAppClassLoader)_context.getClassLoader()).addClassPath(classes.toString()); ((WebAppClassLoader)context.getClassLoader()).addClassPath(classes.toString());
// Look for jars // Look for jars
Resource lib= web_inf.addPath("lib/"); Resource lib= web_inf.addPath("lib/");
if (lib.exists() || lib.isDirectory()) if (lib.exists() || lib.isDirectory())
((WebAppClassLoader)_context.getClassLoader()).addJars(lib); ((WebAppClassLoader)context.getClassLoader()).addJars(lib);
} }
}
public void deconfigure(WebAppContext context) throws Exception
{
// delete temp directory if we had to create it or if it isn't called work
Boolean containerCreated = (Boolean)context.getAttribute(TEMPDIR_CREATED);
} if (context.getTempDirectory()!=null && (containerCreated != null && containerCreated.booleanValue()) && !isTempWorkDirectory(context.getTempDirectory()))
{
/* ------------------------------------------------------------------------------- */ IO.delete(context.getTempDirectory());
public void configureDefaults() throws Exception setTempDirectory(null, context);
{ }
} }
/* ------------------------------------------------------------------------------- */
public void configureWebApp() throws Exception
/* ------------------------------------------------------------ */
/**
* Get a temporary directory in which to unpack the war etc etc.
* The algorithm for determining this is to check these alternatives
* in the order shown:
*
* <p>A. Try to use an explicit directory specifically for this webapp:</p>
* <ol>
* <li>
* Iff an explicit directory is set for this webapp, use it. Do NOT set
* delete on exit.
* </li>
* <li>
* Iff javax.servlet.context.tempdir context attribute is set for
* this webapp && exists && writeable, then use it. Do NOT set delete on exit.
* </li>
* </ol>
*
* <p>B. Create a directory based on global settings. The new directory
* will be called "Jetty_"+host+"_"+port+"__"+context+"_"+virtualhost
* Work out where to create this directory:
* <ol>
* <li>
* Iff $(jetty.home)/work exists create the directory there. Do NOT
* set delete on exit. Do NOT delete contents if dir already exists.
* </li>
* <li>
* Iff WEB-INF/work exists create the directory there. Do NOT set
* delete on exit. Do NOT delete contents if dir already exists.
* </li>
* <li>
* Else create dir in $(java.io.tmpdir). Set delete on exit. Delete
* contents if dir already exists.
* </li>
* </ol>
*
* @return
*/
public void resolveTempDirectory (WebAppContext context)
{ {
//If a tmp directory is already set, we're done
File tmpDir = context.getTempDirectory();
if (tmpDir!=null && tmpDir.isDirectory() && tmpDir.canWrite())
return; //Already have a suitable tmp dir configured
//None configured, try and come up with one
//First ... see if one is configured in a context attribute
//either as a File or name of a file
Object t = context.getAttribute(WebAppContext.TEMPDIR);
if (t != null)
{
//Is it a File?
if (t instanceof File)
{
tmpDir=(File)t;
if (tmpDir.isDirectory() && tmpDir.canWrite())
{
context.setTempDirectory(tmpDir);
return;
}
}
// The context attribute specified a name not a File
if (t instanceof String)
{
try
{
tmpDir=new File((String)t);
if (tmpDir.isDirectory() && tmpDir.canWrite())
{
context.setAttribute(context.TEMPDIR,tmpDir);
context.setTempDirectory(tmpDir);
return;
}
}
catch(Exception e)
{
Log.warn(Log.EXCEPTION,e);
}
}
}
// Second ... make a tmp directory, in a work directory if one exists
String temp = getCanonicalNameForWebAppTmpDir(context);
try
{
//Put the tmp dir in the work directory if we had one
File work = new File(System.getProperty("jetty.home"),"work");
if (!work.exists() || !work.canWrite() || !work.isDirectory())
work = null;
if (work!=null)
makeTempDirectory(work, context, false); //make a tmp dir inside work, don't delete if it exists
else
makeTempDirectory(new File(System.getProperty("java.io.tmpdir")), context, true); //make a tmpdir, delete if it already exists
}
catch(Exception e)
{
tmpDir=null;
Log.ignore(e);
}
//Third ... Something went wrong trying to make the tmp directory, just make
//a jvm managed tmp directory
if (context.getTempDirectory() == null)
{
try
{
// Last resort
tmpDir=File.createTempFile("JettyContext","");
if (tmpDir.exists())
tmpDir.delete();
tmpDir.mkdir();
tmpDir.deleteOnExit();
setTempDirectory(tmpDir, context);
}
catch(IOException e)
{
Log.warn("tmpdir",e); System.exit(1);
}
}
}
public void makeTempDirectory (File parent, WebAppContext context, boolean deleteExisting)
throws IOException
{
if (parent != null && parent.exists() && parent.canWrite() && parent.isDirectory())
{
String temp = getCanonicalNameForWebAppTmpDir(context);
File tmpDir = new File(parent,temp);
if (deleteExisting && tmpDir.exists())
{
if (!IO.delete(tmpDir))
{
if(Log.isDebugEnabled())Log.debug("Failed to delete temp dir "+tmpDir);
}
//If we can't delete the existing tmp dir, create a new one
if (tmpDir.exists())
{
String old=tmpDir.toString();
tmpDir=File.createTempFile(temp+"_","");
if (tmpDir.exists())
tmpDir.delete();
Log.warn("Can't reuse "+old+", using "+tmpDir);
}
}
if (!tmpDir.exists())
tmpDir.mkdir();
//If the parent is not a work directory
if (!isTempWorkDirectory(tmpDir))
{
tmpDir.deleteOnExit();
//TODO why is this here?
File sentinel = new File(tmpDir, ".active");
if(!sentinel.exists())
sentinel.mkdir();
}
setTempDirectory(tmpDir, context);
}
} }
/* ------------------------------------------------------------------------------- */
public void deconfigureWebApp() throws Exception public void setTempDirectory (File tmpDir, WebAppContext context)
{ {
context.setAttribute(TEMPDIR_CREATED, Boolean.TRUE);
context.setAttribute(context.TEMPDIR,tmpDir);
context.setTempDirectory(tmpDir);
if(Log.isDebugEnabled())Log.debug("Set temp dir "+tmpDir);
} }
public void unpack (WebAppContext context) throws IOException
{
Resource web_app = context.getBaseResource();
if (web_app == null)
{
String war = context.getWar();
if (war==null || war.length()==0)
war=context.getResourceBase();
// Set dir or WAR
web_app = context.newResource(war);
// Accept aliases for WAR files
if (web_app.getAlias() != null)
{
Log.debug(web_app + " anti-aliased to " + web_app.getAlias());
web_app = context.newResource(web_app.getAlias());
}
if (Log.isDebugEnabled())
Log.debug("Try webapp=" + web_app + ", exists=" + web_app.exists() + ", directory=" + web_app.isDirectory());
// Is the WAR usable directly?
if (web_app.exists() && !web_app.isDirectory() && !web_app.toString().startsWith("jar:"))
{
// No - then lets see if it can be turned into a jar URL.
Resource jarWebApp = context.newResource("jar:" + web_app + "!/");
if (jarWebApp.exists() && jarWebApp.isDirectory())
{
web_app= jarWebApp;
}
}
// If we should extract or the URL is still not usable
if (web_app.exists() &&
(
(context.isCopyWebDir() && web_app.getFile()!= null && web_app.getFile().isDirectory())
||
(context.isExtractWAR() && web_app.getFile()!= null && !web_app.getFile().isDirectory())
||
(context.isExtractWAR() && web_app.getFile() == null)
||
!web_app.isDirectory()
))
{
// Then extract it if necessary to the temporary location
File extractedWebAppDir= new File(context.getTempDirectory(), "webapp");
if (web_app.getFile()!=null && web_app.getFile().isDirectory())
{
// Copy directory
Log.info("Copy " + web_app.getFile() + " to " + extractedWebAppDir);
IO.copyDir(web_app.getFile(),extractedWebAppDir);
}
else
{
if (!extractedWebAppDir.exists())
{
//it hasn't been extracted before so extract it
extractedWebAppDir.mkdir();
Log.info("Extract " + war + " to " + extractedWebAppDir);
JarResource.extract(web_app, extractedWebAppDir, false);
}
else
{
//only extract if the war file is newer
if (web_app.lastModified() > extractedWebAppDir.lastModified())
{
extractedWebAppDir.delete();
extractedWebAppDir.mkdir();
Log.info("Extract " + war + " to " + extractedWebAppDir);
JarResource.extract(web_app, extractedWebAppDir, false);
}
}
}
web_app = Resource.newResource(extractedWebAppDir.getCanonicalPath());
}
// Now do we have something usable?
if (!web_app.exists() || !web_app.isDirectory())
{
Log.warn("Web application not found " + war);
throw new java.io.FileNotFoundException(war);
}
context.setBaseResource(web_app);
System.err.println("SetBaseResource in WebInfConfiguration, toString="+context.toString());
if (Log.isDebugEnabled())
Log.debug("webapp=" + web_app);
}
}
public File findWorkDirectory (WebAppContext context) throws IOException
{
if (context.getBaseResource() != null)
{
Resource web_inf = context.getWebInf();
if (web_inf !=null && web_inf.exists())
{
return new File(web_inf.getFile(),"work");
}
}
return null;
}
/**
* Check if the tmpDir itself is called "work", or if the tmpDir
* is in a directory called "work".
* @return
*/
public boolean isTempWorkDirectory (File tmpDir)
{
if (tmpDir == null)
return false;
if (tmpDir.getName().equalsIgnoreCase("work"))
return true;
File t = tmpDir.getParentFile();
if (t == null)
return false;
return (t.getName().equalsIgnoreCase("work"));
}
/**
* Create a canonical name for a webapp tmp directory.
* The form of the name is:
* "Jetty_"+host+"_"+port+"__"+resourceBase+"_"+context+"_"+virtualhost+base36 hashcode of whole string
*
* host and port uniquely identify the server
* context and virtual host uniquely identify the webapp
* @return
*/
public String getCanonicalNameForWebAppTmpDir (WebAppContext context)
{
StringBuffer canonicalName = new StringBuffer();
canonicalName.append("Jetty");
//get the host and the port from the first connector
Connector[] connectors = context.getServer().getConnectors();
//Get the host
canonicalName.append("_");
String host = (connectors==null||connectors[0]==null?"":connectors[0].getHost());
if (host == null)
host = "0.0.0.0";
canonicalName.append(host.replace('.', '_'));
//Get the port
canonicalName.append("_");
//try getting the real port being listened on
int port = (connectors==null||connectors[0]==null?0:connectors[0].getLocalPort());
//if not available (eg no connectors or connector not started),
//try getting one that was configured.
if (port < 0)
port = connectors[0].getPort();
canonicalName.append(port);
//Resource base
canonicalName.append("_");
try
{
Resource resource = context.getBaseResource();
if (resource == null)
{
if (context.getWar()==null || context.getWar().length()==0)
resource=context.newResource(context.getResourceBase());
// Set dir or WAR
resource = context.newResource(context.getWar());
}
String tmp = URIUtil.decodePath(resource.getURL().getPath());
if (tmp.endsWith("/"))
tmp = tmp.substring(0, tmp.length()-1);
if (tmp.endsWith("!"))
tmp = tmp.substring(0, tmp.length() -1);
//get just the last part which is the filename
int i = tmp.lastIndexOf("/");
canonicalName.append(tmp.substring(i+1, tmp.length()));
}
catch (Exception e)
{
Log.warn("Can't generate resourceBase as part of webapp tmp dir name", e);
}
//Context name
canonicalName.append("_");
String contextPath = context.getContextPath();
contextPath=contextPath.replace('/','_');
contextPath=contextPath.replace('\\','_');
canonicalName.append(contextPath);
//Virtual host (if there is one)
canonicalName.append("_");
String[] vhosts = context.getVirtualHosts();
canonicalName.append((vhosts==null||vhosts[0]==null?"":vhosts[0]));
//base36 hash of the whole string for uniqueness
String hash = Integer.toString(canonicalName.toString().hashCode(),36);
canonicalName.append("_");
canonicalName.append(hash);
// sanitize
for (int i=0;i<canonicalName.length();i++)
{
char c=canonicalName.charAt(i);
if (!Character.isJavaIdentifierPart(c))
canonicalName.setCharAt(i,'.');
}
return canonicalName.toString();
}
} }

View File

@ -0,0 +1,954 @@
// ========================================================================
// 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.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.Servlet;
import javax.servlet.UnavailableException;
import org.eclipse.jetty.http.security.Constraint;
import org.eclipse.jetty.security.ConstraintAware;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.security.authentication.FormAuthenticator;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.FilterMapping;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.ServletMapping;
import org.eclipse.jetty.util.LazyList;
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;
/**
* WebXmlProcessor
*
*
*/
public class WebXmlProcessor
{
public static final String __web_processor = "org.eclipse.jetty.webProcessor";
protected WebAppContext _context;
protected XmlParser _xmlParser;
protected XmlParser.Node _webDefaultsRoot;
protected XmlParser.Node _webXmlRoot;
protected List<XmlParser.Node> _webFragmentRoots = new ArrayList<XmlParser.Node>();
protected XmlParser.Node _webOverrideRoot;
protected int _version;
protected boolean _metaDataComplete = false;
protected ServletHandler _servletHandler;
protected SecurityHandler _securityHandler;
protected Object _filters;
protected Object _filterMappings;
protected Object _servlets;
protected Object _servletMappings;
protected Object _listeners;
protected Object _welcomeFiles;
protected Set<String> _roles = new HashSet<String>();
protected Object _constraintMappings;
protected Map _errorPages;
protected boolean _hasJSP;
protected String _jspServletName;
protected String _jspServletClass;
protected boolean _defaultWelcomeFileList;
public static XmlParser webXmlParser() 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,"jsp_2_1.xsd",jsp21xsd);
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 WebXmlProcessor (WebAppContext context) throws ClassNotFoundException
{
_context = context;
_xmlParser = webXmlParser();
}
public int getVersion ()
{
return _version;
}
public boolean isMetaDataComplete ()
{
return _metaDataComplete;
}
public void processForVersion (XmlParser.Node config)
{
String version = config.getAttribute("version", "DTD");
if ("2.5".equals(version))
_version = 25;
else if ("2.4".equals(version))
_version = 24;
else if ("3.0".equals(version))
_version = 30;
else if ("DTD".equals(version))
{
_version = 23;
String dtd = _xmlParser.getDTD();
if (dtd != null && dtd.indexOf("web-app_2_2") >= 0) _version = 22;
}
if (_version < 25)
_metaDataComplete = true; // does not apply before 2.5
else
_metaDataComplete = Boolean.valueOf((String) config.getAttribute("metadata-complete", "false")).booleanValue();
Log.debug("Calculated metadatacomplete = " + _metaDataComplete + " with version=" + version);
_context.setAttribute("metadata-complete", String.valueOf(_metaDataComplete));
}
public XmlParser.Node parseDefaults (URL webDefaults)
throws Exception
{
_webDefaultsRoot = _xmlParser.parse(webDefaults.toString());
return _webDefaultsRoot;
}
public XmlParser.Node parseWebXml (URL webXml)
throws Exception
{
_webXmlRoot = _xmlParser.parse(webXml.toString());
processForVersion(_webXmlRoot);
return _webXmlRoot;
}
public XmlParser.Node parseFragment (URL fragment)
throws Exception
{
if (isMetaDataComplete())
return null; //do not process anything else if main web.xml file is complete
//Metadata-complete is not set, or there is no web.xml
XmlParser.Node root = _xmlParser.parse(fragment.toString());
_webFragmentRoots.add(root);
return root;
}
public XmlParser.Node parseOverride (URL override)
throws Exception
{
_xmlParser.setValidating(false);
_webOverrideRoot = _xmlParser.parse(override.toString());
return _webOverrideRoot;
}
public void processDefaults ()
throws Exception
{
process (_webDefaultsRoot);
_defaultWelcomeFileList = _context.getWelcomeFiles() != null;
}
public void processWebXml ()
throws Exception
{
process (_webXmlRoot);
}
public void processFragments ()
throws Exception
{
for (XmlParser.Node frag : _webFragmentRoots)
{
process (frag);
}
}
public void processOverride ()
throws Exception
{
process(_webOverrideRoot);
}
public XmlParser.Node getWebXml ()
{
return _webXmlRoot;
}
public XmlParser.Node getOverrideWeb ()
{
return _webOverrideRoot;
}
public XmlParser.Node getWebDefault ()
{
return _webDefaultsRoot;
}
public List<XmlParser.Node> getFragments ()
{
return _webFragmentRoots;
}
public void process (XmlParser.Node config)
throws Exception
{
//Get the current objects from the context
_servletHandler = _context.getServletHandler();
_securityHandler = (SecurityHandler)_context.getSecurityHandler();
_filters = LazyList.array2List(_servletHandler.getFilters());
_filterMappings = LazyList.array2List(_servletHandler.getFilterMappings());
_servlets = LazyList.array2List(_servletHandler.getServlets());
_servletMappings = LazyList.array2List(_servletHandler.getServletMappings());
_listeners = LazyList.array2List(_context.getEventListeners());
_welcomeFiles = LazyList.array2List(_context.getWelcomeFiles());
if (_securityHandler instanceof ConstraintAware)
{
_constraintMappings = LazyList.array2List(((ConstraintAware) _securityHandler).getConstraintMappings());
if (((ConstraintAware) _securityHandler).getRoles() != null)
{
_roles.addAll(((ConstraintAware) _securityHandler).getRoles());
}
}
_errorPages = _context.getErrorHandler() instanceof ErrorPageErrorHandler ? ((ErrorPageErrorHandler)_context.getErrorHandler()).getErrorPages() : null;
Iterator iter = config.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");
}
}
//Set the context with the results of the processing
_servletHandler.setFilters((FilterHolder[]) LazyList.toArray(_filters, FilterHolder.class));
_servletHandler.setFilterMappings((FilterMapping[]) LazyList.toArray(_filterMappings, FilterMapping.class));
_servletHandler.setServlets((ServletHolder[]) LazyList.toArray(_servlets, ServletHolder.class));
_servletHandler.setServletMappings((ServletMapping[]) LazyList.toArray(_servletMappings, ServletMapping.class));
_context.setEventListeners((EventListener[]) LazyList.toArray(_listeners, EventListener.class));
_context.setWelcomeFiles((String[]) LazyList.toArray(_welcomeFiles, String.class));
// TODO jaspi check this
if (_securityHandler instanceof ConstraintAware)
{
((ConstraintAware) _securityHandler).setConstraintMappings((ConstraintMapping[]) LazyList.toArray(_constraintMappings,
ConstraintMapping.class),
_roles);
}
if (_errorPages != null && _context.getErrorHandler() instanceof ErrorPageErrorHandler)
((ErrorPageErrorHandler)_context.getErrorHandler()).setErrorPages(_errorPages);
}
/* ------------------------------------------------------------ */
/**
* Handle web.xml element. This method is called for each top level element
* within the web.xml file. It may be specialized by derived WebAppHandlers
* to provide additional configuration and handling.
*
* @param element The element name
* @param node The node containing the element.
*/
protected void initWebXmlElement(String element, XmlParser.Node node) throws Exception
{
if ("display-name".equals(element))
initDisplayName(node);
else if ("description".equals(element))
{
}
else if ("context-param".equals(element))
initContextParam(node);
else if ("servlet".equals(element))
initServlet(node);
else if ("servlet-mapping".equals(element))
initServletMapping(node);
else if ("session-config".equals(element))
initSessionConfig(node);
else if ("mime-mapping".equals(element))
initMimeConfig(node);
else if ("welcome-file-list".equals(element))
initWelcomeFileList(node);
else if ("locale-encoding-mapping-list".equals(element))
initLocaleEncodingList(node);
else if ("error-page".equals(element))
initErrorPage(node);
else if ("taglib".equals(element))
initTagLib(node);
else if ("jsp-config".equals(element))
initJspConfig(node);
else if ("resource-ref".equals(element))
{
if (Log.isDebugEnabled()) Log.debug("No implementation: " + node);
}
else if ("security-constraint".equals(element))
initSecurityConstraint(node);
else if ("login-config".equals(element))
initLoginConfig(node);
else if ("security-role".equals(element))
initSecurityRole(node);
else if ("filter".equals(element))
initFilter(node);
else if ("filter-mapping".equals(element))
initFilterMapping(node);
else if ("listener".equals(element))
initListener(node);
else if ("distributable".equals(element))
initDistributable(node);
else if ("web-fragment".equals(element))
{
}
else
{
if (Log.isDebugEnabled())
{
Log.debug("Element {} not handled in {}", element, this);
Log.debug(node.toString());
}
}
}
/* ------------------------------------------------------------ */
protected void initDisplayName(XmlParser.Node node)
{
_context.setDisplayName(node.toString(false, true));
}
/* ------------------------------------------------------------ */
protected void initContextParam(XmlParser.Node node)
{
String name = node.getString("param-name", false, true);
String value = node.getString("param-value", false, true);
if (Log.isDebugEnabled()) Log.debug("ContextParam: " + name + "=" + value);
_context.getInitParams().put(name, value);
}
/* ------------------------------------------------------------ */
protected void initFilter(XmlParser.Node node)
{
String name = node.getString("filter-name", false, true);
FilterHolder holder = _servletHandler.getFilter(name);
if (holder == null)
{
holder = _servletHandler.newFilterHolder();
holder.setName(name);
_filters = LazyList.add(_filters, holder);
}
String filter_class = node.getString("filter-class", false, true);
if (filter_class != null) holder.setClassName(filter_class);
Iterator iter = node.iterator("init-param");
while (iter.hasNext())
{
XmlParser.Node paramNode = (XmlParser.Node) iter.next();
String pname = paramNode.getString("param-name", false, true);
String pvalue = paramNode.getString("param-value", false, true);
holder.setInitParameter(pname, pvalue);
}
String async=node.getString("async-support",false,true);
if (async!=null)
holder.setAsyncSupported(Boolean.valueOf(async));
}
/* ------------------------------------------------------------ */
protected void initFilterMapping(XmlParser.Node node)
{
String filter_name = node.getString("filter-name", false, true);
FilterMapping mapping = new FilterMapping();
mapping.setFilterName(filter_name);
ArrayList paths = new ArrayList();
Iterator iter = node.iterator("url-pattern");
while (iter.hasNext())
{
String p = ((XmlParser.Node) iter.next()).toString(false, true);
p = normalizePattern(p);
paths.add(p);
}
mapping.setPathSpecs((String[]) paths.toArray(new String[paths.size()]));
ArrayList names = new ArrayList();
iter = node.iterator("servlet-name");
while (iter.hasNext())
{
String n = ((XmlParser.Node) iter.next()).toString(false, true);
names.add(n);
}
mapping.setServletNames((String[]) names.toArray(new String[names.size()]));
int dispatcher=FilterMapping.DEFAULT;
iter=node.iterator("dispatcher");
while(iter.hasNext())
{
String d=((XmlParser.Node)iter.next()).toString(false,true);
dispatcher|=FilterMapping.dispatch(d);
}
mapping.setDispatches(dispatcher);
_filterMappings = LazyList.add(_filterMappings, mapping);
}
/* ------------------------------------------------------------ */
protected String normalizePattern(String p)
{
if (p != null && p.length() > 0 && !p.startsWith("/") && !p.startsWith("*")) return "/" + p;
return p;
}
/* ------------------------------------------------------------ */
protected void initServlet(XmlParser.Node node)
{
String id = node.getAttribute("id");
// initialize holder
String servlet_name = node.getString("servlet-name", false, true);
ServletHolder holder = _servletHandler.getServlet(servlet_name);
if (holder == null)
{
holder = _servletHandler.newServletHolder();
holder.setName(servlet_name);
_servlets = LazyList.add(_servlets, holder);
}
// init params
Iterator iParamsIter = node.iterator("init-param");
while (iParamsIter.hasNext())
{
XmlParser.Node paramNode = (XmlParser.Node) iParamsIter.next();
String pname = paramNode.getString("param-name", false, true);
String pvalue = paramNode.getString("param-value", false, true);
holder.setInitParameter(pname, pvalue);
}
String servlet_class = node.getString("servlet-class", false, true);
// Handle JSP
if (id != null && id.equals("jsp"))
{
_jspServletName = servlet_name;
_jspServletClass = servlet_class;
try
{
Loader.loadClass(this.getClass(), servlet_class);
_hasJSP = true;
}
catch (ClassNotFoundException e)
{
Log.info("NO JSP Support for {}, did not find {}", _context.getContextPath(), servlet_class);
_hasJSP = false;
_jspServletClass = servlet_class = "org.eclipse.jetty.servlet.NoJspServlet";
}
if (holder.getInitParameter("scratchdir") == null)
{
File tmp = _context.getTempDirectory();
File scratch = new File(tmp, "jsp");
if (!scratch.exists()) scratch.mkdir();
holder.setInitParameter("scratchdir", scratch.getAbsolutePath());
if ("?".equals(holder.getInitParameter("classpath")))
{
String classpath = _context.getClassPath();
Log.debug("classpath=" + classpath);
if (classpath != null) holder.setInitParameter("classpath", classpath);
}
}
}
if (servlet_class != null) holder.setClassName(servlet_class);
// Handler JSP file
String jsp_file = node.getString("jsp-file", false, true);
if (jsp_file != null)
{
holder.setForcedPath(jsp_file);
holder.setClassName(_jspServletClass);
}
// handle startup
XmlParser.Node startup = node.get("load-on-startup");
if (startup != null)
{
String s = startup.toString(false, true).toLowerCase();
if (s.startsWith("t"))
{
Log.warn("Deprecated boolean load-on-startup. Please use integer");
holder.setInitOrder(1);
}
else
{
int order = 0;
try
{
if (s != null && s.trim().length() > 0) order = Integer.parseInt(s);
}
catch (Exception e)
{
Log.warn("Cannot parse load-on-startup " + s + ". Please use integer");
Log.ignore(e);
}
holder.setInitOrder(order);
}
}
Iterator sRefsIter = node.iterator("security-role-ref");
while (sRefsIter.hasNext())
{
XmlParser.Node securityRef = (XmlParser.Node) sRefsIter.next();
String roleName = securityRef.getString("role-name", false, true);
String roleLink = securityRef.getString("role-link", false, true);
if (roleName != null && roleName.length() > 0 && roleLink != null && roleLink.length() > 0)
{
if (Log.isDebugEnabled()) Log.debug("link role " + roleName + " to " + roleLink + " for " + this);
holder.setUserRoleLink(roleName, roleLink);
}
else
{
Log.warn("Ignored invalid security-role-ref element: " + "servlet-name=" + holder.getName() + ", " + securityRef);
}
}
XmlParser.Node run_as = node.get("run-as");
if (run_as != null)
{
String roleName = run_as.getString("role-name", false, true);
if (roleName != null)
holder.setRunAsRole(roleName);
}
String async=node.getString("async-support",false,true);
if (async!=null)
holder.setAsyncSupported(Boolean.valueOf(async));
}
/* ------------------------------------------------------------ */
protected void initServletMapping(XmlParser.Node node)
{
String servlet_name = node.getString("servlet-name", false, true);
ServletMapping mapping = new ServletMapping();
mapping.setServletName(servlet_name);
ArrayList paths = new ArrayList();
Iterator iter = node.iterator("url-pattern");
while (iter.hasNext())
{
String p = ((XmlParser.Node) iter.next()).toString(false, true);
p = normalizePattern(p);
paths.add(p);
}
mapping.setPathSpecs((String[]) paths.toArray(new String[paths.size()]));
_servletMappings = LazyList.add(_servletMappings, mapping);
}
/* ------------------------------------------------------------ */
protected void initListener(XmlParser.Node node)
{
String className = node.getString("listener-class", false, true);
Object listener = null;
try
{
Class listenerClass = _context.loadClass(className);
listener = newListenerInstance(listenerClass);
if (!(listener instanceof EventListener))
{
Log.warn("Not an EventListener: " + listener);
return;
}
_listeners = LazyList.add(_listeners, listener);
}
catch (Exception e)
{
Log.warn("Could not instantiate listener " + className, e);
return;
}
}
/* ------------------------------------------------------------ */
protected Object newListenerInstance(Class clazz) throws InstantiationException, IllegalAccessException
{
return clazz.newInstance();
}
/* ------------------------------------------------------------ */
protected void initDistributable(XmlParser.Node node)
{
// the element has no content, so its simple presence
// indicates that the webapp is distributable...
if (!_context.isDistributable())
_context.setDistributable(true);
}
/* ------------------------------------------------------------ */
protected void initSessionConfig(XmlParser.Node node)
{
XmlParser.Node tNode = node.get("session-timeout");
if (tNode != null)
{
int timeout = Integer.parseInt(tNode.toString(false, true));
_context.getSessionHandler().getSessionManager().setMaxInactiveInterval(timeout * 60);
}
}
/* ------------------------------------------------------------ */
protected void initMimeConfig(XmlParser.Node node)
{
String extension = node.getString("extension", false, true);
if (extension != null && extension.startsWith(".")) extension = extension.substring(1);
String mimeType = node.getString("mime-type", false, true);
_context.getMimeTypes().addMimeMapping(extension, mimeType);
}
/* ------------------------------------------------------------ */
protected void initWelcomeFileList(XmlParser.Node node)
{
if (_defaultWelcomeFileList)
_welcomeFiles = null; // erase welcome files from default web.xml
_defaultWelcomeFileList = false;
Iterator iter = node.iterator("welcome-file");
while (iter.hasNext())
{
XmlParser.Node indexNode = (XmlParser.Node) iter.next();
String welcome = indexNode.toString(false, true);
_welcomeFiles = LazyList.add(_welcomeFiles, welcome);
}
}
/* ------------------------------------------------------------ */
protected void initLocaleEncodingList(XmlParser.Node node)
{
Iterator iter = node.iterator("locale-encoding-mapping");
while (iter.hasNext())
{
XmlParser.Node mapping = (XmlParser.Node) iter.next();
String locale = mapping.getString("locale", false, true);
String encoding = mapping.getString("encoding", false, true);
_context.addLocaleEncoding(locale, encoding);
}
}
/* ------------------------------------------------------------ */
protected void initErrorPage(XmlParser.Node node)
{
String error = node.getString("error-code", false, true);
if (error == null || error.length() == 0) error = node.getString("exception-type", false, true);
String location = node.getString("location", false, true);
if (_errorPages == null)
_errorPages = new HashMap();
_errorPages.put(error, location);
}
/* ------------------------------------------------------------ */
protected void initTagLib(XmlParser.Node node)
{
String uri = node.getString("taglib-uri", false, true);
String location = node.getString("taglib-location", false, true);
_context.setResourceAlias(uri, location);
}
/* ------------------------------------------------------------ */
protected void initJspConfig(XmlParser.Node node)
{
for (int i = 0; i < node.size(); i++)
{
Object o = node.get(i);
if (o instanceof XmlParser.Node && "taglib".equals(((XmlParser.Node) o).getTag())) initTagLib((XmlParser.Node) o);
}
// Map URLs from jsp property groups to JSP servlet.
// this is more JSP stupidness creaping into the servlet spec
Iterator iter = node.iterator("jsp-property-group");
Object paths = null;
while (iter.hasNext())
{
XmlParser.Node group = (XmlParser.Node) iter.next();
Iterator iter2 = group.iterator("url-pattern");
while (iter2.hasNext())
{
String url = ((XmlParser.Node) iter2.next()).toString(false, true);
url = normalizePattern(url);
paths = LazyList.add(paths, url);
}
}
if (LazyList.size(paths) > 0)
{
String jspName = getJSPServletName();
if (jspName != null)
{
ServletMapping mapping = new ServletMapping();
mapping.setServletName(jspName);
mapping.setPathSpecs(LazyList.toStringArray(paths));
_servletMappings = LazyList.add(_servletMappings, mapping);
}
}
}
/* ------------------------------------------------------------ */
protected void initSecurityConstraint(XmlParser.Node node)
{
Constraint scBase = new Constraint();
try
{
XmlParser.Node auths = node.get("auth-constraint");
if (auths != null)
{
scBase.setAuthenticate(true);
// auth-constraint
Iterator iter = auths.iterator("role-name");
Object roles = null;
while (iter.hasNext())
{
String role = ((XmlParser.Node) iter.next()).toString(false, true);
roles = LazyList.add(roles, role);
}
scBase.setRoles(LazyList.toStringArray(roles));
}
XmlParser.Node data = node.get("user-data-constraint");
if (data != null)
{
data = data.get("transport-guarantee");
String guarantee = data.toString(false, true).toUpperCase();
if (guarantee == null || guarantee.length() == 0 || "NONE".equals(guarantee))
scBase.setDataConstraint(Constraint.DC_NONE);
else if ("INTEGRAL".equals(guarantee))
scBase.setDataConstraint(Constraint.DC_INTEGRAL);
else if ("CONFIDENTIAL".equals(guarantee))
scBase.setDataConstraint(Constraint.DC_CONFIDENTIAL);
else
{
Log.warn("Unknown user-data-constraint:" + guarantee);
scBase.setDataConstraint(Constraint.DC_CONFIDENTIAL);
}
}
Iterator iter = node.iterator("web-resource-collection");
while (iter.hasNext())
{
XmlParser.Node collection = (XmlParser.Node) iter.next();
String name = collection.getString("web-resource-name", false, true);
Constraint sc = (Constraint) scBase.clone();
sc.setName(name);
Iterator iter2 = collection.iterator("url-pattern");
while (iter2.hasNext())
{
String url = ((XmlParser.Node) iter2.next()).toString(false, true);
url = normalizePattern(url);
Iterator iter3 = collection.iterator("http-method");
if (iter3.hasNext())
{
while (iter3.hasNext())
{
String method = ((XmlParser.Node) iter3.next()).toString(false, true);
ConstraintMapping mapping = new ConstraintMapping();
mapping.setMethod(method);
mapping.setPathSpec(url);
mapping.setConstraint(sc);
_constraintMappings = LazyList.add(_constraintMappings, mapping);
}
}
else
{
ConstraintMapping mapping = new ConstraintMapping();
mapping.setPathSpec(url);
mapping.setConstraint(sc);
_constraintMappings = LazyList.add(_constraintMappings, mapping);
}
}
}
}
catch (CloneNotSupportedException e)
{
Log.warn(e);
}
}
/* ------------------------------------------------------------ */
protected void initLoginConfig(XmlParser.Node node) throws Exception
{
XmlParser.Node method = node.get("auth-method");
if (method != null)
{
XmlParser.Node name = node.get("realm-name");
_securityHandler.setRealmName(name == null ? "default" : name.toString(false, true));
_securityHandler.setAuthMethod(method.toString(false, true));
if (Constraint.__FORM_AUTH.equals(_securityHandler.getAuthMethod()))
{
XmlParser.Node formConfig = node.get("form-login-config");
if (formConfig != null)
{
String loginPageName = null;
XmlParser.Node loginPage = formConfig.get("form-login-page");
if (loginPage != null)
loginPageName = loginPage.toString(false, true);
String errorPageName = null;
XmlParser.Node errorPage = formConfig.get("form-error-page");
if (errorPage != null)
errorPageName = errorPage.toString(false, true);
_securityHandler.setInitParameter(FormAuthenticator.__FORM_LOGIN_PAGE,loginPageName);
_securityHandler.setInitParameter(FormAuthenticator.__FORM_ERROR_PAGE,errorPageName);
}
else
{
throw new IllegalArgumentException("!form-login-config");
}
}
}
}
/* ------------------------------------------------------------ */
protected void initSecurityRole(XmlParser.Node node)
{
XmlParser.Node roleNode = node.get("role-name");
String role = roleNode.toString(false, true);
_roles.add(role);
}
/* ------------------------------------------------------------ */
protected String getJSPServletName()
{
if (_jspServletName == null)
{
Map.Entry entry = _context.getServletHandler().getHolderEntry("test.jsp");
if (entry != null)
{
ServletHolder holder = (ServletHolder) entry.getValue();
_jspServletName = holder.getName();
}
}
return _jspServletName;
}
}