Merge branch 'jetty-9.1' into release-9.1

This commit is contained in:
Jesse McConnell 2013-09-30 18:19:56 -05:00
commit 727c64a5e9
114 changed files with 2584 additions and 2453 deletions

View File

@ -51,7 +51,7 @@ public class FileServer
handlers.setHandlers(new Handler[] { resource_handler, new DefaultHandler() });
server.setHandler(handlers);
//Start things up! By using the server.join() the server thread will join with the current thread.
// Start things up! By using the server.join() the server thread will join with the current thread.
// See "http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()" for more details.
server.start();
server.join();

View File

@ -48,7 +48,9 @@ public class LikeJettyXml
public static void main(String[] args) throws Exception
{
String jetty_home = System.getProperty("jetty.home","../../jetty-distribution/target/distribution");
String jetty_base = System.getProperty("jetty.home","../../jetty-distribution/target/distribution/demo-base");
System.setProperty("jetty.home",jetty_home);
System.setProperty("jetty.base",jetty_base);
// === jetty.xml ===
@ -132,7 +134,7 @@ public class LikeJettyXml
deployer.setContextAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",".*/servlet-api-[^/]*\\.jar$");
WebAppProvider webapp_provider = new WebAppProvider();
webapp_provider.setMonitoredDirName(jetty_home + "/webapps");
webapp_provider.setMonitoredDirName(jetty_base + "/webapps");
webapp_provider.setDefaultsDescriptor(jetty_home + "/etc/webdefault.xml");
webapp_provider.setScanInterval(1);
webapp_provider.setExtractWars(true);
@ -176,7 +178,7 @@ public class LikeJettyXml
// === test-realm.xml ===
HashLoginService login = new HashLoginService();
login.setName("Test Realm");
login.setConfig(jetty_home + "/etc/realm.properties");
login.setConfig(jetty_base + "/etc/realm.properties");
login.setRefreshInterval(0);
server.addBean(login);

View File

@ -46,8 +46,10 @@ public class MinimalServlets
// on a given context path.
// !! This is a raw Servlet, not a servlet that has been configured through a web.xml or anything like that !!
handler.addServletWithMapping(HelloServlet.class,"/*");
handler.addServletWithMapping(HelloServlet.class, "/*");
// Start things up! By using the server.join() the server thread will join with the current thread.
// See "http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()" for more details.
server.start();
server.join();
}

View File

@ -18,6 +18,9 @@
package org.eclipse.jetty.embedded;
import java.lang.management.ManagementFactory;
import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
@ -26,19 +29,40 @@ public class OneWebApp
{
public static void main(String[] args) throws Exception
{
// Create a basic jetty server object that will listen on port 8080. Note that if you set this to port 0 then
// a randomly available port will be assigned that you can either look in the logs for the port,
// or programmatically obtain it for use in test cases.
Server server = new Server(8080);
// Setup JMX
MBeanContainer mbContainer=new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
server.addBean(mbContainer);
// The WebAppContext is the entity that controls the environment in which a web application lives and
// breathes. In this example the context path is being set to "/" so it is suitable for serving root context
// requests and then we see it setting the location of the war. A whole host of other configurations are
// available, ranging from configuring to support annotation scanning in the webapp (through
// PlusConfiguration) to choosing where the webapp will unpack itself.
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
webapp.setWar("../../tests/test-webapps/test-jetty-webapp/target/test-jetty-webapp-9.0.0-SNAPSHOT.war");
webapp.setWar("../../jetty-distribution/target/distribution/demo-base/webapps/test.war");
// A WebAppContext is a ContextHandler as well so it needs to be set to the server so it is aware of where to
// send the appropriate requests.
server.setHandler(webapp);
// Configure a LoginService
// Since this example is for our test webapp, we need to setup a LoginService so this shows how to create a
// very simple hashmap based one. The name of the LoginService needs to correspond to what is configured in
// the webapp's web.xml and since it has a lifecycle of its own we register it as a bean with the Jetty
// server object so it can be started and stopped according to the lifecycle of the server itself.
HashLoginService loginService = new HashLoginService();
loginService.setName("Test Realm");
loginService.setConfig("src/test/resources/realm.properties");
server.addBean(loginService);
// Start things up! By using the server.join() the server thread will join with the current thread.
// See "http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()" for more details.
server.start();
server.join();
}

View File

@ -32,31 +32,56 @@ public class SecuredHelloHandler
{
public static void main(String[] args) throws Exception
{
// Create a basic jetty server object that will listen on port 8080. Note that if you set this to port 0
// then a randomly available port will be assigned that you can either look in the logs for the port,
// or programmatically obtain it for use in test cases.
Server server = new Server(8080);
// Since this example is for our test webapp, we need to setup a LoginService so this shows how to create a
// very simple hashmap based one. The name of the LoginService needs to correspond to what is configured a
// webapp's web.xml and since it has a lifecycle of its own we register it as a bean with the Jetty server
// object so it can be started and stopped according to the lifecycle of the server itself. In this example
// the name can be whatever you like since we are not dealing with webapp realms.
LoginService loginService = new HashLoginService("MyRealm","src/test/resources/realm.properties");
server.addBean(loginService);
// A security handler is a jetty handler that secures content behind a particular portion of a url space. The
// ConstraintSecurityHandler is a more specialized handler that allows matching of urls to different
// constraints. The server sets this as the first handler in the chain,
// effectively applying these constraints to all subsequent handlers in the chain.
ConstraintSecurityHandler security = new ConstraintSecurityHandler();
server.setHandler(security);
// This constraint requires authentication and in addition that an authenticated user be a member of a given
// set of roles for authorization purposes.
Constraint constraint = new Constraint();
constraint.setName("auth");
constraint.setAuthenticate( true );
constraint.setRoles(new String[]{"user", "admin"});
// Binds a url pattern with the previously created constraint. The roles for this constraing mapping are
// mined from the Constraint itself although methods exist to declare and bind roles separately as well.
ConstraintMapping mapping = new ConstraintMapping();
mapping.setPathSpec( "/*" );
mapping.setConstraint( constraint );
// First you see the constraint mapping being applied to the handler as a singleton list,
// however you can passing in as many security constraint mappings as you like so long as they follow the
// mapping requirements of the servlet api. Next we set a BasicAuthenticator instance which is the object
// that actually checks the credentials followed by the LoginService which is the store of known users, etc.
security.setConstraintMappings(Collections.singletonList(mapping));
security.setAuthenticator(new BasicAuthenticator());
security.setLoginService(loginService);
// The Hello Handler is the handler we are securing so we create one, and then set it as the handler on the
// security handler to complain the simple handler chain.
HelloHandler hh = new HelloHandler();
// chain the hello handler into the security handler
security.setHandler(hh);
// Start things up! By using the server.join() the server thread will join with the current thread.
// See "http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()" for more details.
server.start();
server.join();
}

View File

@ -43,7 +43,8 @@ public class ServerWithAnnotations
//Create a WebApp
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
webapp.setWar("../../tests/test-webapps/test-servlet-spec/test-spec-webapp/target/test-spec-webapp-9.0.4-SNAPSHOT.war");
webapp.setWar("../../tests/test-webapps/test-servlet-spec/test-spec-webapp/target/test-spec-webapp-9.1.0-SNAPSHOT.war");
webapp.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$");
server.setHandler(webapp);
//Register new transaction manager in JNDI

View File

@ -40,30 +40,42 @@ public class SplitFileServer
public static void main(String[] args) throws Exception
{
// Create the Server object and a corresponding ServerConnector and then set the port for the connector. In
// this example the server will listen on port 8090. If you set this to port 0 then when the server has been
// started you can called connector.getLocalPort() to programmatically get the port the server started on.
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(8090);
server.setConnectors(new Connector[]
{ connector });
// Create a Context Handler and ResourceHandler. The ContextHandler is getting set to "/" path but this could
// be anything you like for builing out your url. Note how we are setting the ResourceBase using our jetty
// maven testing utilities to get the proper resource directory, you needn't use these,
// you simply need to supply the paths you are looking to serve content from.
ContextHandler context0 = new ContextHandler();
context0.setContextPath("/");
ResourceHandler rh0 = new ResourceHandler();
rh0.setBaseResource( Resource.newResource(MavenTestingUtils.getTestResourceDir("dir0")));
context0.setHandler(rh0);
// Rinse and repeat the previous item, only specifying a different resource base.
ContextHandler context1 = new ContextHandler();
context1.setContextPath("/");
ResourceHandler rh1 = new ResourceHandler();
rh1.setBaseResource( Resource.newResource(MavenTestingUtils.getTestResourceDir("dir1")));
context1.setHandler(rh1);
// Create a ContextHandlerCollection and set the context handlers to it. This will let jetty process urls
// against the declared contexts in order to match up content.
ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(new Handler[]
{ context0, context1 });
server.setHandler(contexts);
// Start things up! By using the server.join() the server thread will join with the current thread.
// See "http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()" for more details.
server.start();
System.err.println(server.dump());
server.join();

View File

@ -25,7 +25,7 @@ import javax.websocket.server.ServerEndpoint;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.jsr356.server.ServerContainer;
import org.eclipse.jetty.websocket.jsr356.server.WebSocketConfiguration;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
/**
* Example of setting up a javax.websocket server with Jetty embedded
@ -54,7 +54,7 @@ public class WebSocketJsrServer
server.setHandler(context);
// Enable javax.websocket configuration for the context
ServerContainer wsContainer = WebSocketConfiguration.configureContext(context);
ServerContainer wsContainer = WebSocketServerContainerInitializer.configureContext(context);
// Add your websockets to the container
wsContainer.addEndpoint(EchoJsrSocket.class);

View File

@ -102,8 +102,12 @@
<artifactId>javax.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.orbit</groupId>
<artifactId>org.objectweb.asm</artifactId>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-commons</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -18,62 +18,30 @@
package org.eclipse.jetty.annotations;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.annotations.AnnotationParser.AbstractHandler;
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* DiscoverableAnnotationHandler
*
* Base class for handling the discovery of an annotation.
*
*/
public abstract class AbstractDiscoverableAnnotationHandler implements DiscoverableAnnotationHandler
public abstract class AbstractDiscoverableAnnotationHandler extends AbstractHandler
{
protected WebAppContext _context;
protected List<DiscoveredAnnotation> _annotations;
protected Resource _resource;
public AbstractDiscoverableAnnotationHandler(WebAppContext context)
{
this(context, null);
}
public AbstractDiscoverableAnnotationHandler(WebAppContext context, List<DiscoveredAnnotation> list)
{
_context = context;
if (list == null)
_annotations = new ArrayList<DiscoveredAnnotation>();
else
_annotations = list;
}
public Resource getResource()
{
return _resource;
}
public void setResource(Resource resource)
{
_resource = resource;
}
public List<DiscoveredAnnotation> getAnnotationList ()
{
return _annotations;
}
public void resetList()
{
_annotations.clear();
}
public void addAnnotation (DiscoveredAnnotation a)
{
_annotations.add(a);
_context.getMetaData().addDiscoveredAnnotation(a);
}
}

View File

@ -20,22 +20,28 @@ package org.eclipse.jetty.annotations;
import java.net.URI;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
import java.util.StringTokenizer;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.annotation.HandlesTypes;
import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.Handler;
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
import org.eclipse.jetty.util.ArrayUtil;
import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.webapp.AbstractConfiguration;
import org.eclipse.jetty.webapp.FragmentDescriptor;
import org.eclipse.jetty.webapp.MetaDataComplete;
@ -50,15 +56,50 @@ import org.eclipse.jetty.webapp.WebDescriptor;
public class AnnotationConfiguration extends AbstractConfiguration
{
private static final Logger LOG = Log.getLogger(AnnotationConfiguration.class);
public static final String CLASS_INHERITANCE_MAP = "org.eclipse.jetty.classInheritanceMap";
public static final String CONTAINER_INITIALIZERS = "org.eclipse.jetty.containerInitializers";
public static final String CONTAINER_INITIALIZER_LISTENER = "org.eclipse.jetty.containerInitializerListener";
public static final String CONTAINER_INITIALIZER_STARTER = "org.eclipse.jetty.containerInitializerStarter";
public static final String MULTI_THREADED = "org.eclipse.jetty.annotations.multiThreaded";
public static final String MAX_SCAN_WAIT = "org.eclipse.jetty.annotations.maxWait";
public static final int DEFAULT_MAX_SCAN_WAIT = 60; /* time in sec */
public static final boolean DEFAULT_MULTI_THREADED = true;
protected List<DiscoverableAnnotationHandler> _discoverableAnnotationHandlers = new ArrayList<DiscoverableAnnotationHandler>();
protected List<AbstractDiscoverableAnnotationHandler> _discoverableAnnotationHandlers = new ArrayList<AbstractDiscoverableAnnotationHandler>();
protected ClassInheritanceHandler _classInheritanceHandler;
protected List<ContainerInitializerAnnotationHandler> _containerInitializerAnnotationHandlers = new ArrayList<ContainerInitializerAnnotationHandler>();
protected List<ParserTask> _parserTasks;
protected WebAppClassNameResolver _webAppClassNameResolver;
protected ContainerClassNameResolver _containerClassNameResolver;
public class ParserTask implements Callable<Void>
{
protected Exception _exception;
protected final AnnotationParser _parser;
protected final Set<? extends Handler> _handlers;
protected final ClassNameResolver _resolver;
protected final Resource _resource;
public ParserTask (AnnotationParser parser, Set<? extends Handler>handlers, Resource resource, ClassNameResolver resolver)
{
_parser = parser;
_handlers = handlers;
_resolver = resolver;
_resource = resource;
}
public Void call() throws Exception
{
if (_parser != null)
_parser.parse(_handlers, _resource, _resolver);
return null;
}
}
/**
* WebAppClassNameResolver
@ -138,10 +179,12 @@ public class AnnotationConfiguration extends AbstractConfiguration
@Override
public void preConfigure(final WebAppContext context) throws Exception
{
_webAppClassNameResolver = new WebAppClassNameResolver(context);
_containerClassNameResolver = new ContainerClassNameResolver(context);
}
public void addDiscoverableAnnotationHandler(DiscoverableAnnotationHandler handler)
public void addDiscoverableAnnotationHandler(AbstractDiscoverableAnnotationHandler handler)
{
_discoverableAnnotationHandlers.add(handler);
}
@ -151,11 +194,11 @@ public class AnnotationConfiguration extends AbstractConfiguration
{
context.removeAttribute(CLASS_INHERITANCE_MAP);
context.removeAttribute(CONTAINER_INITIALIZERS);
ServletContainerInitializerListener listener = (ServletContainerInitializerListener)context.getAttribute(CONTAINER_INITIALIZER_LISTENER);
if (listener != null)
ServletContainerInitializersStarter starter = (ServletContainerInitializersStarter)context.getAttribute(CONTAINER_INITIALIZER_STARTER);
if (starter != null)
{
context.removeBean(listener);
context.removeAttribute(CONTAINER_INITIALIZER_LISTENER);
context.removeBean(starter);
context.removeAttribute(CONTAINER_INITIALIZER_STARTER);
}
}
@ -165,13 +208,11 @@ public class AnnotationConfiguration extends AbstractConfiguration
@Override
public void configure(WebAppContext context) throws Exception
{
boolean metadataComplete = context.getMetaData().isMetaDataComplete();
context.addDecorator(new AnnotationDecorator(context));
//Even if metadata is complete, we still need to scan for ServletContainerInitializers - if there are any
AnnotationParser parser = null;
if (!metadataComplete)
if (!context.getMetaData().isMetaDataComplete())
{
//If metadata isn't complete, if this is a servlet 3 webapp or isConfigDiscovered is true, we need to search for annotations
if (context.getServletContext().getEffectiveMajorVersion() >= 3 || context.isConfigurationDiscovered())
@ -181,31 +222,13 @@ public class AnnotationConfiguration extends AbstractConfiguration
_discoverableAnnotationHandlers.add(new WebListenerAnnotationHandler(context));
}
}
else
if (LOG.isDebugEnabled()) LOG.debug("Metadata-complete==true, not processing discoverable servlet annotations for context "+context);
//Regardless of metadata, if there are any ServletContainerInitializers with @HandlesTypes, then we need to scan all the
//classes so we can call their onStartup() methods correctly
createServletContainerInitializerAnnotationHandlers(context, getNonExcludedInitializers(context));
if (!_discoverableAnnotationHandlers.isEmpty() || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty())
{
parser = createAnnotationParser();
if (LOG.isDebugEnabled()) LOG.debug("Scanning all classses for annotations: webxmlVersion="+context.getServletContext().getEffectiveMajorVersion()+" configurationDiscovered="+context.isConfigurationDiscovered());
parseContainerPath(context, parser);
//email from Rajiv Mordani jsrs 315 7 April 2010
// If there is a <others/> then the ordering should be
// WEB-INF/classes the order of the declared elements + others.
// In case there is no others then it is
// WEB-INF/classes + order of the elements.
parseWebInfClasses(context, parser);
parseWebInfLib (context, parser);
for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
context.getMetaData().addDiscoveredAnnotations(((AbstractDiscoverableAnnotationHandler)h).getAnnotationList());
}
scanForAnnotations(context);
}
@ -216,15 +239,17 @@ public class AnnotationConfiguration extends AbstractConfiguration
@Override
public void postConfigure(WebAppContext context) throws Exception
{
MultiMap<String> map = (MultiMap<String>)context.getAttribute(CLASS_INHERITANCE_MAP);
if (map != null)
map.clear();
ConcurrentHashMap<String, ConcurrentHashSet<String>> classMap = (ConcurrentHashMap<String, ConcurrentHashSet<String>>)context.getAttribute(CLASS_INHERITANCE_MAP);
List<ContainerInitializer> initializers = (List<ContainerInitializer>)context.getAttribute(CONTAINER_INITIALIZERS);
context.removeAttribute(CLASS_INHERITANCE_MAP);
if (classMap != null)
classMap.clear();
List<ContainerInitializer> initializers = (List<ContainerInitializer>)context.getAttribute(CONTAINER_INITIALIZERS);
context.removeAttribute(CONTAINER_INITIALIZERS);
if (initializers != null)
initializers.clear();
if (_discoverableAnnotationHandlers != null)
_discoverableAnnotationHandlers.clear();
@ -232,11 +257,115 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (_containerInitializerAnnotationHandlers != null)
_containerInitializerAnnotationHandlers.clear();
if (_parserTasks != null)
{
_parserTasks.clear();
_parserTasks = null;
}
super.postConfigure(context);
}
/**
* @return a new AnnotationParser. This method can be overridden to use a different impleemntation of
* Perform scanning of classes for annotations
*
* @param context
* @throws Exception
*/
protected void scanForAnnotations (WebAppContext context)
throws Exception
{
AnnotationParser parser = createAnnotationParser();
boolean multiThreadedScan = isUseMultiThreading(context);
int maxScanWait = 0;
if (multiThreadedScan)
{
_parserTasks = new ArrayList<ParserTask>();
maxScanWait = getMaxScanWait(context);
}
long start = 0;
if (LOG.isDebugEnabled())
{
start = System.nanoTime();
LOG.debug("Scanning for annotations: webxml={}, metadatacomplete={}, configurationDiscovered={}, multiThreaded={}",
context.getServletContext().getEffectiveMajorVersion(),
context.getMetaData().isMetaDataComplete(),
context.isConfigurationDiscovered(),
multiThreadedScan);
}
parseContainerPath(context, parser);
//email from Rajiv Mordani jsrs 315 7 April 2010
// If there is a <others/> then the ordering should be
// WEB-INF/classes the order of the declared elements + others.
// In case there is no others then it is
// WEB-INF/classes + order of the elements.
parseWebInfClasses(context, parser);
parseWebInfLib (context, parser);
if (!multiThreadedScan)
{
if (LOG.isDebugEnabled())
{
long end = System.nanoTime();
LOG.debug("Annotation parsing millisec={}",(TimeUnit.MILLISECONDS.convert(end-start, TimeUnit.NANOSECONDS)));
}
return;
}
if (LOG.isDebugEnabled())
start = System.nanoTime();
//execute scan asynchronously using jetty's thread pool
final CountDownLatch latch = new CountDownLatch(_parserTasks.size());
final MultiException me = new MultiException();
final Semaphore task_limit=new Semaphore(Runtime.getRuntime().availableProcessors());
for (final ParserTask p:_parserTasks)
{
task_limit.acquire();
context.getServer().getThreadPool().execute(new Runnable()
{
@Override
public void run()
{
try
{
p.call();
}
catch (Exception e)
{
me.add(e);
}
finally
{
task_limit.release();
latch.countDown();
}
}
});
}
boolean timeout = !latch.await(maxScanWait, TimeUnit.SECONDS);
if (LOG.isDebugEnabled())
{
long end = System.nanoTime();
LOG.debug("Annotation parsing millisec={}",(TimeUnit.MILLISECONDS.convert(end-start, TimeUnit.NANOSECONDS)));
}
if (timeout)
me.add(new Exception("Timeout scanning annotations"));
me.ifExceptionThrow();
}
/**
* @return a new AnnotationParser. This method can be overridden to use a different implementation of
* the AnnotationParser. Note that this is considered internal API.
*/
protected AnnotationParser createAnnotationParser()
@ -244,6 +373,57 @@ public class AnnotationConfiguration extends AbstractConfiguration
return new AnnotationParser();
}
/**
* Check if we should use multiple threads to scan for annotations or not
* @param context
* @return
*/
protected boolean isUseMultiThreading(WebAppContext context)
{
//try context attribute to see if we should use multithreading
Object o = context.getAttribute(MULTI_THREADED);
if (o instanceof Boolean)
{
return ((Boolean)o).booleanValue();
}
//try server attribute to see if we should use multithreading
o = context.getServer().getAttribute(MULTI_THREADED);
if (o instanceof Boolean)
{
return ((Boolean)o).booleanValue();
}
//try system property to see if we should use multithreading
return Boolean.valueOf(System.getProperty(MULTI_THREADED, Boolean.toString(DEFAULT_MULTI_THREADED)));
}
/**
* Work out how long we should wait for the async scanning to occur.
*
* @param context
* @return
*/
protected int getMaxScanWait (WebAppContext context)
{
//try context attribute to get max time in sec to wait for scan completion
Object o = context.getAttribute(MAX_SCAN_WAIT);
if (o != null && o instanceof Number)
{
return ((Number)o).intValue();
}
//try server attribute to get max time in sec to wait for scan completion
o = context.getServer().getAttribute(MAX_SCAN_WAIT);
if (o != null && o instanceof Number)
{
return ((Number)o).intValue();
}
//try system property to get max time in sec to wait for scan completion
return Integer.getInteger(MAX_SCAN_WAIT, DEFAULT_MAX_SCAN_WAIT).intValue();
}
/**
* @see org.eclipse.jetty.webapp.AbstractConfiguration#cloneConfigure(org.eclipse.jetty.webapp.WebAppContext, org.eclipse.jetty.webapp.WebAppContext)
*/
@ -263,36 +443,30 @@ public class AnnotationConfiguration extends AbstractConfiguration
public void createServletContainerInitializerAnnotationHandlers (WebAppContext context, List<ServletContainerInitializer> scis)
throws Exception
{
if (scis == null || scis.isEmpty())
return; // nothing to do
List<ContainerInitializer> initializers = new ArrayList<ContainerInitializer>();
context.setAttribute(CONTAINER_INITIALIZERS, initializers);
for (ServletContainerInitializer service : scis)
{
HandlesTypes annotation = service.getClass().getAnnotation(HandlesTypes.class);
ContainerInitializer initializer = new ContainerInitializer();
initializer.setTarget(service);
initializers.add(initializer);
ContainerInitializer initializer = null;
if (annotation != null)
{
//There is a HandlesTypes annotation on the on the ServletContainerInitializer
Class[] classes = annotation.value();
if (classes != null)
{
initializer.setInterestedTypes(classes);
initializer = new ContainerInitializer(service, classes);
//If we haven't already done so, we need to register a handler that will
//process the whole class hierarchy to satisfy the ServletContainerInitializer
if (context.getAttribute(CLASS_INHERITANCE_MAP) == null)
{
MultiMap<String> map = new MultiMap<>();
//MultiMap<String> map = new MultiMap<>();
ConcurrentHashMap<String, ConcurrentHashSet<String>> map = new ConcurrentHashMap<String, ConcurrentHashSet<String>>();
context.setAttribute(CLASS_INHERITANCE_MAP, map);
_classInheritanceHandler = new ClassInheritanceHandler(map);
}
@ -304,28 +478,33 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (c.isAnnotation())
{
if (LOG.isDebugEnabled()) LOG.debug("Registering annotation handler for "+c.getName());
_containerInitializerAnnotationHandlers.add(new ContainerInitializerAnnotationHandler(initializer, c));
}
}
}
else
{
initializer = new ContainerInitializer(service, null);
if (LOG.isDebugEnabled()) LOG.debug("No classes in HandlesTypes on initializer "+service.getClass());
}
}
else
{
initializer = new ContainerInitializer(service, null);
if (LOG.isDebugEnabled()) LOG.debug("No annotation on initializer "+service.getClass());
}
initializers.add(initializer);
}
//add a bean which will call the servletcontainerinitializers when appropriate
ServletContainerInitializerListener listener = (ServletContainerInitializerListener)context.getAttribute(CONTAINER_INITIALIZER_LISTENER);
if (listener != null)
throw new IllegalStateException("ServletContainerInitializerListener already exists");
listener = new ServletContainerInitializerListener();
listener.setWebAppContext(context);
context.setAttribute(CONTAINER_INITIALIZER_LISTENER, listener);
context.addBean(listener, true);
//add a bean to the context which will call the servletcontainerinitializers when appropriate
ServletContainerInitializersStarter starter = (ServletContainerInitializersStarter)context.getAttribute(CONTAINER_INITIALIZER_STARTER);
if (starter != null)
throw new IllegalStateException("ServletContainerInitializersStarter already exists");
starter = new ServletContainerInitializersStarter(context);
context.setAttribute(CONTAINER_INITIALIZER_STARTER, starter);
context.addBean(starter, true);
}
@ -383,7 +562,12 @@ public class AnnotationConfiguration extends AbstractConfiguration
List<ServletContainerInitializer> nonExcludedInitializers = new ArrayList<ServletContainerInitializer>();
//We use the ServiceLoader mechanism to find the ServletContainerInitializer classes to inspect
long start = 0;
if (LOG.isDebugEnabled())
start = System.nanoTime();
ServiceLoader<ServletContainerInitializer> loadedInitializers = ServiceLoader.load(ServletContainerInitializer.class, context.getClassLoader());
if (LOG.isDebugEnabled())
LOG.debug("Service loaders found in {}ms", (TimeUnit.MILLISECONDS.convert((System.nanoTime()-start), TimeUnit.NANOSECONDS)));
if (loadedInitializers != null)
{
@ -406,33 +590,27 @@ public class AnnotationConfiguration extends AbstractConfiguration
* @param parser
* @throws Exception
*/
public void parseContainerPath (final WebAppContext context, final AnnotationParser parser)
throws Exception
public void parseContainerPath (final WebAppContext context, final AnnotationParser parser) throws Exception
{
//if no pattern for the container path is defined, then by default scan NOTHING
LOG.debug("Scanning container jars");
//always parse for discoverable annotations as well as class hierarchy and servletcontainerinitializer related annotations
parser.clearHandlers();
for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
{
if (h instanceof AbstractDiscoverableAnnotationHandler)
((AbstractDiscoverableAnnotationHandler)h).setResource(null); //
}
parser.registerHandlers(_discoverableAnnotationHandlers);
parser.registerHandler(_classInheritanceHandler);
parser.registerHandlers(_containerInitializerAnnotationHandlers);
final Set<Handler> handlers = new HashSet<Handler>();
handlers.addAll(_discoverableAnnotationHandlers);
handlers.addAll(_containerInitializerAnnotationHandlers);
if (_classInheritanceHandler != null)
handlers.add(_classInheritanceHandler);
//Convert from Resource to URI
ArrayList<URI> containerUris = new ArrayList<URI>();
for (Resource r : context.getMetaData().getContainerResources())
{
URI uri = r.getURI();
containerUris.add(uri);
//queue it up for scanning if using multithreaded mode
if (_parserTasks != null)
_parserTasks.add(new ParserTask(parser, handlers, r, _containerClassNameResolver));
else
//just scan it now
parser.parse(handlers, r, _containerClassNameResolver);
}
parser.parse (containerUris.toArray(new URI[containerUris.size()]),
new ContainerClassNameResolver (context));
}
@ -443,9 +621,10 @@ public class AnnotationConfiguration extends AbstractConfiguration
* @param parser
* @throws Exception
*/
public void parseWebInfLib (final WebAppContext context, final AnnotationParser parser)
throws Exception
public void parseWebInfLib (final WebAppContext context, final AnnotationParser parser) throws Exception
{
LOG.debug("Scanning WEB-INF/lib jars");
List<FragmentDescriptor> frags = context.getMetaData().getFragments();
//email from Rajiv Mordani jsrs 315 7 April 2010
@ -462,9 +641,8 @@ public class AnnotationConfiguration extends AbstractConfiguration
for (Resource r : jars)
{
//for each jar, we decide which set of annotations we need to parse for
parser.clearHandlers();
final Set<Handler> handlers = new HashSet<Handler>();
URI uri = r.getURI();
FragmentDescriptor f = getFragmentFromJar(r, frags);
//if its from a fragment jar that is metadata complete, we should skip scanning for @webservlet etc
@ -474,27 +652,26 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (f == null || !isMetaDataComplete(f) || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty())
{
//register the classinheritance handler if there is one
parser.registerHandler(_classInheritanceHandler);
if (_classInheritanceHandler != null)
handlers.add(_classInheritanceHandler);
//register the handlers for the @HandlesTypes values that are themselves annotations if there are any
parser.registerHandlers(_containerInitializerAnnotationHandlers);
handlers.addAll(_containerInitializerAnnotationHandlers);
//only register the discoverable annotation handlers if this fragment is not metadata complete, or has no fragment descriptor
if (f == null || !isMetaDataComplete(f))
{
for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
{
if (h instanceof AbstractDiscoverableAnnotationHandler)
((AbstractDiscoverableAnnotationHandler)h).setResource(r);
}
parser.registerHandlers(_discoverableAnnotationHandlers);
}
handlers.addAll(_discoverableAnnotationHandlers);
parser.parse(uri, new WebAppClassNameResolver(context));
if (_parserTasks != null)
_parserTasks.add (new ParserTask(parser, handlers,r, _webAppClassNameResolver));
else
parser.parse(handlers, r, _webAppClassNameResolver);
}
}
}
/**
* Scan classes in WEB-INF/classes
*
@ -505,27 +682,26 @@ public class AnnotationConfiguration extends AbstractConfiguration
public void parseWebInfClasses (final WebAppContext context, final AnnotationParser parser)
throws Exception
{
LOG.debug("Scanning classes in WEB-INF/classes");
LOG.debug("Scanning WEB-INF/classes");
parser.clearHandlers();
for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
{
if (h instanceof AbstractDiscoverableAnnotationHandler)
((AbstractDiscoverableAnnotationHandler)h).setResource(null); //
}
parser.registerHandlers(_discoverableAnnotationHandlers);
parser.registerHandler(_classInheritanceHandler);
parser.registerHandlers(_containerInitializerAnnotationHandlers);
Set<Handler> handlers = new HashSet<Handler>();
handlers.addAll(_discoverableAnnotationHandlers);
if (_classInheritanceHandler != null)
handlers.add(_classInheritanceHandler);
handlers.addAll(_containerInitializerAnnotationHandlers);
for (Resource dir : context.getMetaData().getWebInfClassesDirs())
{
parser.parseDir(dir, new WebAppClassNameResolver(context));
if (_parserTasks != null)
_parserTasks.add(new ParserTask(parser, handlers, dir, _webAppClassNameResolver));
else
parser.parse(handlers, dir, _webAppClassNameResolver);
}
}
/**
/**
* Get the web-fragment.xml from a jar
*
* @param jar
@ -554,6 +730,4 @@ public class AnnotationConfiguration extends AbstractConfiguration
{
return (d!=null && d.getMetaDataComplete() == MetaDataComplete.True);
}
}

View File

@ -19,8 +19,13 @@
package org.eclipse.jetty.annotations;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jetty.annotations.AnnotationParser.ClassHandler;
import org.eclipse.jetty.annotations.AnnotationParser.AbstractHandler;
import org.eclipse.jetty.annotations.AnnotationParser.ClassInfo;
import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -30,33 +35,33 @@ import org.eclipse.jetty.util.log.Logger;
*
* As asm scans for classes, remember the type hierarchy.
*/
public class ClassInheritanceHandler implements ClassHandler
public class ClassInheritanceHandler extends AbstractHandler
{
private static final Logger LOG = Log.getLogger(ClassInheritanceHandler.class);
MultiMap<String> _inheritanceMap;
ConcurrentHashMap<String, ConcurrentHashSet<String>> _inheritanceMap;
public ClassInheritanceHandler()
{
_inheritanceMap = new MultiMap<>();
}
public ClassInheritanceHandler(MultiMap<String> map)
public ClassInheritanceHandler(ConcurrentHashMap<String, ConcurrentHashSet<String>> map)
{
_inheritanceMap = map;
}
public void handle(String className, int version, int access, String signature, String superName, String[] interfaces)
public void handle(ClassInfo classInfo)
{
try
{
for (int i=0; interfaces != null && i<interfaces.length;i++)
for (int i=0; classInfo.getInterfaces() != null && i < classInfo.getInterfaces().length;i++)
{
_inheritanceMap.add (interfaces[i], className);
addToInheritanceMap(classInfo.getInterfaces()[i], classInfo.getClassName());
//_inheritanceMap.add (classInfo.getInterfaces()[i], classInfo.getClassName());
}
//To save memory, we don't record classes that only extend Object, as that can be assumed
if (!"java.lang.Object".equals(superName))
_inheritanceMap.add(superName, className);
if (!"java.lang.Object".equals(classInfo.getSuperName()))
{
addToInheritanceMap(classInfo.getSuperName(), classInfo.getClassName());
//_inheritanceMap.add(classInfo.getSuperName(), classInfo.getClassName());
}
}
catch (Exception e)
{
@ -64,13 +69,21 @@ public class ClassInheritanceHandler implements ClassHandler
}
}
public List<String> getClassNamesExtendingOrImplementing (String className)
private void addToInheritanceMap (String interfaceOrSuperClassName, String implementingOrExtendingClassName)
{
return _inheritanceMap.getValues(className);
}
public MultiMap<String> getMap ()
{
return _inheritanceMap;
//As it is likely that the interfaceOrSuperClassName is already in the map, try getting it first
ConcurrentHashSet<String> implementingClasses = _inheritanceMap.get(interfaceOrSuperClassName);
//If it isn't in the map, then add it in, but test to make sure that someone else didn't get in
//first and add it
if (implementingClasses == null)
{
implementingClasses = new ConcurrentHashSet<String>();
ConcurrentHashSet<String> tmp = _inheritanceMap.putIfAbsent(interfaceOrSuperClassName, implementingClasses);
if (tmp != null)
implementingClasses = tmp;
}
implementingClasses.add(implementingOrExtendingClassName);
}
}

View File

@ -19,10 +19,11 @@
package org.eclipse.jetty.annotations;
import java.util.List;
import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import org.eclipse.jetty.annotations.AnnotationParser.AbstractHandler;
import org.eclipse.jetty.annotations.AnnotationParser.ClassInfo;
import org.eclipse.jetty.annotations.AnnotationParser.FieldInfo;
import org.eclipse.jetty.annotations.AnnotationParser.MethodInfo;
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
/**
@ -32,10 +33,14 @@ import org.eclipse.jetty.plus.annotation.ContainerInitializer;
* method level. The specified annotation is derived from an @HandlesTypes on
* a ServletContainerInitializer class.
*/
public class ContainerInitializerAnnotationHandler implements DiscoverableAnnotationHandler
/**
* @author janb
*
*/
public class ContainerInitializerAnnotationHandler extends AbstractHandler
{
ContainerInitializer _initializer;
Class _annotation;
final ContainerInitializer _initializer;
final Class _annotation;
public ContainerInitializerAnnotationHandler (ContainerInitializer initializer, Class annotation)
{
@ -45,35 +50,43 @@ public class ContainerInitializerAnnotationHandler implements DiscoverableAnnota
/**
* Handle finding a class that is annotated with the annotation we were constructed with.
* @see org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler#handleClass(java.lang.String, int, int, java.lang.String, java.lang.String, java.lang.String[], java.lang.String, java.util.List)
* @see org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler#handle(ClassInfo)
* */
public void handle(ClassInfo info, String annotationName)
{
if (annotationName == null || !_annotation.getName().equals(annotationName))
return;
_initializer.addAnnotatedTypeName(info.getClassName());
}
/**
* Handle finding a field that is annotated with the annotation we were constructed with.
*
* @see org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler#handle(org.eclipse.jetty.annotations.AnnotationParser.FieldAnnotationInfo)
*/
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotationName,
List<Value> values)
public void handle(FieldInfo info, String annotationName)
{
_initializer.addAnnotatedTypeName(className);
if (annotationName == null || !_annotation.getName().equals(annotationName))
return;
_initializer.addAnnotatedTypeName(info.getClassInfo().getClassName());
}
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
/**
* Handle finding a method that is annotated with the annotation we were constructed with.
*
* @see org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler#handle(org.eclipse.jetty.annotations.AnnotationParser.MethodAnnotationInfo)
*/
public void handle(MethodInfo info, String annotationName)
{
_initializer.addAnnotatedTypeName(className);
if (annotationName == null || !_annotation.getName().equals(annotationName))
return;
_initializer.addAnnotatedTypeName(info.getClassInfo().getClassName());
}
public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation,
List<Value> values)
{
_initializer.addAnnotatedTypeName(className);
}
@Override
public String getAnnotationName()
{
return _annotation.getName();
}
public ContainerInitializer getContainerInitializer()
{
return _initializer;
}
}

View File

@ -23,7 +23,6 @@ import java.util.List;
import javax.servlet.Servlet;
import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import org.eclipse.jetty.plus.annotation.RunAsCollection;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.log.Log;
@ -87,14 +86,12 @@ public class RunAsAnnotationHandler extends AbstractIntrospectableAnnotationHand
}
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation)
{
LOG.warn ("@RunAs annotation not applicable for fields: "+className+"."+fieldName);
}
public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation,
List<Value> values)
public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation)
{
LOG.warn("@RunAs annotation ignored on method: "+className+"."+methodName+" "+signature);
}

View File

@ -1,145 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.annotations;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* ServletContainerInitializerListener
*
*
*/
public class ServletContainerInitializerListener extends AbstractLifeCycle
{
private static final Logger LOG = Log.getLogger(ServletContainerInitializerListener.class);
protected WebAppContext _context = null;
public void setWebAppContext (WebAppContext context)
{
_context = context;
}
/**
* Call the doStart method of the ServletContainerInitializers
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
*/
public void doStart()
{
List<ContainerInitializer> initializers = (List<ContainerInitializer>)_context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS);
MultiMap classMap = (MultiMap)_context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP);
if (initializers != null)
{
for (ContainerInitializer i : initializers)
{
//We have already found the classes that directly have an annotation that was in the HandlesTypes
//annotation of the ServletContainerInitializer. For each of those classes, walk the inheritance
//hierarchy to find classes that extend or implement them.
if (i.getAnnotatedTypeNames() != null)
{
Set<String> annotatedClassNames = new HashSet<String>(i.getAnnotatedTypeNames());
for (String name : annotatedClassNames)
{
//add the class with the annotation
i.addApplicableTypeName(name);
//add the classes that inherit the annotation
if (classMap != null)
{
List<String> implementsOrExtends = (List<String>)classMap.getValues(name);
if (implementsOrExtends != null && !implementsOrExtends.isEmpty())
addInheritedTypes(classMap, i, implementsOrExtends);
}
}
}
//Now we need to look at the HandlesTypes classes that were not annotations. We need to
//find all classes that extend or implement them.
if (i.getInterestedTypes() != null)
{
for (Class c : i.getInterestedTypes())
{
if (!c.isAnnotation())
{
//add the classes that implement or extend the class.
//TODO but not including the class itself?
if (classMap != null)
{
List<String> implementsOrExtends = (List<String>)classMap.getValues(c.getName());
if (implementsOrExtends != null && !implementsOrExtends.isEmpty())
addInheritedTypes(classMap, i, implementsOrExtends);
}
}
}
}
//instantiate ServletContainerInitializers, call doStart
try
{
i.callStartup(_context);
}
catch (Exception e)
{
LOG.warn(e);
throw new RuntimeException(e);
}
}
}
}
void addInheritedTypes (MultiMap classMap, ContainerInitializer initializer, List<String> applicableTypes)
{
for (String s : applicableTypes)
{
//add the name of the class that extends or implements
initializer.addApplicableTypeName(s);
//walk the hierarchy and find all types that extend or implement it
List<String> implementsOrExtends = (List<String>)classMap.getValues(s);
if (implementsOrExtends != null && !implementsOrExtends.isEmpty())
addInheritedTypes (classMap, initializer, implementsOrExtends);
}
}
/**
* Nothing to do for ServletContainerInitializers on stop
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
*/
public void doStop()
{
}
}

View File

@ -0,0 +1,161 @@
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.annotations;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* ServletContainerInitializersStarter
*
* Call the onStartup() method on all ServletContainerInitializers, after having
* found all applicable classes (if any) to pass in as args.
*/
public class ServletContainerInitializersStarter extends AbstractLifeCycle
{
private static final Logger LOG = Log.getLogger(ServletContainerInitializersStarter.class);
WebAppContext _context;
/**
* @param context
*/
public ServletContainerInitializersStarter(WebAppContext context)
{
_context = context;
}
/**
* Call the doStart method of the ServletContainerInitializers
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
*/
public void doStart()
{
List<ContainerInitializer> initializers = (List<ContainerInitializer>)_context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS);
if (initializers == null)
return;
ConcurrentHashMap<String, ConcurrentHashSet<String>> map = ( ConcurrentHashMap<String, ConcurrentHashSet<String>>)_context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP);
for (ContainerInitializer i : initializers)
{
configureHandlesTypes(_context, i, map);
//instantiate ServletContainerInitializers, call doStart
try
{
i.callStartup(_context);
}
catch (Exception e)
{
LOG.warn(e);
throw new RuntimeException(e);
}
}
}
private void configureHandlesTypes (WebAppContext context, ContainerInitializer initializer, ConcurrentHashMap<String, ConcurrentHashSet<String>> classMap)
{
doHandlesTypesAnnotations(context, initializer, classMap);
doHandlesTypesClasses(context, initializer, classMap);
}
private void doHandlesTypesAnnotations(WebAppContext context, ContainerInitializer initializer, ConcurrentHashMap<String, ConcurrentHashSet<String>> classMap)
{
if (initializer == null)
return;
if (context == null)
throw new IllegalArgumentException("WebAppContext null");
//We have already found the classes that directly have an annotation that was in the HandlesTypes
//annotation of the ServletContainerInitializer. For each of those classes, walk the inheritance
//hierarchy to find classes that extend or implement them.
Set<String> annotatedClassNames = initializer.getAnnotatedTypeNames();
if (annotatedClassNames != null && !annotatedClassNames.isEmpty())
{
if (classMap == null)
throw new IllegalStateException ("No class hierarchy");
for (String name : annotatedClassNames)
{
//add the class that has the annotation
initializer.addApplicableTypeName(name);
//find and add the classes that inherit the annotation
addInheritedTypes(classMap, initializer, (ConcurrentHashSet<String>)classMap.get(name));
}
}
}
private void doHandlesTypesClasses (WebAppContext context, ContainerInitializer initializer, ConcurrentHashMap<String, ConcurrentHashSet<String>> classMap)
{
if (initializer == null)
return;
if (context == null)
throw new IllegalArgumentException("WebAppContext null");
//Now we need to look at the HandlesTypes classes that were not annotations. We need to
//find all classes that extend or implement them.
if (initializer.getInterestedTypes() != null)
{
if (classMap == null)
throw new IllegalStateException ("No class hierarchy");
for (Class c : initializer.getInterestedTypes())
{
if (!c.isAnnotation())
{
//find and add the classes that implement or extend the class.
//but not including the class itself
addInheritedTypes(classMap, initializer, (ConcurrentHashSet<String>)classMap.get(c.getName()));
}
}
}
}
private void addInheritedTypes (ConcurrentHashMap<String, ConcurrentHashSet<String>> classMap, ContainerInitializer initializer, ConcurrentHashSet<String> names)
{
if (names == null || names.isEmpty())
return;
for (String s : names)
{
//add the name of the class
initializer.addApplicableTypeName(s);
//walk the hierarchy and find all types that extend or implement the class
addInheritedTypes(classMap, initializer, (ConcurrentHashSet<String>)classMap.get(s));
}
}
}

View File

@ -18,12 +18,11 @@
package org.eclipse.jetty.annotations;
import java.util.List;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import org.eclipse.jetty.annotations.AnnotationParser.ClassInfo;
import org.eclipse.jetty.annotations.AnnotationParser.FieldInfo;
import org.eclipse.jetty.annotations.AnnotationParser.MethodInfo;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
import org.eclipse.jetty.webapp.WebAppContext;
/**
@ -40,37 +39,30 @@ public class WebFilterAnnotationHandler extends AbstractDiscoverableAnnotationHa
super(context);
}
public WebFilterAnnotationHandler (WebAppContext context, List<DiscoveredAnnotation> list)
{
super(context, list);
}
@Override
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)
public void handle(ClassInfo info, String annotationName)
{
WebFilterAnnotation wfAnnotation = new WebFilterAnnotation(_context, className, _resource);
if (annotationName == null || !"javax.servlet.annotation.WebFilter".equals(annotationName))
return;
WebFilterAnnotation wfAnnotation = new WebFilterAnnotation(_context, info.getClassName(), info.getContainingResource());
addAnnotation(wfAnnotation);
}
@Override
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
public void handle(FieldInfo info, String annotationName)
{
LOG.warn ("@WebFilter not applicable for fields: "+className+"."+fieldName);
if (annotationName == null || !"javax.servlet.annotation.WebFilter".equals(annotationName))
return;
LOG.warn ("@WebFilter not applicable for fields: "+info.getClassInfo().getClassName()+"."+info.getFieldName());
}
@Override
public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation,
List<Value> values)
public void handle(MethodInfo info, String annotationName)
{
LOG.warn ("@WebFilter not applicable for methods: "+className+"."+methodName+" "+signature);
if (annotationName == null || !"javax.servlet.annotation.WebFilter".equals(annotationName))
return;
LOG.warn ("@WebFilter not applicable for methods: "+info.getClassInfo().getClassName()+"."+info.getMethodName()+" "+info.getSignature());
}
@Override
public String getAnnotationName()
{
return "javax.servlet.annotation.WebFilter";
}
}

View File

@ -18,12 +18,11 @@
package org.eclipse.jetty.annotations;
import java.util.List;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import org.eclipse.jetty.annotations.AnnotationParser.ClassInfo;
import org.eclipse.jetty.annotations.AnnotationParser.FieldInfo;
import org.eclipse.jetty.annotations.AnnotationParser.MethodInfo;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
import org.eclipse.jetty.webapp.WebAppContext;
public class WebListenerAnnotationHandler extends AbstractDiscoverableAnnotationHandler
@ -35,37 +34,30 @@ public class WebListenerAnnotationHandler extends AbstractDiscoverableAnnotation
super(context);
}
public WebListenerAnnotationHandler (WebAppContext context, List<DiscoveredAnnotation> list)
{
super(context, list);
}
/**
* @see org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler#handleClass(java.lang.String, int, int, java.lang.String, java.lang.String, java.lang.String[], java.lang.String, java.util.List)
* @see org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler#handle(ClassAnnotationInfo)
*/
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)
public void handle(ClassInfo info, String annotationName)
{
WebListenerAnnotation wlAnnotation = new WebListenerAnnotation(_context, className, _resource);
if (annotationName == null || !"javax.servlet.annotation.WebListener".equals(annotationName))
return;
WebListenerAnnotation wlAnnotation = new WebListenerAnnotation(_context, info.getClassName(), info.getContainingResource());
addAnnotation(wlAnnotation);
}
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
public void handle(FieldInfo info, String annotationName)
{
LOG.warn ("@WebListener is not applicable to fields: "+className+"."+fieldName);
if (annotationName == null || !"javax.servlet.annotation.WebListener".equals(annotationName))
return;
LOG.warn ("@WebListener is not applicable to fields: "+info.getClassInfo().getClassName()+"."+info.getFieldName());
}
public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation,
List<Value> values)
public void handle(MethodInfo info, String annotationName)
{
LOG.warn ("@WebListener is not applicable to methods: "+className+"."+methodName+" "+signature);
if (annotationName == null || !"javax.servlet.annotation.WebListener".equals(annotationName))
return;
LOG.warn ("@WebListener is not applicable to methods: "+info.getClassInfo().getClassName()+"."+info.getMethodName()+" "+info.getSignature());
}
@Override
public String getAnnotationName()
{
return "javax.servlet.annotation.WebListener";
}
}

View File

@ -20,7 +20,9 @@ package org.eclipse.jetty.annotations;
import java.util.List;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import org.eclipse.jetty.annotations.AnnotationParser.ClassInfo;
import org.eclipse.jetty.annotations.AnnotationParser.FieldInfo;
import org.eclipse.jetty.annotations.AnnotationParser.MethodInfo;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
@ -41,11 +43,6 @@ public class WebServletAnnotationHandler extends AbstractDiscoverableAnnotationH
super(context);
}
public WebServletAnnotationHandler (WebAppContext context, List<DiscoveredAnnotation> list)
{
super(context, list);
}
/**
* Handle discovering a WebServlet annotation.
@ -54,34 +51,30 @@ public class WebServletAnnotationHandler extends AbstractDiscoverableAnnotationH
* @see org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler#handleClass(java.lang.String, int, int, java.lang.String, java.lang.String, java.lang.String[], java.lang.String, java.util.List)
*/
@Override
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotationName,
List<Value> values)
public void handle(ClassInfo info, String annotationName)
{
if (!"javax.servlet.annotation.WebServlet".equals(annotationName))
if (annotationName == null || !"javax.servlet.annotation.WebServlet".equals(annotationName))
return;
WebServletAnnotation annotation = new WebServletAnnotation (_context, className, _resource);
WebServletAnnotation annotation = new WebServletAnnotation (_context, info.getClassName(), info.getContainingResource());
addAnnotation(annotation);
}
@Override
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
public void handle(FieldInfo info, String annotationName)
{
if (annotationName == null || !"javax.servlet.annotation.WebServlet".equals(annotationName))
return;
LOG.warn ("@WebServlet annotation not supported for fields");
}
@Override
public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation,
List<Value> values)
public void handle(MethodInfo info, String annotationName)
{
if (annotationName == null || !"javax.servlet.annotation.WebServlet".equals(annotationName))
return;
LOG.warn ("@WebServlet annotation not supported for methods");
}
@Override
public String getAnnotationName()
{
return "javax.servlet.annotation.WebServlet";
}
}

View File

@ -24,14 +24,19 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import org.eclipse.jetty.annotations.AnnotationParser.AbstractHandler;
import org.eclipse.jetty.annotations.AnnotationParser.ClassInfo;
import org.eclipse.jetty.annotations.AnnotationParser.FieldInfo;
import org.eclipse.jetty.annotations.AnnotationParser.MethodInfo;
import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.MultiMap;
import org.junit.After;
import org.junit.Test;
@ -44,34 +49,32 @@ public class TestAnnotationInheritance
List<String> classNames = new ArrayList<String>();
class SampleHandler implements DiscoverableAnnotationHandler
class SampleHandler extends AbstractHandler
{
public final List<String> annotatedClassNames = new ArrayList<String>();
public final List<String> annotatedMethods = new ArrayList<String>();
public final List<String> annotatedFields = new ArrayList<String>();
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)
public void handle(ClassInfo info, String annotation)
{
annotatedClassNames.add(className);
if (annotation == null || !"org.eclipse.jetty.annotations.Sample".equals(annotation))
return;
annotatedClassNames.add(info.getClassName());
}
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
public void handle(FieldInfo info, String annotation)
{
annotatedFields.add(className+"."+fieldName);
if (annotation == null || !"org.eclipse.jetty.annotations.Sample".equals(annotation))
return;
annotatedFields.add(info.getClassInfo().getClassName()+"."+info.getFieldName());
}
public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation,
List<Value> values)
public void handle(MethodInfo info, String annotation)
{
annotatedMethods.add(className+"."+methodName);
}
@Override
public String getAnnotationName()
{
return "org.eclipse.jetty.annotations.Sample";
if (annotation == null || !"org.eclipse.jetty.annotations.Sample".equals(annotation))
return;
annotatedMethods.add(info.getClassInfo().getClassName()+"."+info.getMethodName());
}
}
@ -92,8 +95,7 @@ public class TestAnnotationInheritance
SampleHandler handler = new SampleHandler();
AnnotationParser parser = new AnnotationParser();
parser.registerHandler(handler);
parser.parse(classNames, new ClassNameResolver ()
parser.parse(Collections.singleton(handler), classNames, new ClassNameResolver ()
{
public boolean isExcluded(String name)
{
@ -129,8 +131,7 @@ public class TestAnnotationInheritance
{
SampleHandler handler = new SampleHandler();
AnnotationParser parser = new AnnotationParser();
parser.registerAnnotationHandler("org.eclipse.jetty.annotations.Sample", handler);
parser.parse(ClassB.class, new ClassNameResolver ()
parser.parse(Collections.singleton(handler), ClassB.class, new ClassNameResolver ()
{
public boolean isExcluded(String name)
{
@ -166,8 +167,7 @@ public class TestAnnotationInheritance
{
AnnotationParser parser = new AnnotationParser();
SampleHandler handler = new SampleHandler();
parser.registerAnnotationHandler("org.eclipse.jetty.annotations.Sample", handler);
parser.parse(ClassA.class.getName(), new ClassNameResolver()
parser.parse(Collections.singleton(handler), ClassA.class.getName(), new ClassNameResolver()
{
public boolean isExcluded(String name)
{
@ -187,7 +187,7 @@ public class TestAnnotationInheritance
handler.annotatedFields.clear();
handler.annotatedMethods.clear();
parser.parse (ClassA.class.getName(), new ClassNameResolver()
parser.parse (Collections.singleton(handler), ClassA.class.getName(), new ClassNameResolver()
{
public boolean isExcluded(String name)
{
@ -205,9 +205,10 @@ public class TestAnnotationInheritance
@Test
public void testTypeInheritanceHandling() throws Exception
{
ConcurrentHashMap<String, ConcurrentHashSet<String>> map = new ConcurrentHashMap<String, ConcurrentHashSet<String>>();
AnnotationParser parser = new AnnotationParser();
ClassInheritanceHandler handler = new ClassInheritanceHandler();
parser.registerClassHandler(handler);
ClassInheritanceHandler handler = new ClassInheritanceHandler(map);
class Foo implements InterfaceD
{
@ -219,22 +220,22 @@ public class TestAnnotationInheritance
classNames.add(InterfaceD.class.getName());
classNames.add(Foo.class.getName());
parser.parse(classNames, null);
parser.parse(Collections.singleton(handler), classNames, null);
MultiMap map = handler.getMap();
assertNotNull(map);
assertFalse(map.isEmpty());
assertEquals(2, map.size());
Map stringArrayMap = map.toStringArrayMap();
assertTrue (stringArrayMap.keySet().contains("org.eclipse.jetty.annotations.ClassA"));
assertTrue (stringArrayMap.keySet().contains("org.eclipse.jetty.annotations.InterfaceD"));
String[] classes = (String[])stringArrayMap.get("org.eclipse.jetty.annotations.ClassA");
assertEquals(1, classes.length);
assertEquals ("org.eclipse.jetty.annotations.ClassB", classes[0]);
classes = (String[])stringArrayMap.get("org.eclipse.jetty.annotations.InterfaceD");
assertEquals(2, classes.length);
assertEquals ("org.eclipse.jetty.annotations.ClassB", classes[0]);
assertEquals(Foo.class.getName(), classes[1]);
assertTrue (map.keySet().contains("org.eclipse.jetty.annotations.ClassA"));
assertTrue (map.keySet().contains("org.eclipse.jetty.annotations.InterfaceD"));
ConcurrentHashSet<String> classes = map.get("org.eclipse.jetty.annotations.ClassA");
assertEquals(1, classes.size());
assertEquals ("org.eclipse.jetty.annotations.ClassB", classes.iterator().next());
classes = map.get("org.eclipse.jetty.annotations.InterfaceD");
assertEquals(2, classes.size());
assertTrue(classes.contains("org.eclipse.jetty.annotations.ClassB"));
assertTrue(classes.contains(Foo.class.getName()));
}
}

View File

@ -18,8 +18,11 @@
package org.eclipse.jetty.annotations;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.FileOutputStream;
@ -28,24 +31,26 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import org.eclipse.jetty.annotations.AnnotationParser.ClassInfo;
import org.eclipse.jetty.annotations.AnnotationParser.FieldInfo;
import org.eclipse.jetty.annotations.AnnotationParser.Handler;
import org.eclipse.jetty.annotations.AnnotationParser.MethodInfo;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.IO;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.TestingDir;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Rule;
import org.junit.Test;
public class TestAnnotationParser
{
public static class TrackingAnnotationHandler implements DiscoverableAnnotationHandler
public static class TrackingAnnotationHandler extends AnnotationParser.AbstractHandler
{
private final String annotationName;
public final Set<String> foundClasses;
@ -57,30 +62,11 @@ public class TestAnnotationParser
}
@Override
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)
public void handle(ClassInfo info, String annotation)
{
foundClasses.add(className);
}
@Override
public void handleMethod(String className, String methodName, int access, String desc, String signature, String[] exceptions, String annotation,
List<Value> values)
{
/* ignore */
}
@Override
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
{
/* ignore */
}
@Override
public String getAnnotationName()
{
return this.annotationName;
if (annotation == null || !annotationName.equals(annotation))
return;
foundClasses.add(info.getClassName());
}
}
@ -94,47 +80,38 @@ public class TestAnnotationParser
{ "org.eclipse.jetty.annotations.ClassA" };
AnnotationParser parser = new AnnotationParser();
class SampleAnnotationHandler implements DiscoverableAnnotationHandler
class SampleAnnotationHandler extends AnnotationParser.AbstractHandler
{
private List<String> methods = Arrays.asList("a","b","c","d","l");
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)
public void handle(ClassInfo info, String annotation)
{
assertEquals("org.eclipse.jetty.annotations.ClassA",className);
if (annotation == null || !"org.eclipse.jetty.annotations.Sample".equals(annotation))
return;
assertEquals("org.eclipse.jetty.annotations.ClassA",info.getClassName());
}
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
public void handle(FieldInfo info, String annotation)
{
assertEquals("m",fieldName);
assertEquals(org.objectweb.asm.Type.OBJECT,org.objectweb.asm.Type.getType(fieldType).getSort());
assertEquals(1,values.size());
Value anv1 = values.get(0);
assertEquals("value",anv1.getName());
assertEquals(7,anv1.getValue());
if (annotation == null || !"org.eclipse.jetty.annotations.Sample".equals(annotation))
return;
assertEquals("m",info.getFieldName());
assertEquals(org.objectweb.asm.Type.OBJECT,org.objectweb.asm.Type.getType(info.getFieldType()).getSort());
}
public void handleMethod(String className, String methodName, int access, String desc, String signature, String[] exceptions, String annotation,
List<Value> values)
public void handle(MethodInfo info, String annotation)
{
assertEquals("org.eclipse.jetty.annotations.ClassA",className);
assertTrue(methods.contains(methodName));
if (annotation == null || !"org.eclipse.jetty.annotations.Sample".equals(annotation))
return;
assertEquals("org.eclipse.jetty.annotations.ClassA",info.getClassInfo().getClassName());
assertTrue(methods.contains(info.getMethodName()));
assertEquals("org.eclipse.jetty.annotations.Sample",annotation);
}
@Override
public String getAnnotationName()
{
return "org.eclipse.jetty.annotations.Sample";
}
}
parser.registerHandler(new SampleAnnotationHandler());
//long start = System.currentTimeMillis();
parser.parse(classNames,new ClassNameResolver()
parser.parse(Collections.singleton(new SampleAnnotationHandler()), classNames,new ClassNameResolver()
{
public boolean isExcluded(String name)
{
@ -159,38 +136,33 @@ public class TestAnnotationParser
{ "org.eclipse.jetty.annotations.ClassB" };
AnnotationParser parser = new AnnotationParser();
class MultiAnnotationHandler implements DiscoverableAnnotationHandler
class MultiAnnotationHandler extends AnnotationParser.AbstractHandler
{
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
List<Value> values)
public void handle(ClassInfo info, String annotation)
{
assertTrue("org.eclipse.jetty.annotations.ClassB".equals(className));
if (annotation == null || ! "org.eclipse.jetty.annotations.Multi".equals(annotation))
return;
assertTrue("org.eclipse.jetty.annotations.ClassB".equals(info.getClassName()));
}
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
public void handle(FieldInfo info, String annotation)
{
if (annotation == null || ! "org.eclipse.jetty.annotations.Multi".equals(annotation))
return;
// there should not be any
fail();
}
public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation,
List<Value> values)
public void handle(MethodInfo info, String annotation)
{
assertTrue("org.eclipse.jetty.annotations.ClassB".equals(className));
assertTrue("a".equals(methodName));
if (annotation == null || ! "org.eclipse.jetty.annotations.Multi".equals(annotation))
return;
assertTrue("org.eclipse.jetty.annotations.ClassB".equals(info.getClassInfo().getClassName()));
assertTrue("a".equals(info.getMethodName()));
}
@Override
public String getAnnotationName()
{
return "org.eclipse.jetty.annotations.Multi";
}
}
parser.registerHandler(new MultiAnnotationHandler());
parser.parse(classNames,null);
parser.parse(Collections.singleton(new MultiAnnotationHandler()), classNames,null);
}
@Test
@ -198,7 +170,8 @@ public class TestAnnotationParser
{
File badClassesJar = MavenTestingUtils.getTestResourceFile("bad-classes.jar");
AnnotationParser parser = new AnnotationParser();
parser.parse(badClassesJar.toURI(),null);
Set<Handler> emptySet = Collections.emptySet();
parser.parse(emptySet, badClassesJar.toURI(),null);
// only the valid classes inside bad-classes.jar should be parsed. If any invalid classes are parsed and exception would be thrown here
}
@ -221,10 +194,9 @@ public class TestAnnotationParser
// Setup annotation scanning
AnnotationParser parser = new AnnotationParser();
parser.registerHandler(tracker);
// Parse
parser.parse(basedir.toURI(),null);
parser.parse(Collections.singleton(tracker), basedir.toURI(),null);
// Validate
Assert.assertThat("Found Class", tracker.foundClasses, contains(ClassA.class.getName()));

View File

@ -25,12 +25,14 @@ import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.ServletMapping;
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.Test;
@ -41,6 +43,27 @@ import org.junit.Test;
*/
public class TestServletAnnotations
{
public class TestWebServletAnnotationHandler extends WebServletAnnotationHandler
{
List<DiscoveredAnnotation> _list = null;
public TestWebServletAnnotationHandler(WebAppContext context, List<DiscoveredAnnotation> list)
{
super(context);
_list = list;
}
@Override
public void addAnnotation(DiscoveredAnnotation a)
{
super.addAnnotation(a);
_list.add(a);
}
}
@Test
public void testServletAnnotation() throws Exception
{
@ -49,10 +72,11 @@ public class TestServletAnnotations
AnnotationParser parser = new AnnotationParser();
WebAppContext wac = new WebAppContext();
WebServletAnnotationHandler handler = new WebServletAnnotationHandler(wac);
parser.registerAnnotationHandler("javax.servlet.annotation.WebServlet", handler);
List<DiscoveredAnnotation> results = new ArrayList<DiscoveredAnnotation>();
parser.parse(classes, new ClassNameResolver ()
TestWebServletAnnotationHandler handler = new TestWebServletAnnotationHandler(wac, results);
parser.parse(Collections.singleton(handler), classes, new ClassNameResolver ()
{
public boolean isExcluded(String name)
{
@ -65,10 +89,11 @@ public class TestServletAnnotations
}
});
assertEquals(1, handler.getAnnotationList().size());
assertTrue(handler.getAnnotationList().get(0) instanceof WebServletAnnotation);
handler.getAnnotationList().get(0).apply();
assertEquals(1, results.size());
assertTrue(results.get(0) instanceof WebServletAnnotation);
results.get(0).apply();
ServletHolder[] holders = wac.getServletHandler().getServlets();
assertNotNull(holders);

View File

@ -27,7 +27,7 @@ public class HttpClientTransportOverHTTP extends AbstractHttpClientTransport
{
public HttpClientTransportOverHTTP()
{
this(1);
this(Runtime.getRuntime().availableProcessors());
}
public HttpClientTransportOverHTTP(int selectors)

View File

@ -69,7 +69,7 @@ public class SslBytesClientTest extends SslBytesTest
client.start();
SSLContext sslContext = sslContextFactory.getSslContext();
acceptor = (SSLServerSocket)sslContext.getServerSocketFactory().createServerSocket(43191);
acceptor = (SSLServerSocket)sslContext.getServerSocketFactory().createServerSocket(0);
int serverPort = acceptor.getLocalPort();

View File

@ -399,8 +399,8 @@
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeGroupIds>javax.annotation,org.eclipse.jetty.orbit</includeGroupIds>
<includeArtifactIds>javax.annotation-api,org.objectweb.asm</includeArtifactIds>
<includeGroupIds>javax.annotation,org.eclipse.jetty.orbit,org.ow2.asm</includeGroupIds>
<includeArtifactIds>javax.annotation-api,asm,asm-commons</includeArtifactIds>
<includeTypes>jar</includeTypes>
<outputDirectory>${assembly-directory}/lib/annotations</outputDirectory>
</configuration>
@ -439,12 +439,25 @@
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeGroupIds>org.eclipse.jetty.orbit,org.glassfish.web, org.glassfish, javax.el, javax.servlet.jsp</includeGroupIds>
<includeArtifactIds>javax.servlet.jsp.jstl,org.apache.taglibs.standard.glassfish,org.eclipse.jdt.core, javax.servlet.jsp-api, javax.servlet.jsp, javax.el-api, javax.el</includeArtifactIds>
<includeGroupIds>org.eclipse.jetty.orbit,org.glassfish.web, org.glassfish, javax.el, javax.servlet.jsp, org.eclipse.jetty.toolchain</includeGroupIds>
<includeArtifactIds>javax.servlet.jsp.jstl,org.apache.taglibs.standard.glassfish,org.eclipse.jdt.core, javax.servlet.jsp-api, javax.servlet.jsp, jetty-jsp-jdt, javax.el-api, javax.el</includeArtifactIds>
<includeTypes>jar</includeTypes>
<outputDirectory>${assembly-directory}/lib/jsp</outputDirectory>
</configuration>
</execution>
<execution>
<id>copy-jaspi-deps</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeGroupIds>org.eclipse.jetty.orbit</includeGroupIds>
<includeArtifactIds>javax.security.auth.message</includeArtifactIds>
<includeTypes>jar</includeTypes>
<outputDirectory>${assembly-directory}/lib/jaspi</outputDirectory>
</configuration>
</execution>
<execution>
<id>unpack-config-deps</id>
<phase>generate-resources</phase>
@ -489,6 +502,7 @@
<arguments>
<argument>jetty.home=${assembly-directory}</argument>
<argument>jetty.base=${assembly-directory}/demo-base</argument>
<argument>--add-to-start=server,deploy,jsp,ext,resources,client,annotations,jndi</argument>
<argument>--add-to-startd-ini=http,https</argument>
</arguments>
</configuration>
@ -541,10 +555,6 @@
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.orbit</groupId>
<artifactId>org.objectweb.asm</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.orbit</groupId>
<artifactId>javax.activation</artifactId>
@ -570,6 +580,10 @@
<groupId>org.glassfish.web</groupId>
<artifactId>javax.servlet.jsp</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-jsp-jdt</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
@ -579,6 +593,15 @@
<artifactId>javax.el</artifactId>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-commons</artifactId>
</dependency>
<!-- jetty deps -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
@ -704,5 +727,10 @@
<version>${project.version}</version>
<type>war</type>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jaspi</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -1,9 +0,0 @@
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
org.eclipse.jetty.LEVEL=INFO
org.eclipse.jetty.STACKS=true
org.eclipse.jetty.SOURCE=false
#org.eclipse.jetty.STACKS=false
#org.eclipse.jetty.spdy.LEVEL=DEBUG
#org.eclipse.jetty.server.LEVEL=DEBUG
#org.eclipse.jetty.io.ssl.LEVEL=DEBUG
#org.eclipse.jetty.spdy.server.LEVEL=DEBUG

View File

@ -57,7 +57,7 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.spi.JettyExchange#getRequestHeaders()
* @see JettyHttpExchangeDelegate#getRequestHeaders()
*/
@Override
public Headers getRequestHeaders()
@ -67,7 +67,7 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.spi.JettyExchange#getResponseHeaders()
* @see JettyHttpExchangeDelegate#getResponseHeaders()
*/
@Override
public Headers getResponseHeaders()
@ -77,7 +77,7 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.spi.JettyExchange#getRequestURI()
* @see JettyHttpExchangeDelegate#getRequestURI()
*/
@Override
public URI getRequestURI()
@ -87,7 +87,7 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.spi.JettyExchange#getRequestMethod()
* @see JettyHttpExchangeDelegate#getRequestMethod()
*/
@Override
public String getRequestMethod()
@ -97,7 +97,7 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.spi.JettyExchange#getHttpContext()
* @see JettyHttpExchangeDelegate#getHttpContext()
*/
@Override
public HttpContext getHttpContext()
@ -107,7 +107,7 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.spi.JettyExchange#close()
* @see JettyHttpExchangeDelegate#close()
*/
@Override
public void close()
@ -127,7 +127,7 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.spi.JettyExchange#getRequestBody()
* @see JettyHttpExchangeDelegate#getRequestBody()
*/
@Override
public InputStream getRequestBody()
@ -137,7 +137,7 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.spi.JettyExchange#getResponseBody()
* @see JettyHttpExchangeDelegate#getResponseBody()
*/
@Override
public OutputStream getResponseBody()
@ -147,7 +147,7 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.spi.JettyExchange#sendResponseHeaders(int, long)
* @see JettyHttpExchangeDelegate#sendResponseHeaders(int, long)
*/
@Override
public void sendResponseHeaders(int rCode, long responseLength) throws IOException
@ -157,7 +157,7 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.spi.JettyExchange#getRemoteAddress()
* @see JettyHttpExchangeDelegate#getRemoteAddress()
*/
@Override
public InetSocketAddress getRemoteAddress()
@ -167,7 +167,7 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.spi.JettyExchange#getResponseCode()
* @see JettyHttpExchangeDelegate#getResponseCode()
*/
@Override
public int getResponseCode()
@ -177,7 +177,7 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.spi.JettyExchange#getLocalAddress()
* @see JettyHttpExchangeDelegate#getLocalAddress()
*/
@Override
public InetSocketAddress getLocalAddress()
@ -187,7 +187,7 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.spi.JettyExchange#getProtocol()
* @see JettyHttpExchangeDelegate#getProtocol()
*/
@Override
public String getProtocol()
@ -197,7 +197,7 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.spi.JettyExchange#getAttribute(java.lang.String)
* @see JettyHttpExchangeDelegate#getAttribute(java.lang.String)
*/
@Override
public Object getAttribute(String name)
@ -207,7 +207,7 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.spi.JettyExchange#setAttribute(java.lang.String, java.lang.Object)
* @see JettyHttpExchangeDelegate#setAttribute(java.lang.String, java.lang.Object)
*/
@Override
public void setAttribute(String name, Object value)
@ -217,7 +217,7 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.spi.JettyExchange#setStreams(java.io.InputStream, java.io.OutputStream)
* @see JettyHttpExchangeDelegate#setStreams(java.io.InputStream, java.io.OutputStream)
*/
@Override
public void setStreams(InputStream i, OutputStream o)

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.http;
import java.nio.ByteBuffer;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
import org.eclipse.jetty.util.ArrayTrie;
import org.eclipse.jetty.util.BufferUtil;
@ -101,6 +102,7 @@ public class HttpField
CACHE.put(new HttpField(HttpHeader.COOKIE,(String)null));
}
private final static Pattern __splitter = Pattern.compile("\\s*,\\s*");
private final static byte[] __colon_space = new byte[] {':',' '};
private final HttpHeader _header;
@ -153,10 +155,10 @@ public class HttpField
if (value.equalsIgnoreCase(_value))
return true;
String[] split = _value.split("\\s*,\\s*");
for (String s : split)
String[] split = __splitter.split(_value);
for (int i = 0; split!=null && i < split.length; i++)
{
if (value.equalsIgnoreCase(s))
if (value.equalsIgnoreCase(split[i]))
return true;
}

View File

@ -272,6 +272,12 @@ public class HttpFieldsTest
public void testSetCookie() throws Exception
{
HttpFields fields = new HttpFields();
fields.addSetCookie("null",null,null,null,-1,null,false,false,-1);
assertEquals("null=",fields.getStringField("Set-Cookie"));
fields.clear();
fields.addSetCookie("minimal","value",null,null,-1,null,false,false,-1);
assertEquals("minimal=value",fields.getStringField("Set-Cookie"));

View File

@ -26,11 +26,9 @@ import java.nio.channels.ReadPendingException;
import java.nio.channels.WritePendingException;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.ExecutorCallback;
import org.eclipse.jetty.util.FutureCallback;
/**
*
* A transport EndPoint

View File

@ -232,7 +232,10 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
catch (Exception x)
{
LOG.info("Exception while notifying connection " + connection, x);
if (isRunning())
LOG.warn("Exception while notifying connection " + connection, x);
else
LOG.debug("Exception while notifying connection {}",connection, x);
}
}
@ -421,7 +424,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
String name = _thread.getName();
try
{
_thread.setName(name + "-selector-" + _id);
_thread.setName(name + "-selector-" + SelectorManager.this.getClass().getSimpleName()+"@"+Integer.toHexString(SelectorManager.this.hashCode())+"/"+_id);
LOG.debug("Starting {} on {}", _thread, this);
while (isRunning())
select();

View File

@ -14,6 +14,23 @@
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>config</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>

View File

@ -0,0 +1,9 @@
#
# Jetty JASPI Module
#
[depend]
security
[lib]
lib/jetty-jaspi-${jetty.version}.jar
lib/jaspi/*.jar

View File

@ -45,7 +45,10 @@ import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.eclipse.jetty.jndi.NamingContext;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.junit.Ignore;
@ -78,17 +81,24 @@ public class TestJNDI
public void testThreadContextClassloaderAndCurrentContext()
throws Exception
{
//create a jetty context, and start it so that its classloader it created
//and it is the current context
ClassLoader currentLoader = Thread.currentThread().getContextClassLoader();
ContextHandler ch = new ContextHandler();
URLClassLoader chLoader = new URLClassLoader(new URL[0], currentLoader);
ch.setClassLoader(chLoader);
Server server = new Server();
HandlerList hl = new HandlerList();
server.setHandler(hl);
hl.addHandler(ch);
//Create another one
ContextHandler ch2 = new ContextHandler();
URLClassLoader ch2Loader = new URLClassLoader(new URL[0], currentLoader);
ch2.setClassLoader(ch2Loader);
hl.addHandler(ch2);
try
{

View File

@ -1,5 +1,5 @@
#
# Jetty Servlet Module
# Jetty JSP Module
#
[depend]
@ -8,3 +8,6 @@ servlet
[lib]
lib/jsp/*.jar
[ini-template]
# To use an non-jdk compiler for JSP compilation uncomment next line
#-Dorg.apache.jasper.compiler.disablejsr199=true

View File

@ -709,19 +709,20 @@ public class JettyRunForkedMojo extends AbstractMojo
if (PluginLog.getLog().isDebugEnabled())
PluginLog.getLog().debug(Arrays.toString(cmd.toArray()));
forkedProcess = builder.start();
PluginLog.getLog().info("Forked process starting");
if (waitForChild)
{
forkedProcess = builder.start();
startPump("STDOUT",forkedProcess.getInputStream());
startPump("STDERR",forkedProcess.getErrorStream());
int exitcode = forkedProcess.waitFor();
PluginLog.getLog().info("Forked execution exit: "+exitcode);
}
else
{ //we're not going to be reading the stderr as we're not waiting for the child to finish
forkedProcess.getErrorStream().close();
{ //merge stderr and stdout from child
builder.redirectErrorStream(true);
forkedProcess = builder.start();
//wait for the child to be ready before terminating.
//child indicates it has finished starting by printing on stdout the token passed to it
@ -754,6 +755,7 @@ public class JettyRunForkedMojo extends AbstractMojo
{
throw new MojoExecutionException ("Problem determining if forked process is ready: "+e.getMessage());
}
}
}
catch (InterruptedException ex)

View File

@ -174,7 +174,7 @@ public class JettyRunMojo extends AbstractJettyMojo
/**
* Verify the configuration given in the pom.
*
* @see org.mortbay.jetty.plugin.AbstractJettyMojo#checkPomConfiguration()
* @see AbstractJettyMojo#checkPomConfiguration()
*/
public void checkPomConfiguration () throws MojoExecutionException
{

View File

@ -78,7 +78,7 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
/**
*
* @see org.mortbay.jetty.plugin.AbstractJettyMojo#checkPomConfiguration()
* @see AbstractJettyMojo#checkPomConfiguration()
*/
public void checkPomConfiguration() throws MojoExecutionException
{
@ -89,7 +89,7 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
/**
* @see org.mortbay.jetty.plugin.AbstractJettyMojo#configureScanner()
* @see AbstractJettyMojo#configureScanner()
*/
public void configureScanner() throws MojoExecutionException
{

View File

@ -83,7 +83,7 @@ public class JettyRunWarMojo extends AbstractJettyMojo
/**
* @see org.mortbay.jetty.plugin.AbstractJettyMojo#checkPomConfiguration()
* @see AbstractJettyMojo#checkPomConfiguration()
*/
public void checkPomConfiguration() throws MojoExecutionException
{
@ -94,7 +94,7 @@ public class JettyRunWarMojo extends AbstractJettyMojo
/**
* @see org.eclipse.jetty.server.plugin.AbstractJettyMojo#configureScanner()
* @see AbstractJettyMojo#configureScanner()
*/
public void configureScanner() throws MojoExecutionException
{

View File

@ -47,7 +47,6 @@ import org.eclipse.jetty.webapp.MetaInfConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.eclipse.jetty.webapp.WebXmlConfiguration;
import org.eclipse.jetty.websocket.jsr356.server.WebSocketConfiguration;
/**
* JettyWebAppContext
@ -112,7 +111,6 @@ public class JettyWebAppContext extends WebAppContext
new FragmentConfiguration(),
_envConfig = new EnvConfiguration(),
new PlusConfiguration(),
new WebSocketConfiguration(),
new MavenAnnotationConfiguration(),
new JettyWebXmlConfiguration()
});

View File

@ -19,11 +19,12 @@
package org.eclipse.jetty.maven.plugin;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jetty.annotations.AbstractDiscoverableAnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.annotations.AnnotationParser;
import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.Handler;
import org.eclipse.jetty.annotations.ClassNameResolver;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -51,15 +52,11 @@ public class MavenAnnotationConfiguration extends AnnotationConfiguration
if (metaData == null)
throw new IllegalStateException ("No metadata");
parser.clearHandlers();
for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
{
if (h instanceof AbstractDiscoverableAnnotationHandler)
((AbstractDiscoverableAnnotationHandler)h).setResource(null); //
}
parser.registerHandlers(_discoverableAnnotationHandlers);
parser.registerHandler(_classInheritanceHandler);
parser.registerHandlers(_containerInitializerAnnotationHandlers);
Set<Handler> handlers = new HashSet<Handler>();
handlers.addAll(_discoverableAnnotationHandlers);
if (_classInheritanceHandler != null)
handlers.add(_classInheritanceHandler);
handlers.addAll(_containerInitializerAnnotationHandlers);
for (File f:jwac.getClassPathFiles())
@ -67,7 +64,7 @@ public class MavenAnnotationConfiguration extends AnnotationConfiguration
//scan the equivalent of the WEB-INF/classes directory that has been synthesised by the plugin
if (f.isDirectory() && f.exists())
{
doParse(context, parser, Resource.newResource(f.toURI()));
doParse(handlers, context, parser, Resource.newResource(f.toURI()));
}
}
@ -78,32 +75,19 @@ public class MavenAnnotationConfiguration extends AnnotationConfiguration
Resource classesDir = context.getWebInf().addPath("classes/");
if (classesDir.exists())
{
doParse(context, parser, classesDir);
doParse(handlers, context, parser, classesDir);
}
}
}
}
public void doParse (final WebAppContext context, final AnnotationParser parser, Resource resource)
public void doParse (final Set<? extends Handler> handlers, final WebAppContext context, final AnnotationParser parser, Resource resource)
throws Exception
{
parser.parseDir(resource, new ClassNameResolver()
{
public boolean isExcluded (String name)
{
if (context.isSystemClass(name)) return true;
if (context.isServerClass(name)) return false;
return false;
}
public boolean shouldOverride (String name)
{
//looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp?
if (context.isParentLoaderPriority())
return false;
return true;
}
});
if (_parserTasks != null)
_parserTasks.add(new ParserTask(parser, handlers, resource, _webAppClassNameResolver));
else
parser.parse(handlers, resource, _webAppClassNameResolver);
}
}

View File

@ -18,16 +18,14 @@
package org.eclipse.jetty.osgi.annotations;
import java.util.ArrayList;
import java.util.List;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jetty.annotations.AbstractDiscoverableAnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.Handler;
import org.eclipse.jetty.annotations.ClassNameResolver;
import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
import org.eclipse.jetty.webapp.WebAppContext;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
@ -39,6 +37,26 @@ import org.osgi.framework.Constants;
*/
public class AnnotationConfiguration extends org.eclipse.jetty.annotations.AnnotationConfiguration
{
public class BundleParserTask extends ParserTask
{
public BundleParserTask (AnnotationParser parser, Set<? extends Handler>handlers, Resource resource, ClassNameResolver resolver)
{
super(parser, handlers, resource, resolver);
}
public Void call() throws Exception
{
if (_parser != null)
{
org.eclipse.jetty.osgi.annotations.AnnotationParser osgiAnnotationParser = (org.eclipse.jetty.osgi.annotations.AnnotationParser)_parser;
Bundle bundle = osgiAnnotationParser.getBundle(_resource);
osgiAnnotationParser.parse(_handlers, bundle, _resolver);
}
return null;
}
}
/**
* This parser scans the bundles using the OSGi APIs instead of assuming a jar.
@ -69,7 +87,7 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot
Bundle[] fragAndRequiredBundles = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles(webbundle);
if (fragAndRequiredBundles != null)
{
//index:
//index and scan fragments
for (Bundle bundle : fragAndRequiredBundles)
{
Resource bundleRes = oparser.indexBundle(bundle);
@ -77,19 +95,16 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot
{
context.getMetaData().addWebInfJar(bundleRes);
}
}
//scan the fragments
for (Bundle fragmentBundle : fragAndRequiredBundles)
{
if (fragmentBundle.getHeaders().get(Constants.FRAGMENT_HOST) != null)
if (bundle.getHeaders().get(Constants.FRAGMENT_HOST) != null)
{
//a fragment indeed:
parseFragmentBundle(context,oparser,webbundle,fragmentBundle);
parseFragmentBundle(context,oparser,webbundle,bundle);
}
}
}
//scan ourselves
oparser.indexBundle(webbundle);
parseWebBundle(context,oparser,webbundle);
//scan the WEB-INF/lib
@ -151,27 +166,21 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot
}
protected void parseBundle(WebAppContext context, AnnotationParser parser,
Bundle webbundle, Bundle bundle) throws Exception
{
Bundle webbundle, Bundle bundle) throws Exception
{
Resource bundleRes = parser.getResource(bundle);
Set<Handler> handlers = new HashSet<Handler>();
handlers.addAll(_discoverableAnnotationHandlers);
if (_classInheritanceHandler != null)
handlers.add(_classInheritanceHandler);
handlers.addAll(_containerInitializerAnnotationHandlers);
parser.clearHandlers();
for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
{
if (h instanceof AbstractDiscoverableAnnotationHandler)
{
if (webbundle == bundle)
((AbstractDiscoverableAnnotationHandler)h).setResource(null);
else
((AbstractDiscoverableAnnotationHandler)h).setResource(bundleRes);
}
}
parser.registerHandlers(_discoverableAnnotationHandlers);
parser.registerHandler(_classInheritanceHandler);
parser.registerHandlers(_containerInitializerAnnotationHandlers);
parser.parse(bundle,createClassNameResolver(context));
ClassNameResolver classNameResolver = createClassNameResolver(context);
if (_parserTasks != null)
_parserTasks.add(new BundleParserTask(parser, handlers, bundleRes, classNameResolver));
else
parser.parse(handlers, bundle, classNameResolver);
}
/**

View File

@ -29,9 +29,11 @@ import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jetty.annotations.ClassNameResolver;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.resource.Resource;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
@ -41,11 +43,12 @@ import org.osgi.framework.Constants;
*/
public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationParser
{
private Set<URI> _alreadyParsed = new HashSet<URI>();
private Set<URI> _alreadyParsed = new ConcurrentHashSet<URI>();
private Map<URI,Bundle> _uriToBundle = new HashMap<URI, Bundle>();
private Map<Bundle,Resource> _resourceToBundle = new HashMap<Bundle,Resource>();
private Map<Bundle,URI> _bundleToUri = new HashMap<Bundle, URI>();
private ConcurrentHashMap<URI,Bundle> _uriToBundle = new ConcurrentHashMap<URI, Bundle>();
private ConcurrentHashMap<Bundle,Resource> _bundleToResource = new ConcurrentHashMap<Bundle,Resource>();
private ConcurrentHashMap<Resource, Bundle> _resourceToBundle = new ConcurrentHashMap<Resource, Bundle>();
private ConcurrentHashMap<Bundle,URI> _bundleToUri = new ConcurrentHashMap<Bundle, URI>();
/**
* Keep track of a jetty URI Resource and its associated OSGi bundle.
@ -58,9 +61,10 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa
File bundleFile = BundleFileLocatorHelper.DEFAULT.getBundleInstallLocation(bundle);
Resource resource = Resource.newResource(bundleFile.toURI());
URI uri = resource.getURI();
_uriToBundle.put(uri,bundle);
_bundleToUri.put(bundle,uri);
_resourceToBundle.put(bundle,resource);
_uriToBundle.putIfAbsent(uri,bundle);
_bundleToUri.putIfAbsent(bundle,uri);
_bundleToResource.putIfAbsent(bundle,resource);
_resourceToBundle.putIfAbsent(resource,bundle);
return resource;
}
protected URI getURI(Bundle bundle)
@ -69,13 +73,19 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa
}
protected Resource getResource(Bundle bundle)
{
return _resourceToBundle.get(bundle);
return _bundleToResource.get(bundle);
}
protected Bundle getBundle (Resource resource)
{
return _resourceToBundle.get(resource);
}
/**
*
*/
@Override
public void parse (URI[] uris, ClassNameResolver resolver)
public void parse (Set<? extends Handler> handlers, URI[] uris, ClassNameResolver resolver)
throws Exception
{
for (URI uri : uris)
@ -89,16 +99,16 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa
}
//a jar in WEB-INF/lib or the WEB-INF/classes
//use the behavior of the super class for a standard jar.
super.parse(new URI[] {uri},resolver);
super.parse(handlers, new URI[] {uri},resolver);
}
else
{
parse(associatedBundle,resolver);
parse(handlers, associatedBundle,resolver);
}
}
}
protected void parse(Bundle bundle, ClassNameResolver resolver)
protected void parse(Set<? extends Handler> handlers, Bundle bundle, ClassNameResolver resolver)
throws Exception
{
URI uri = _bundleToUri.get(bundle);
@ -190,7 +200,7 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa
//transform into a classname to pass to the resolver
String shortName = name.replace('/', '.').substring(0,name.length()-6);
if ((resolver == null)|| (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
scanClass(classUrl.openStream());
scanClass(handlers, getResource(bundle), classUrl.openStream());
}
}

View File

@ -21,7 +21,11 @@ package org.eclipse.jetty.osgi.boot;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
@ -53,8 +57,8 @@ public class OSGiMetaInfConfiguration extends MetaInfConfiguration
@Override
public void preConfigure(final WebAppContext context) throws Exception
{
List<Resource> frags = (List<Resource>) context.getAttribute(METAINF_FRAGMENTS);
List<Resource> resfrags = (List<Resource>) context.getAttribute(METAINF_RESOURCES);
Map<Resource, Resource> frags = (Map<Resource, Resource>) context.getAttribute(METAINF_FRAGMENTS);
Set<Resource> resfrags = (Set<Resource>) context.getAttribute(METAINF_RESOURCES);
List<Resource> tldfrags = (List<Resource>) context.getAttribute(METAINF_TLDS);
Bundle[] fragments = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles((Bundle)context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE));
@ -73,10 +77,11 @@ public class OSGiMetaInfConfiguration extends MetaInfConfiguration
{
if (frags == null)
{
frags = new ArrayList<Resource>();
frags = new HashMap<Resource,Resource>();
context.setAttribute(METAINF_FRAGMENTS, frags);
}
frags.add(Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(frag).toURI()));
frags.put(Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(frag).toURI()),
Resource.newResource(webFrag));
}
if (resEnum != null && resEnum.hasMoreElements())
{
@ -92,7 +97,7 @@ public class OSGiMetaInfConfiguration extends MetaInfConfiguration
{
if (resfrags == null)
{
resfrags = new ArrayList<Resource>();
resfrags = new HashSet<Resource>();
context.setAttribute(METAINF_RESOURCES, resfrags);
}
resfrags.add(Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(resourcesEntry)));

View File

@ -212,7 +212,7 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration
}
}
if (!appendedResourcesPath.isEmpty())
context.setAttribute(WebInfConfiguration.RESOURCE_URLS, new ArrayList<Resource>(appendedResourcesPath.values()));
context.setAttribute(WebInfConfiguration.RESOURCE_DIRS, new HashSet<Resource>(appendedResourcesPath.values()));
}
}

View File

@ -172,7 +172,7 @@
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-jsp-fragment</artifactId>
<version>2.3.2</version>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<dependency>

View File

@ -18,26 +18,33 @@
package org.eclipse.jetty.plus.annotation;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContextListener;
import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.webapp.WebAppContext;
public class ContainerInitializer
{
protected ServletContainerInitializer _target;
protected Class[] _interestedTypes;
protected Set<String> _applicableTypeNames;
protected Set<String> _annotatedTypeNames;
private static final Logger LOG = Log.getLogger(ContainerInitializer.class);
final protected ServletContainerInitializer _target;
final protected Class[] _interestedTypes;
protected Set<String> _applicableTypeNames = new ConcurrentHashSet<String>();
protected Set<String> _annotatedTypeNames = new ConcurrentHashSet<String>();
public void setTarget (ServletContainerInitializer target)
public ContainerInitializer (ServletContainerInitializer target, Class[] classes)
{
_target = target;
_interestedTypes = classes;
}
public ServletContainerInitializer getTarget ()
@ -50,10 +57,6 @@ public class ContainerInitializer
return _interestedTypes;
}
public void setInterestedTypes (Class[] interestedTypes)
{
_interestedTypes = interestedTypes;
}
/**
* A class has been found that has an annotation of interest
@ -62,26 +65,22 @@ public class ContainerInitializer
*/
public void addAnnotatedTypeName (String className)
{
if (_annotatedTypeNames == null)
_annotatedTypeNames = new HashSet<String>();
_annotatedTypeNames.add(className);
}
public Set<String> getAnnotatedTypeNames ()
{
return _annotatedTypeNames;
return Collections.unmodifiableSet(_annotatedTypeNames);
}
public void addApplicableTypeName (String className)
{
if (_applicableTypeNames == null)
_applicableTypeNames = new HashSet<String>();
_applicableTypeNames.add(className);
}
public Set<String> getApplicableTypeNames ()
{
return _applicableTypeNames;
return Collections.unmodifiableSet(_applicableTypeNames);
}
@ -97,13 +96,18 @@ public class ContainerInitializer
try
{
if (_applicableTypeNames != null)
{
for (String s : _applicableTypeNames)
classes.add(Loader.loadClass(context.getClass(), s));
}
for (String s : _applicableTypeNames)
classes.add(Loader.loadClass(context.getClass(), s));
context.getServletContext().setExtendedListenerTypes(true);
_target.onStartup(classes, context.getServletContext());
if (LOG.isDebugEnabled())
{
long start = System.nanoTime();
_target.onStartup(classes, context.getServletContext());
LOG.debug("ContainerInitializer {} called in {}ms", _target.getClass().getName(), TimeUnit.MILLISECONDS.convert(System.nanoTime()-start, TimeUnit.NANOSECONDS));
}
else
_target.onStartup(classes, context.getServletContext());
}
finally
{

View File

@ -177,7 +177,7 @@ public class ConnectHandler extends HandlerWrapper
protected SelectorManager newSelectorManager()
{
return new Manager(getExecutor(), getScheduler(), 1);
return new ConnectManager(getExecutor(), getScheduler(), 1);
}
@Override
@ -429,10 +429,10 @@ public class ConnectHandler extends HandlerWrapper
dump(out, indent, getBeans(), TypeUtil.asList(getHandlers()));
}
protected class Manager extends SelectorManager
protected class ConnectManager extends SelectorManager
{
private Manager(Executor executor, Scheduler scheduler, int selectors)
private ConnectManager(Executor executor, Scheduler scheduler, int selectors)
{
super(executor, scheduler, selectors);
}

View File

@ -28,8 +28,10 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.servlet.AsyncContext;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
@ -47,7 +49,6 @@ import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.HttpCookieStore;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -206,7 +207,8 @@ public class ProxyServlet extends HttpServlet
* <tr>
* <td>maxThreads</td>
* <td>256</td>
* <td>The max number of threads of HttpClient's Executor</td>
* <td>The max number of threads of HttpClient's Executor. If not set, or set to the value of "-", then the
* Jetty server thread pool will be used.</td>
* </tr>
* <tr>
* <td>maxConnections</td>
@ -244,21 +246,30 @@ public class ProxyServlet extends HttpServlet
ServletConfig config = getServletConfig();
HttpClient client = newHttpClient();
// Redirects must be proxied as is, not followed
client.setFollowRedirects(false);
// Must not store cookies, otherwise cookies of different clients will mix
client.setCookieStore(new HttpCookieStore.Empty());
Executor executor;
String value = config.getInitParameter("maxThreads");
if (value == null)
value = "256";
QueuedThreadPool executor = new QueuedThreadPool(Integer.parseInt(value));
String servletName = config.getServletName();
int dot = servletName.lastIndexOf('.');
if (dot >= 0)
servletName = servletName.substring(dot + 1);
executor.setName(servletName);
if (value == null || "-".equals(value))
{
executor = (Executor)getServletContext().getAttribute("org.eclipse.jetty.server.Executor");
}
else
{
QueuedThreadPool qtp= new QueuedThreadPool(Integer.parseInt(value));
String servletName = config.getServletName();
int dot = servletName.lastIndexOf('.');
if (dot >= 0)
servletName = servletName.substring(dot + 1);
qtp.setName(servletName);
executor=qtp;
}
client.setExecutor(executor);
value = config.getInitParameter("maxConnections");

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.server;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@ -361,13 +362,13 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
// Complete generating the response
_response.closeOutput();
}
catch(EofException e)
catch(EofException|ClosedChannelException e)
{
LOG.debug(e);
}
catch(Exception e)
{
LOG.warn("handle complete",e);
LOG.warn("complete failed",e);
}
finally
{
@ -762,7 +763,7 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
@Override
public void failed(final Throwable x)
{
if (x instanceof EofException)
if (x instanceof EofException || x instanceof ClosedChannelException)
{
LOG.debug(x);
_callback.failed(x);

View File

@ -51,6 +51,7 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
{
private final static Logger LOG = Log.getLogger(HttpInput.class);
private final byte[] _oneByteBuffer = new byte[1];
private HttpChannelState _channelState;
private Throwable _onError;
private ReadListener _listener;
@ -59,6 +60,7 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
protected State _state = BLOCKING;
private State _eof=null;
private final Object _lock;
private long _contentRead;
protected HttpInput()
{
@ -82,6 +84,7 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
_state = BLOCKING;
_eof=null;
_onError=null;
_contentRead=0;
}
}
@ -118,9 +121,8 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
@Override
public int read() throws IOException
{
byte[] bytes = new byte[1];
int read = read(bytes, 0, 1);
return read < 0 ? -1 : 0xff & bytes[0];
int read = read(_oneByteBuffer, 0, 1);
return read < 0 ? -1 : 0xff & _oneByteBuffer[0];
}
@Override
@ -144,6 +146,7 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
public int read(byte[] b, int off, int len) throws IOException
{
T item = null;
int l;
synchronized (lock())
{
// System.err.printf("read s=%s q=%d e=%s%n",_state,_inputQ.size(),_eof);
@ -159,10 +162,14 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
if (item==null)
return _state.noContent();
}
}
return get(item, b, off, len);
l=get(item, b, off, len);
_contentRead+=l;
}
return l;
}
protected abstract int remaining(T item);
protected abstract int get(T item, byte[] buffer, int offset, int length);
@ -179,14 +186,20 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
return true;
}
/* ------------------------------------------------------------ */
public long getContentRead()
{
synchronized (lock())
{
return _contentRead;
}
}
/** Add some content to the input stream
* @param item
*/
public abstract void content(T item);
/* ------------------------------------------------------------ */
/** This method should be called to signal to the HttpInput
* that an EOF has arrived before all the expected content.
* Typically this will result in an EOFException being thrown
@ -206,7 +219,6 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
}
}
/* ------------------------------------------------------------ */
public void messageComplete()
{
synchronized (lock())
@ -221,7 +233,6 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
}
}
/* ------------------------------------------------------------ */
public void consumeAll()
{
synchronized (lock())
@ -355,7 +366,6 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
}
}
protected static class State
{
public void waitForContent(HttpInput<?> in) throws IOException
@ -432,7 +442,6 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
}
};
public void init(HttpChannelState state)
{
synchronized (lock())

View File

@ -312,6 +312,7 @@ public class LowResourceMonitor extends AbstractLifeCycle
LOG.info("Low Resources cleared");
_reasons=null;
_lowStarted=0;
_cause=null;
clearLowResources();
}
}

View File

@ -526,6 +526,12 @@ public class Request implements HttpServletRequest
return _fields.getLongField(HttpHeader.CONTENT_LENGTH.toString());
}
/* ------------------------------------------------------------ */
public long getContentRead()
{
return _input.getContentRead();
}
/* ------------------------------------------------------------ */
/*
* @see javax.servlet.ServletRequest#getContentType()

View File

@ -54,7 +54,7 @@ public class AllowSymLinkAliasChecker implements AliasCheck
{
// we can use the real path method to check the symlinks resolve to the alias
URI real = file.toPath().toRealPath().toUri();
if (real.equals(resource.getAlias().toURI()))
if (real.equals(resource.getAlias()))
{
LOG.debug("Allow symlink {} --> {}",resource,real);
return true;
@ -77,7 +77,7 @@ public class AllowSymLinkAliasChecker implements AliasCheck
d=link.toFile().getAbsoluteFile().getCanonicalFile();
}
}
if (resource.getAlias().toURI().equals(d.toURI()))
if (resource.getAlias().equals(d.toURI()))
{
LOG.debug("Allow symlink {} --> {}",resource,d);
return true;

View File

@ -22,6 +22,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessController;
@ -96,6 +97,8 @@ import org.eclipse.jetty.util.resource.Resource;
* <p>
* The maximum size of a form that can be processed by this context is controlled by the system properties org.eclipse.jetty.server.Request.maxFormKeys
* and org.eclipse.jetty.server.Request.maxFormContentSize. These can also be configured with {@link #setMaxFormContentSize(int)} and {@link #setMaxFormKeys(int)}
* <p>
* This servers executore is made available via a context attributed "org.eclipse.jetty.server.Executor".
*
* @org.apache.xbean.XBean description="Creates a basic HTTP context"
*/
@ -718,6 +721,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
Thread current_thread = null;
Context old_context = null;
_attributes.setAttribute("org.eclipse.jetty.server.Executor",getServer().getThreadPool());
try
{
// Set the classloader
@ -1653,6 +1658,15 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
return Resource.newResource(url);
}
/* ------------------------------------------------------------ */
/**
* Convert URL to Resource wrapper for {@link Resource#newResource(URL)} enables extensions to provide alternate resource implementations.
*/
public Resource newResource(URI uri) throws IOException
{
return Resource.newResource(uri);
}
/* ------------------------------------------------------------ */
/**
* Convert a URL or path to a Resource. The default implementation is a wrapper for {@link Resource#newResource(String)}.

View File

@ -316,7 +316,7 @@ public class ContextHandlerGetResourceTest
Resource resource=context.getResource(path);
assertNotNull(resource);
assertEquals(context.getResource("/subdir/TextFile.Long.txt").getURL(),resource.getAlias());
assertEquals(context.getResource("/subdir/TextFile.Long.txt").getURI(),resource.getAlias());
URL url=context.getServletContext().getResource(path);
assertNotNull(url);

View File

@ -399,6 +399,7 @@ public class ContextHandlerTest
public void testAttributes() throws Exception
{
ContextHandler handler = new ContextHandler();
handler.setServer(new Server());
handler.setAttribute("aaa","111");
assertEquals("111",handler.getServletContext().getAttribute("aaa"));
assertEquals(null,handler.getAttribute("bbb"));

View File

@ -80,7 +80,7 @@ public class SPDYConnection extends AbstractConnection implements Controller, Id
@Override
public void onFillable()
{
ByteBuffer buffer = bufferPool.acquire(bufferSize, true);
ByteBuffer buffer = bufferPool.acquire(bufferSize, false);
boolean readMore = read(buffer) == 0;
bufferPool.release(buffer);
if (readMore)

View File

@ -533,7 +533,6 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
streamListener = notifyOnSyn(listener, stream, synInfo);
}
stream.setStreamFrameListener(streamListener);
flush();
// The onSyn() listener may have sent a frame that closed the stream
if (stream.isClosed())
removeStream(stream);
@ -698,7 +697,6 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
RstInfo rstInfo = new RstInfo(frame.getStreamId(), StreamStatus.from(frame.getVersion(), frame.getStatusCode()));
notifyOnRst(listener, rstInfo);
flush();
if (stream != null)
removeStream(stream);
@ -722,7 +720,6 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
}
SettingsInfo settingsInfo = new SettingsInfo(frame.getSettings(), frame.isClearPersisted());
notifyOnSettings(listener, settingsInfo);
flush();
}
private void onPing(PingFrame frame)
@ -732,7 +729,6 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{
PingResultInfo pingResultInfo = new PingResultInfo(frame.getPingId());
notifyOnPing(listener, pingResultInfo);
flush();
}
else
{
@ -747,7 +743,6 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
//TODO: Find a better name for GoAwayResultInfo
GoAwayResultInfo goAwayResultInfo = new GoAwayResultInfo(frame.getLastStreamId(), SessionStatus.from(frame.getStatusCode()));
notifyOnGoAway(listener, goAwayResultInfo);
flush();
// SPDY does not require to send back a response to a GO_AWAY.
// We notified the application of the last good stream id and
// tried our best to flush remaining data.
@ -788,7 +783,6 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
private void onCredential(CredentialFrame frame)
{
LOG.warn("{} frame not yet supported", frame.getType());
flush();
}
protected void close()

View File

@ -246,7 +246,6 @@ public class StandardStream extends IdleTimeout implements IStream
throw new IllegalStateException();
}
}
session.flush();
}
@Override
@ -270,7 +269,6 @@ public class StandardStream extends IdleTimeout implements IStream
updateCloseState(dataInfo.isClose(), false);
notifyOnData(dataInfo);
session.flush();
}
@Override

View File

@ -53,7 +53,7 @@ public class CredentialGenerator extends ControlFrameGenerator
int frameBodyLength = 2 + 4 + proof.length + certificates.size() * 4 + certificatesLength;
int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength;
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, true);
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
BufferUtil.clearToFill(buffer);
generateControlFrameHeader(credential, frameBodyLength, buffer);

View File

@ -36,7 +36,7 @@ public class DataFrameGenerator
public ByteBuffer generate(int streamId, int length, DataInfo dataInfo)
{
ByteBuffer buffer = bufferPool.acquire(DataFrame.HEADER_LENGTH + length, true);
ByteBuffer buffer = bufferPool.acquire(DataFrame.HEADER_LENGTH + length, Generator.useDirectBuffers);
BufferUtil.clearToFill(buffer);
buffer.limit(length + DataFrame.HEADER_LENGTH);
buffer.position(DataFrame.HEADER_LENGTH);

View File

@ -29,6 +29,7 @@ import org.eclipse.jetty.spdy.frames.ControlFrameType;
public class Generator
{
final static boolean useDirectBuffers=false;
private final EnumMap<ControlFrameType, ControlFrameGenerator> generators = new EnumMap<>(ControlFrameType.class);
private final DataFrameGenerator dataFrameGenerator;

View File

@ -40,7 +40,7 @@ public class GoAwayGenerator extends ControlFrameGenerator
int frameBodyLength = 8;
int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength;
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, true);
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
BufferUtil.clearToFill(buffer);
generateControlFrameHeader(goAway, frameBodyLength, buffer);

View File

@ -60,7 +60,7 @@ public class HeadersGenerator extends ControlFrameGenerator
int totalLength = ControlFrame.HEADER_LENGTH + frameLength;
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, true);
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
BufferUtil.clearToFill(buffer);
generateControlFrameHeader(headers, frameLength, buffer);

View File

@ -39,7 +39,7 @@ public class NoOpGenerator extends ControlFrameGenerator
int frameBodyLength = 0;
int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength;
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, true);
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
BufferUtil.clearToFill(buffer);
generateControlFrameHeader(noOp, frameBodyLength, buffer);

View File

@ -39,7 +39,7 @@ public class PingGenerator extends ControlFrameGenerator
int frameBodyLength = 4;
int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength;
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, true);
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
BufferUtil.clearToFill(buffer);
generateControlFrameHeader(ping, frameBodyLength, buffer);

View File

@ -39,7 +39,7 @@ public class RstStreamGenerator extends ControlFrameGenerator
int frameBodyLength = 8;
int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength;
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, true);
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
BufferUtil.clearToFill(buffer);
generateControlFrameHeader(rstStream, frameBodyLength, buffer);

View File

@ -43,7 +43,7 @@ public class SettingsGenerator extends ControlFrameGenerator
int size = settings.size();
int frameBodyLength = 4 + 8 * size;
int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength;
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, true);
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
BufferUtil.clearToFill(buffer);
generateControlFrameHeader(settingsFrame, frameBodyLength, buffer);

View File

@ -58,7 +58,7 @@ public class SynReplyGenerator extends ControlFrameGenerator
int totalLength = ControlFrame.HEADER_LENGTH + frameLength;
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, true);
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
BufferUtil.clearToFill(buffer);
generateControlFrameHeader(synReply, frameLength, buffer);

View File

@ -60,7 +60,7 @@ public class SynStreamGenerator extends ControlFrameGenerator
int totalLength = ControlFrame.HEADER_LENGTH + frameLength;
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, true);
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
BufferUtil.clearToFill(buffer);
generateControlFrameHeader(synStream, frameLength, buffer);

View File

@ -39,7 +39,7 @@ public class WindowUpdateGenerator extends ControlFrameGenerator
int frameBodyLength = 8;
int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength;
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, true);
ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
BufferUtil.clearToFill(buffer);
generateControlFrameHeader(windowUpdate, frameBodyLength, buffer);

View File

@ -57,7 +57,7 @@ public class SSLExternalServerTest extends AbstractHTTPSPDYTest
return new SPDYClient.Factory(threadPool, null, sslContextFactory, 30000);
}
@Test
@Test(timeout=5000)
public void testExternalServer() throws Exception
{
String host = "encrypted.google.com";

View File

@ -0,0 +1,159 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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.spdy.server.http;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.ReplyInfo;
import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.Stream;
import org.eclipse.jetty.spdy.api.StreamFrameListener;
import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@Ignore("So far only used for testing performance tweaks. So no need to run it in a build")
public class SimpleHTTPBenchmarkTest extends AbstractHTTPSPDYTest
{
private static final Logger LOG = Log.getLogger(SimpleHTTPBenchmarkTest.class);
private final int dataSize = 4096 * 100;
private Session session;
private int requestCount = 100;
public SimpleHTTPBenchmarkTest(short version)
{
super(version);
}
@Before
public void setUp() throws Exception
{
final byte[] data = new byte[dataSize];
new Random().nextBytes(data);
session = startClient(version, startHTTPServer(version, new AbstractHandler()
{
@Override
public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
throws IOException, ServletException
{
request.setHandled(true);
assertEquals("GET", httpRequest.getMethod());
assertThat("accept-encoding is set to gzip, even if client didn't set it",
httpRequest.getHeader("accept-encoding"), containsString("gzip"));
assertThat(httpRequest.getHeader("host"), is("localhost:" + connector.getLocalPort()));
httpResponse.getOutputStream().write(data);
}
}, 0), null);
}
@Test
public void testRunBenchmark() throws Exception
{
long overallStart = System.nanoTime();
int iterations = 20;
for (int j = 0; j < iterations; j++)
{
long start = System.nanoTime();
for (int i = 0; i < requestCount; i++)
sendGetRequestWithData();
long timeElapsed = System.nanoTime() - start;
LOG.info("Requests with {}b response took: {}ms", dataSize, timeElapsed / 1000 / 1000);
}
long timeElapsedOverall = (System.nanoTime() - overallStart) / 1000 / 1000;
LOG.info("Time elapsed overall: {}ms avg: {}ms", timeElapsedOverall, timeElapsedOverall / iterations);
}
private void sendGetRequest() throws Exception
{
final CountDownLatch replyLatch = new CountDownLatch(1);
final String path = "/foo";
Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getLocalPort(), version, "GET", path);
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
{
@Override
public void onReply(Stream stream, ReplyInfo replyInfo)
{
assertTrue(replyInfo.isClose());
Fields replyHeaders = replyInfo.getHeaders();
assertThat(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200"), CoreMatchers.is(true));
assertThat(replyHeaders.get(HttpHeader.SERVER.asString()), CoreMatchers.is(notNullValue()));
assertThat(replyHeaders.get(HttpHeader.X_POWERED_BY.asString()), CoreMatchers.is(notNullValue()));
replyLatch.countDown();
}
});
assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true));
}
private void sendGetRequestWithData() throws Exception
{
final CountDownLatch replyLatch = new CountDownLatch(1);
final CountDownLatch dataLatch = new CountDownLatch(1);
final String path = "/foo";
Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getLocalPort(), version, "GET", path);
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
{
@Override
public void onReply(Stream stream, ReplyInfo replyInfo)
{
Fields replyHeaders = replyInfo.getHeaders();
assertThat(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200"), CoreMatchers.is(true));
assertThat(replyHeaders.get(HttpHeader.SERVER.asString()), CoreMatchers.is(notNullValue()));
assertThat(replyHeaders.get(HttpHeader.X_POWERED_BY.asString()), CoreMatchers.is(notNullValue()));
replyLatch.countDown();
}
@Override
public void onData(Stream stream, DataInfo dataInfo)
{
dataInfo.consume(dataInfo.available());
if (dataInfo.isClose())
dataLatch.countDown();
}
});
assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true));
assertThat("data has been received", dataLatch.await(5, TimeUnit.SECONDS), is(true));
}
}

View File

@ -67,18 +67,8 @@ import java.util.regex.Pattern;
* </li>
* <li>Module Resolution</li>
* <li>Properties Resolution</li>
* <li>Execution
* <ul>
* <li>--list-modules</li>
* <li>--list-classpath</li>
* <li>--list-config</li>
* <li>--version</li>
* <li>--help</li>
* <li>--dry-run</li>
* <li>--exec</li>
* <li>--stop</li>
* <li>(or normal startup)</li>
* </ul>
* <li>Present Optional Informational Options</li>
* <li>Normal Startup</li>
* </li>
* </ol>
*/

View File

@ -26,6 +26,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
@ -207,13 +208,20 @@ public class StartArgs
return;
}
List<String> sortedKeys = new ArrayList<>();
@SuppressWarnings("unchecked")
Enumeration<String> keyEnum = (Enumeration<String>)properties.propertyNames();
while (keyEnum.hasMoreElements())
{
String name = keyEnum.nextElement();
String value = properties.getProperty(name);
System.out.printf(" %s = %s%n",name,value);
sortedKeys.add(keyEnum.nextElement());
}
Collections.sort(sortedKeys);
for(String key: sortedKeys)
{
String value = properties.getProperty(key);
System.out.printf(" %s = %s%n",key,value);
}
}
@ -229,7 +237,11 @@ public class StartArgs
return;
}
for (String key : systemPropertyKeys)
List<String> sortedKeys = new ArrayList<>();
sortedKeys.addAll(systemPropertyKeys);
Collections.sort(sortedKeys);
for (String key : sortedKeys)
{
String value = System.getProperty(key);
System.out.printf(" %s = %s%n",key,value);

View File

@ -41,8 +41,8 @@ Debug and Start Logging:
--debug Enable debug output of the startup procedure.
Note: this does not setup debug for Jetty itself.
If you want debug for Jetty, configure your logging
(See bellow)
If you want debug for Jetty, configure your logging.
http://www.eclipse.org/jetty/documentation/
--start-log-file=<filename>
A filename, relative to ${jetty.base}, where all startup

View File

@ -1,134 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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.util;
import java.util.concurrent.Executor;
public abstract class ExecutorCallback implements Callback
{
private final ForkInvoker<Void> _invoker;
private final Executor _executor;
private final Runnable _onComplete=new Runnable()
{
@Override
public void run()
{
onCompleted();
}
};
public ExecutorCallback(Executor executor)
{
this(executor, 4);
}
public ExecutorCallback(Executor executor, int maxRecursion)
{
_executor = executor;
_invoker = maxRecursion>0?new ExecutorCallbackInvoker(maxRecursion):null;
if (_executor==null)
throw new IllegalArgumentException();
}
@Override
public void succeeded()
{
// Should we execute?
if (_invoker==null)
{
_executor.execute(_onComplete);
}
else if (alwaysDispatchCompletion())
{
_invoker.fork(null);
}
else
{
_invoker.invoke(null);
}
}
protected abstract void onCompleted();
@Override
public void failed(final Throwable x)
{
// Always execute failure
Runnable runnable = new Runnable()
{
@Override
public void run()
{
onFailed(x);
}
@Override
public String toString()
{
return String.format("ExecutorCallback@%x{%s}", hashCode(), x);
}
};
if (_executor == null)
new Thread(runnable).start();
else
_executor.execute(runnable);
}
protected void onFailed(Throwable x)
{
}
protected boolean alwaysDispatchCompletion()
{
return _executor != null;
}
@Override
public String toString()
{
return String.format("%s@%x", getClass(), hashCode());
}
private class ExecutorCallbackInvoker extends ForkInvoker<Void> implements Runnable
{
private ExecutorCallbackInvoker(int maxInvocations)
{
super(maxInvocations);
}
@Override
public void fork(Void arg)
{
_executor.execute(this);
}
@Override
public void call(Void arg)
{
onCompleted();
}
@Override
public void run()
{
onCompleted();
}
}
}

View File

@ -0,0 +1,130 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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.util.resource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.channels.ReadableByteChannel;
/**
* EmptyResource
*
* Represents a resource that does does not refer to any file, url, jar etc.
*/
public class EmptyResource extends Resource
{
public static final Resource INSTANCE = new EmptyResource();
private EmptyResource()
{
}
@Override
public boolean isContainedIn(Resource r) throws MalformedURLException
{
return false;
}
@Override
public void close()
{
}
@Override
public boolean exists()
{
return false;
}
@Override
public boolean isDirectory()
{
return false;
}
@Override
public long lastModified()
{
return 0;
}
@Override
public long length()
{
return 0;
}
@Override
public URL getURL()
{
return null;
}
@Override
public File getFile() throws IOException
{
return null;
}
@Override
public String getName()
{
return null;
}
@Override
public InputStream getInputStream() throws IOException
{
return null;
}
@Override
public ReadableByteChannel getReadableByteChannel() throws IOException
{
return null;
}
@Override
public boolean delete() throws SecurityException
{
return false;
}
@Override
public boolean renameTo(Resource dest) throws SecurityException
{
return false;
}
@Override
public String[] list()
{
return null;
}
@Override
public Resource addPath(String path) throws IOException, MalformedURLException
{
return null;
}
}

View File

@ -32,6 +32,8 @@ import java.nio.channels.ReadableByteChannel;
import java.nio.file.StandardOpenOption;
import java.security.Permission;
import javax.management.RuntimeErrorException;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log;
@ -54,7 +56,7 @@ public class FileResource extends Resource
/* ------------------------------------------------------------ */
private final File _file;
private final String _uri;
private final URL _alias;
private final URI _alias;
/* -------------------------------------------------------- */
public FileResource(URL url)
@ -133,7 +135,7 @@ public class FileResource extends Resource
}
/* -------------------------------------------------------- */
private static URL checkAlias(File file)
private static URI checkAlias(File file)
{
try
{
@ -143,12 +145,22 @@ public class FileResource extends Resource
if (!abs.equals(can))
{
LOG.debug("ALIAS abs={} can={}",abs,can);
return new File(can).toURI().toURL();
return new File(can).toURI();
}
}
catch(IOException e)
{
LOG.warn(e);
LOG.warn("bad alias for {}: {}",file,e.toString());
LOG.debug(e);
try
{
return new URI("http://eclipse.org/bad/canonical/alias");
}
catch(Exception e2)
{
LOG.ignore(e2);
throw new RuntimeException(e);
}
}
return null;
@ -193,7 +205,7 @@ public class FileResource extends Resource
/* ------------------------------------------------------------ */
@Override
public URL getAlias()
public URI getAlias()
{
return _alias;
}
@ -390,6 +402,12 @@ public class FileResource extends Resource
}
}
@Override
public URI getURI()
{
return _file.toURI();
}
@Override
public String toString()
{

View File

@ -29,7 +29,9 @@ import java.net.URI;
import java.net.URL;
import java.nio.channels.ReadableByteChannel;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import org.eclipse.jetty.util.B64Code;
@ -471,7 +473,7 @@ public abstract class Resource implements ResourceFactory, Closeable
/**
* @return The canonical Alias of this resource or null if none.
*/
public URL getAlias()
public URI getAlias()
{
return null;
}
@ -662,6 +664,34 @@ public abstract class Resource implements ResourceFactory, Closeable
}
}
/* ------------------------------------------------------------ */
public Collection<Resource> getAllResources()
{
try
{
ArrayList<Resource> deep=new ArrayList<>();
{
String[] list=list();
if (list!=null)
{
for (String i:list)
{
Resource r=addPath(i);
if (r.isDirectory())
deep.addAll(r.getAllResources());
else
deep.add(r);
}
}
}
return deep;
}
catch(Exception e)
{
throw new IllegalStateException(e);
}
}
/* ------------------------------------------------------------ */
/** Generate a properly encoded URL from a {@link File} instance.
* @param file Target file.

View File

@ -30,9 +30,9 @@ import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.ZipFile;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
@ -297,8 +297,18 @@ public class ResourceTest
assertTrue(entries.contains("numbers"));
IO.delete(extract);
}
/* ------------------------------------------------------------ */
@Test
public void testJarFileGetAllResoures()
throws Exception
{
String s = "jar:"+__userURL+"TestData/test.zip!/subdir/";
Resource r = Resource.newResource(s);
Collection<Resource> deep=r.getAllResources();
assertEquals(4, deep.size());
}
@Test

View File

@ -168,11 +168,11 @@
</init-param>
<init-param>
<param-name>gzip</param-name>
<param-value>true</param-value>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>etags</param-name>
<param-value>true</param-value>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>useFileMappedBuffer</param-name>

View File

@ -19,7 +19,7 @@
package org.eclipse.jetty.webapp;
import java.util.List;
import java.util.Map;
import org.eclipse.jetty.util.resource.Resource;
@ -70,18 +70,18 @@ public class FragmentConfiguration extends AbstractConfiguration
public void findWebFragments (final WebAppContext context, final MetaData metaData) throws Exception
{
@SuppressWarnings("unchecked")
List<Resource> frags = (List<Resource>)context.getAttribute(FRAGMENT_RESOURCES);
Map<Resource, Resource> frags = (Map<Resource,Resource>)context.getAttribute(FRAGMENT_RESOURCES);
if (frags!=null)
{
for (Resource frag : frags)
for (Resource key : frags.keySet())
{
if (frag.isDirectory()) //tolerate the case where the library is a directory, not a jar. useful for OSGi for example
if (key.isDirectory()) //tolerate the case where the library is a directory, not a jar. useful for OSGi for example
{
metaData.addFragment(frag, Resource.newResource(frag.getURL()+"/META-INF/web-fragment.xml"));
metaData.addFragment(key, frags.get(key));
}
else //the standard case: a jar most likely inside WEB-INF/lib
{
metaData.addFragment(frag, Resource.newResource("jar:"+frag.getURL()+"!/META-INF/web-fragment.xml"));
metaData.addFragment(key, frags.get(key));
}
}
}

View File

@ -18,6 +18,12 @@
package org.eclipse.jetty.webapp;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@ -28,6 +34,8 @@ import javax.servlet.ServletContext;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.EmptyResource;
import org.eclipse.jetty.util.resource.JarResource;
import org.eclipse.jetty.util.resource.Resource;
@ -43,18 +51,18 @@ public class MetaData
private static final Logger LOG = Log.getLogger(MetaData.class);
public static final String ORDERED_LIBS = "javax.servlet.context.orderedLibs";
public static final Resource NON_FRAG_RESOURCE = EmptyResource.INSTANCE;
protected Map<String, OriginInfo> _origins =new HashMap<String,OriginInfo>();
protected WebDescriptor _webDefaultsRoot;
protected WebDescriptor _webXmlRoot;
protected final List<WebDescriptor> _webOverrideRoots=new ArrayList<WebDescriptor>();
protected boolean _metaDataComplete;
protected final List<DiscoveredAnnotation> _annotations = new ArrayList<DiscoveredAnnotation>();
protected final List<DescriptorProcessor> _descriptorProcessors = new ArrayList<DescriptorProcessor>();
protected final List<FragmentDescriptor> _webFragmentRoots = new ArrayList<FragmentDescriptor>();
protected final Map<String,FragmentDescriptor> _webFragmentNameMap = new HashMap<String,FragmentDescriptor>();
protected final Map<Resource, FragmentDescriptor> _webFragmentResourceMap = new HashMap<Resource, FragmentDescriptor>();
protected final Map<Resource, List<DiscoveredAnnotation>> _webFragmentAnnotations = new HashMap<Resource, List<DiscoveredAnnotation>>();
protected final Map<Resource, List<DiscoveredAnnotation>> _annotations = new HashMap<Resource, List<DiscoveredAnnotation>>();
protected final List<Resource> _webInfClasses = new ArrayList<Resource>();
protected final List<Resource> _webInfJars = new ArrayList<Resource>();
protected final List<Resource> _orderedWebInfJars = new ArrayList<Resource>();
@ -135,7 +143,7 @@ public class MetaData
_webFragmentRoots.clear();
_webFragmentNameMap.clear();
_webFragmentResourceMap.clear();
_webFragmentAnnotations.clear();
_annotations.clear();
_webInfJars.clear();
_orderedWebInfJars.clear();
_orderedContainerResources.clear();
@ -276,45 +284,47 @@ public class MetaData
return;
for (DiscoveredAnnotation a:annotations)
{
Resource r = a.getResource();
if (r == null || !_webInfJars.contains(r))
_annotations.add(a);
else
addDiscoveredAnnotation(a.getResource(), a);
addDiscoveredAnnotation(a);
}
}
public void addDiscoveredAnnotation(Resource resource, DiscoveredAnnotation annotation)
/**
* Add an annotation that has been discovered on a class, method or field within a resource
* eg a jar or dir.
*
* This method is synchronized as it is anticipated that it may be called by many threads
* during the annotation scanning phase.
*
* @param annotation
*/
public synchronized void addDiscoveredAnnotation (DiscoveredAnnotation annotation)
{
List<DiscoveredAnnotation> list = _webFragmentAnnotations.get(resource);
if (annotation == null)
return;
//if no resource associated with an annotation or the resource is not one of the WEB-INF/lib jars,
//map it to empty resource
Resource resource = annotation.getResource();
if (resource == null || !_webInfJars.contains(resource))
resource = EmptyResource.INSTANCE;
List<DiscoveredAnnotation> list = _annotations.get(resource);
if (list == null)
{
list = new ArrayList<DiscoveredAnnotation>();
_webFragmentAnnotations.put(resource, list);
_annotations.put(resource, list);
}
list.add(annotation);
}
public void addDiscoveredAnnotations(Resource resource, List<DiscoveredAnnotation> annotations)
{
List<DiscoveredAnnotation> list = _webFragmentAnnotations.get(resource);
if (list == null)
{
list = new ArrayList<DiscoveredAnnotation>();
_webFragmentAnnotations.put(resource, list);
}
list.addAll(annotations);
}
public void addDescriptorProcessor(DescriptorProcessor p)
{
_descriptorProcessors.add(p);
}
public void orderFragments ()
{
//if we have already ordered them don't do it again
@ -373,13 +383,20 @@ public class MetaData
}
}
for (DiscoveredAnnotation a:_annotations)
//get an apply the annotations that are not associated with a fragment (and hence for
//which no ordering applies
List<DiscoveredAnnotation> nonFragAnnotations = _annotations.get(NON_FRAG_RESOURCE);
if (nonFragAnnotations != null)
{
LOG.debug("apply {}",a);
a.apply();
for (DiscoveredAnnotation a:nonFragAnnotations)
{
LOG.debug("apply {}",a);
a.apply();
}
}
//apply the annotations that are associated with a fragment, according to the
//established ordering
List<Resource> resources = getOrderedWebInfJars();
for (Resource r:resources)
{
@ -393,7 +410,7 @@ public class MetaData
}
}
List<DiscoveredAnnotation> fragAnnotations = _webFragmentAnnotations.get(r);
List<DiscoveredAnnotation> fragAnnotations = _annotations.get(r);
if (fragAnnotations != null)
{
for (DiscoveredAnnotation a:fragAnnotations)

View File

@ -21,8 +21,13 @@ package org.eclipse.jetty.webapp;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.jar.JarEntry;
import org.eclipse.jetty.util.log.Log;
@ -45,56 +50,50 @@ public class MetaInfConfiguration extends AbstractConfiguration
public static final String METAINF_TLDS = TagLibConfiguration.TLD_RESOURCES;
public static final String METAINF_FRAGMENTS = FragmentConfiguration.FRAGMENT_RESOURCES;
public static final String METAINF_RESOURCES = WebInfConfiguration.RESOURCE_URLS;
public static final String METAINF_RESOURCES = WebInfConfiguration.RESOURCE_DIRS;
@Override
public void preConfigure(final WebAppContext context) throws Exception
{
//Merge all container and webinf lib jars to look for META-INF resources
ArrayList<Resource> jars = new ArrayList<Resource>();
jars.addAll(context.getMetaData().getContainerResources());
jars.addAll(context.getMetaData().getWebInfJars());
JarScanner scanner = new JarScanner()
{
public void processEntry(URI jarUri, JarEntry entry)
{
try
{
MetaInfConfiguration.this.processEntry(context,jarUri,entry);
}
catch (Exception e)
{
LOG.warn("Problem processing jar entry " + entry, e);
}
}
};
//Scan jars for META-INF information
if (jars != null)
{
URI[] uris = new URI[jars.size()];
int i=0;
for (Resource r : jars)
{
uris[i++] = r.getURI();
URI uri = r.getURI();
Resource fragXml = Resource.newResource("jar:"+uri+"!/META-INF/web-fragment.xml");
if (fragXml.exists())
{
//add mapping for resource->fragment
Map<Resource, Resource> fragments = (Map<Resource,Resource>)context.getAttribute(METAINF_FRAGMENTS);
if (fragments == null)
{
fragments = new HashMap<Resource, Resource>();
context.setAttribute(METAINF_FRAGMENTS, fragments);
}
fragments.put(r, fragXml);
}
Resource resourcesDir = Resource.newResource("jar:"+uri+"!/META-INF/resources");
if (resourcesDir.exists())
{
//add resources dir
Set<Resource> dirs = (Set<Resource>)context.getAttribute(METAINF_RESOURCES);
if (dirs == null)
{
dirs = new HashSet<Resource>();
context.setAttribute(METAINF_RESOURCES, dirs);
}
dirs.add(resourcesDir);
}
}
scanner.scan(null, uris, true);
}
}
@Override
public void configure(WebAppContext context) throws Exception
{
}
@Override
public void deconfigure(WebAppContext context) throws Exception
{
}
@Override
public void postConfigure(WebAppContext context) throws Exception
@ -103,50 +102,4 @@ public class MetaInfConfiguration extends AbstractConfiguration
context.setAttribute(METAINF_RESOURCES, null);
context.setAttribute(METAINF_TLDS, null);
}
public void addResource (WebAppContext context, String attribute, Resource jar)
{
@SuppressWarnings("unchecked")
List<Resource> list = (List<Resource>)context.getAttribute(attribute);
if (list==null)
{
list=new ArrayList<Resource>();
context.setAttribute(attribute,list);
}
if (!list.contains(jar))
list.add(jar);
}
protected void processEntry(WebAppContext context, URI jarUri, JarEntry entry)
{
String name = entry.getName();
if (!name.startsWith("META-INF/"))
return;
try
{
if (name.equals("META-INF/web-fragment.xml") && context.isConfigurationDiscovered())
{
addResource(context,METAINF_FRAGMENTS,Resource.newResource(jarUri));
}
else if (name.equals("META-INF/resources/") && context.isConfigurationDiscovered())
{
addResource(context,METAINF_RESOURCES,Resource.newResource("jar:"+jarUri+"!/META-INF/resources"));
}
else
{
String lcname = name.toLowerCase(Locale.ENGLISH);
if (lcname.endsWith(".tld"))
{
addResource(context,METAINF_TLDS,Resource.newResource("jar:"+jarUri+"!/"+name));
}
}
}
catch(Exception e)
{
context.getServletContext().log(jarUri+"!/"+name,e);
}
}
}

View File

@ -27,7 +27,9 @@ import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import org.eclipse.jetty.server.Connector;
@ -54,7 +56,7 @@ public class WebInfConfiguration extends AbstractConfiguration
* If set, to a list of URLs, these resources are added to the context
* resource base as a resource collection.
*/
public static final String RESOURCE_URLS = "org.eclipse.jetty.resources";
public static final String RESOURCE_DIRS = "org.eclipse.jetty.resources";
protected Resource _preUnpackBaseResource;
@ -175,7 +177,7 @@ public class WebInfConfiguration extends AbstractConfiguration
// Look for extra resource
@SuppressWarnings("unchecked")
List<Resource> resources = (List<Resource>)context.getAttribute(RESOURCE_URLS);
Set<Resource> resources = (Set<Resource>)context.getAttribute(RESOURCE_DIRS);
if (resources!=null)
{
Resource[] collection=new Resource[resources.size()+1];

View File

@ -26,6 +26,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import javax.websocket.ClientEndpoint;
@ -71,6 +72,11 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont
private WebSocketClient client;
public ClientContainer()
{
this(null);
}
public ClientContainer(Executor executor)
{
endpointClientMetadataCache = new ConcurrentHashMap<>();
decoderFactory = new DecoderFactory(PrimitiveDecoderMetadataSet.INSTANCE);
@ -80,7 +86,7 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont
decoderFactory.init(empty);
encoderFactory.init(empty);
client = new WebSocketClient();
client = new WebSocketClient(executor);
client.setEventDriverFactory(new JsrEventDriverFactory(client.getPolicy()));
client.setSessionFactory(new JsrSessionFactory(this));
addBean(client);

View File

@ -1,27 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== -->
<!-- Add javax.websocket Configuring classes to all webapps for this Server -->
<!-- =========================================================== -->
<Call class="org.eclipse.jetty.webapp.Configuration$ClassList" name="setServerDefault">
<Arg><Ref refid="Server" /></Arg>
<Call name="addBefore">
<Arg name="beforeClass">org.eclipse.jetty.annotations.AnnotationConfiguration</Arg>
<Arg>
<Array type="String">
<Item>org.eclipse.jetty.websocket.jsr356.server.WebSocketConfiguration</Item>
</Array>
</Arg>
</Call>
</Call>
<!-- Should a Websocket container be initialized for each context? -->
<!-- Can be overridden by context attribute -->
<Call name="setAttribute">
<Arg>org.eclipse.jetty.websocket.jsr356</Arg>
<Arg type="Boolean"><Property name="org.eclipse.jetty.websocket.jsr356" default="true"/></Arg>
</Call>
</Configure>

View File

@ -4,17 +4,10 @@
[depend]
# WebSocket needs Annotations feature
server
annotations
[lib]
# WebSocket needs websocket jars (as defined in start.config)
lib/websocket/*.jar
[xml]
# WebSocket needs websocket configuration
etc/jetty-websockets.xml
[ini-template]
# Start Websocket containter for all contexts
org.eclipse.jetty.websocket.jsr356=true

View File

@ -18,6 +18,8 @@
package org.eclipse.jetty.websocket.jsr356.server;
import java.util.concurrent.Executor;
import javax.websocket.DeploymentException;
import javax.websocket.Endpoint;
import javax.websocket.server.ServerEndpoint;
@ -42,9 +44,9 @@ public class ServerContainer extends ClientContainer implements javax.websocket.
private final MappedWebSocketCreator mappedCreator;
private final WebSocketServerFactory webSocketServerFactory;
public ServerContainer(MappedWebSocketCreator creator, WebSocketServerFactory factory)
public ServerContainer(MappedWebSocketCreator creator, WebSocketServerFactory factory, Executor executor)
{
super();
super(executor);
this.mappedCreator = creator;
this.webSocketServerFactory = factory;
EventDriverFactory eventDriverFactory = this.webSocketServerFactory.getEventDriverFactory();

View File

@ -1,122 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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.websocket.jsr356.server;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.webapp.AbstractConfiguration;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.websocket.jsr356.server.deploy.DiscoveredEndpoints;
import org.eclipse.jetty.websocket.jsr356.server.deploy.ServerEndpointAnnotationHandler;
import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
/**
* WebSocket Server Configuration component.
* <p>
* This configuration will configure a context for JSR356 Websockets.
* <p>
* It is possible to disable specific contexts with an attribute <code>"org.eclipse.jetty.websocket.jsr356"</code> (set to <code>"false"</code>)
* <p>
* This attribute may be set on an individual context, or on the server to affect all deployed contexts.
*/
public class WebSocketConfiguration extends AbstractConfiguration
{
public static final String ENABLE = "org.eclipse.jetty.websocket.jsr356";
private static final Logger LOG = Log.getLogger(WebSocketConfiguration.class);
/**
* Create a ServerContainer properly, useful for embedded application use.
* <p>
* Notably, the cometd3 project uses this.
*
* @param context
* the context to enable javax.websocket support filters on
* @return the ServerContainer that was created
*/
public static ServerContainer configureContext(ServletContextHandler context)
{
LOG.debug("Configure javax.websocket for WebApp {}",context);
WebSocketUpgradeFilter filter = WebSocketUpgradeFilter.configureContext(context);
// Create the Jetty ServerContainer implementation
ServerContainer jettyContainer = new ServerContainer(filter,filter.getFactory());
context.addBean(jettyContainer);
// Store a reference to the ServerContainer per javax.websocket spec 1.0 final section 6.4 Programmatic Server Deployment
context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
// Store reference to DiscoveredEndpoints
context.setAttribute(DiscoveredEndpoints.class.getName(),new DiscoveredEndpoints());
return jettyContainer;
}
public static boolean isJSR356Context(WebAppContext context)
{
Object enable = context.getAttribute(ENABLE);
if (enable instanceof Boolean)
{
return ((Boolean)enable).booleanValue();
}
enable = context.getServer().getAttribute(ENABLE);
if (enable instanceof Boolean)
{
return ((Boolean)enable).booleanValue();
}
return true;
}
@Override
public void configure(WebAppContext context) throws Exception
{
if (isJSR356Context(context))
{
WebSocketConfiguration.configureContext(context);
}
else
{
LOG.debug("JSR-356 support disabled for WebApp {}",context);
}
}
@Override
public void preConfigure(WebAppContext context) throws Exception
{
if (isJSR356Context(context))
{
boolean scanningAdded = false;
// Add the annotation scanning handlers (if annotation scanning enabled)
for (Configuration config : context.getConfigurations())
{
if (config instanceof AnnotationConfiguration)
{
AnnotationConfiguration annocfg = (AnnotationConfiguration)config;
annocfg.addDiscoverableAnnotationHandler(new ServerEndpointAnnotationHandler(context));
scanningAdded = true;
}
}
LOG.debug("@ServerEndpoint scanning added: {}",scanningAdded);
}
}
}

View File

@ -1,158 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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.websocket.jsr356.server.deploy;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
import javax.websocket.Endpoint;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* Tracking for Discovered Endpoints.
* <p>
* This is a collection of endpoints, grouped by type (by Annotation or by extending Endpoint). Along with some better error messages for conflicting endpoints.
*/
public class DiscoveredEndpoints
{
private static class LocatedClass
{
private Class<?> clazz;
private URI location;
public LocatedClass(Class<?> clazz)
{
this.clazz = clazz;
this.location = getArchiveURI(clazz);
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("LocatedClass[");
builder.append(clazz.getName());
builder.append("]");
return builder.toString();
}
}
private static final Logger LOG = Log.getLogger(DiscoveredEndpoints.class);
public static URI getArchiveURI(Class<?> clazz)
{
String resourceName = clazz.getName().replace('.','/') + ".class";
URL classUrl = clazz.getClassLoader().getResource(resourceName);
if (classUrl == null)
{
// is this even possible at this point?
return null;
}
try
{
URI uri = classUrl.toURI();
String scheme = uri.getScheme();
if (scheme.equalsIgnoreCase("jar"))
{
String ssp = uri.getSchemeSpecificPart();
int idx = ssp.indexOf("!/");
if (idx >= 0)
{
ssp = ssp.substring(0,idx);
}
return URI.create(ssp);
}
}
catch (URISyntaxException e)
{
LOG.warn("Class reference not a valid URI? " + classUrl,e);
}
return null;
}
private Set<LocatedClass> extendedEndpoints;
private Set<LocatedClass> annotatedEndpoints;
public DiscoveredEndpoints()
{
extendedEndpoints = new HashSet<>();
annotatedEndpoints = new HashSet<>();
}
public void addAnnotatedEndpoint(Class<?> endpoint)
{
this.annotatedEndpoints.add(new LocatedClass(endpoint));
}
public void addExtendedEndpoint(Class<? extends Endpoint> endpoint)
{
this.extendedEndpoints.add(new LocatedClass(endpoint));
}
public Set<Class<?>> getAnnotatedEndpoints()
{
Set<Class<?>> endpoints = new HashSet<>();
for (LocatedClass lc : annotatedEndpoints)
{
endpoints.add(lc.clazz);
}
return endpoints;
}
public void getArchiveSpecificAnnnotatedEndpoints(URI archiveURI, Set<Class<?>> archiveSpecificEndpoints)
{
for (LocatedClass lc : annotatedEndpoints)
{
if ((archiveURI == null) || lc.location.getPath().equals(archiveURI.getPath()))
{
archiveSpecificEndpoints.add(lc.clazz);
}
}
}
@SuppressWarnings("unchecked")
public void getArchiveSpecificExtendedEndpoints(URI archiveURI, Set<Class<? extends Endpoint>> archiveSpecificEndpoints)
{
for (LocatedClass lc : extendedEndpoints)
{
if ((archiveURI == null) || (lc.location.getPath().equals(archiveURI.getPath()) && Endpoint.class.isAssignableFrom(lc.clazz)))
{
archiveSpecificEndpoints.add((Class<? extends Endpoint>)lc.clazz);
}
}
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("DiscoveredEndpoints [extendedEndpoints=");
builder.append(extendedEndpoints);
builder.append(", annotatedEndpoints=");
builder.append(annotatedEndpoints);
builder.append("]");
return builder.toString();
}
}

View File

@ -1,162 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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.websocket.jsr356.server.deploy;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;
import javax.websocket.DeploymentException;
import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpointConfig;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.websocket.jsr356.server.ServerContainer;
import org.eclipse.jetty.websocket.jsr356.server.WebSocketConfiguration;
import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
@HandlesTypes(
{ ServerApplicationConfig.class, Endpoint.class })
public class ServerApplicationConfigListener implements ServletContainerInitializer
{
private static final Logger LOG = Log.getLogger(ServerApplicationConfigListener.class);
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException
{
if (!WebSocketConfiguration.isJSR356Context(WebAppContext.getCurrentWebAppContext()))
return;
WebSocketUpgradeFilter filter = (WebSocketUpgradeFilter)ctx.getAttribute(WebSocketUpgradeFilter.class.getName());
if (filter == null)
{
LOG.warn("Required attribute not available: " + WebSocketUpgradeFilter.class.getName());
return;
}
DiscoveredEndpoints discovered = (DiscoveredEndpoints)ctx.getAttribute(DiscoveredEndpoints.class.getName());
if (discovered == null)
{
LOG.warn("Required attribute not available: " + DiscoveredEndpoints.class.getName());
return;
}
LOG.debug("Found {} classes",c.size());
LOG.debug("Discovered: {}",discovered);
// First add all of the Endpoints
addEndpoints(c,discovered);
// Now process the ServerApplicationConfig entries
ServerContainer container = (ServerContainer)ctx.getAttribute(javax.websocket.server.ServerContainer.class.getName());
Set<Class<? extends Endpoint>> archiveSpecificExtendEndpoints = new HashSet<>();
Set<Class<?>> archiveSpecificAnnotatedEndpoints = new HashSet<>();
List<Class<? extends ServerApplicationConfig>> serverAppConfigs = filterServerApplicationConfigs(c);
if(serverAppConfigs.size() >= 1) {
for (Class<? extends ServerApplicationConfig> clazz : filterServerApplicationConfigs(c))
{
LOG.debug("Found ServerApplicationConfig: {}",clazz);
try
{
ServerApplicationConfig config = (ServerApplicationConfig)clazz.newInstance();
URI archiveURI = DiscoveredEndpoints.getArchiveURI(clazz);
archiveSpecificExtendEndpoints.clear();
archiveSpecificAnnotatedEndpoints.clear();
discovered.getArchiveSpecificExtendedEndpoints(archiveURI,archiveSpecificExtendEndpoints);
discovered.getArchiveSpecificAnnnotatedEndpoints(archiveURI,archiveSpecificAnnotatedEndpoints);
Set<ServerEndpointConfig> seconfigs = config.getEndpointConfigs(archiveSpecificExtendEndpoints);
if (seconfigs != null)
{
for (ServerEndpointConfig sec : seconfigs)
{
container.addEndpoint(sec);
}
}
Set<Class<?>> annotatedClasses = config.getAnnotatedEndpointClasses(archiveSpecificAnnotatedEndpoints);
if (annotatedClasses != null)
{
for (Class<?> annotatedClass : annotatedClasses)
{
container.addEndpoint(annotatedClass);
}
}
}
catch (InstantiationException | IllegalAccessException e)
{
throw new ServletException("Unable to instantiate: " + clazz.getName(),e);
}
catch (DeploymentException e)
{
throw new ServletException(e);
}
}
} else {
// Default behavior (no ServerApplicationConfigs found)
// Note: it is impossible to determine path of "extends Endpoint" discovered classes
for(Class<?> annotatedClass: discovered.getAnnotatedEndpoints())
{
try
{
container.addEndpoint(annotatedClass);
}
catch (DeploymentException e)
{
throw new ServletException(e);
}
}
}
}
@SuppressWarnings("unchecked")
private List<Class<? extends ServerApplicationConfig>> filterServerApplicationConfigs(Set<Class<?>> c)
{
List<Class<? extends ServerApplicationConfig>> configs = new ArrayList<>();
for (Class<?> clazz : c)
{
if (ServerApplicationConfig.class.isAssignableFrom(clazz))
{
configs.add((Class<? extends ServerApplicationConfig>)clazz);
}
}
return configs;
}
@SuppressWarnings("unchecked")
private void addEndpoints(Set<Class<?>> c, DiscoveredEndpoints discovered)
{
for (Class<?> clazz : c)
{
if (Endpoint.class.isAssignableFrom(clazz))
{
discovered.addExtendedEndpoint((Class<? extends Endpoint>)clazz);
}
}
}
}

View File

@ -1,64 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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.websocket.jsr356.server.deploy;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* Once an Annotated Server Endpoint is discovered, add it to the list of
* discovered Annotated Endpoints.
*/
public class ServerEndpointAnnotation extends DiscoveredAnnotation
{
private static final Logger LOG = Log.getLogger(ServerEndpointAnnotation.class);
public ServerEndpointAnnotation(WebAppContext context, String className)
{
super(context,className);
}
public ServerEndpointAnnotation(WebAppContext context, String className, Resource resource)
{
super(context,className,resource);
}
@Override
public void apply()
{
Class<?> clazz = getTargetClass();
if (clazz == null)
{
LOG.warn(_className + " cannot be loaded");
return;
}
DiscoveredEndpoints discovered = (DiscoveredEndpoints)_context.getAttribute(DiscoveredEndpoints.class.getName());
if(discovered == null) {
LOG.warn("Context attribute not found: " + DiscoveredEndpoints.class.getName());
return;
}
discovered.addAnnotatedEndpoint(clazz);
}
}

View File

@ -1,88 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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.websocket.jsr356.server.deploy;
import java.util.List;
import javax.websocket.server.ServerEndpoint;
import org.eclipse.jetty.annotations.AbstractDiscoverableAnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationParser.Value;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* Processing for &#64;{@link ServerEndpoint} annotations during Web App Annotation Scanning
*/
public class ServerEndpointAnnotationHandler extends AbstractDiscoverableAnnotationHandler
{
private static final String ANNOTATION_NAME = "javax.websocket.server.ServerEndpoint";
private static final Logger LOG = Log.getLogger(ServerEndpointAnnotationHandler.class);
public ServerEndpointAnnotationHandler(WebAppContext context)
{
super(context);
}
public ServerEndpointAnnotationHandler(WebAppContext context, List<DiscoveredAnnotation> list)
{
super(context,list);
}
@Override
public String getAnnotationName()
{
return ANNOTATION_NAME;
}
@Override
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotationName,
List<Value> values)
{
if (LOG.isDebugEnabled())
{
LOG.debug("handleClass: {}, {}, {}",className,annotationName,values);
}
if (!ANNOTATION_NAME.equals(annotationName))
{
// Not the one we are interested in
return;
}
ServerEndpointAnnotation annotation = new ServerEndpointAnnotation(_context,className,_resource);
addAnnotation(annotation);
}
@Override
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
List<Value> values)
{
/* @ServerEndpoint annotation not supported for fields */
}
@Override
public void handleMethod(String className, String methodName, int access, String desc, String signature, String[] exceptions, String annotation,
List<Value> values)
{
/* @ServerEndpoint annotation not supported for methods */
}
}

View File

@ -0,0 +1,211 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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.websocket.jsr356.server.deploy;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;
import javax.websocket.DeploymentException;
import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpoint;
import javax.websocket.server.ServerEndpointConfig;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.jsr356.server.ServerContainer;
import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
@HandlesTypes(
{ ServerApplicationConfig.class, ServerEndpoint.class, Endpoint.class })
public class WebSocketServerContainerInitializer implements ServletContainerInitializer
{
public static final String ENABLE_KEY = "org.eclipse.jetty.websocket.jsr356";
private static final Logger LOG = Log.getLogger(WebSocketServerContainerInitializer.class);
public static boolean isJSR356EnabledOnContext(ServletContext context)
{
Object enable = context.getAttribute(ENABLE_KEY);
if (enable instanceof Boolean)
{
return ((Boolean)enable).booleanValue();
}
return true;
}
public static ServerContainer configureContext(ServletContextHandler context)
{
// Create Filter
WebSocketUpgradeFilter filter = WebSocketUpgradeFilter.configureContext(context);
// Store reference to the WebSocketUpgradeFilter
context.setAttribute(WebSocketUpgradeFilter.class.getName(),filter);
// Create the Jetty ServerContainer implementation
ServerContainer jettyContainer = new ServerContainer(filter,filter.getFactory(),context.getServer().getThreadPool());
context.addBean(jettyContainer);
// Store a reference to the ServerContainer per javax.websocket spec 1.0 final section 6.4 Programmatic Server Deployment
context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
return jettyContainer;
}
@Override
public void onStartup(Set<Class<?>> c, ServletContext context) throws ServletException
{
if (!isJSR356EnabledOnContext(context))
{
LOG.info("JSR-356 support disabled via attribute on context {} - {}",context.getContextPath(),context);
return;
}
ContextHandler handler = ContextHandler.getContextHandler(context);
if (handler == null)
{
throw new ServletException("Not running on Jetty, JSR support disabled");
}
if (!(handler instanceof ServletContextHandler))
{
throw new ServletException("Not running in Jetty ServletContextHandler, JSR support disabled");
}
ServletContextHandler jettyContext = (ServletContextHandler)handler;
// Create the Jetty ServerContainer implementation
ServerContainer jettyContainer = configureContext(jettyContext);
// Store a reference to the ServerContainer per javax.websocket spec 1.0 final section 6.4 Programmatic Server Deployment
context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
LOG.debug("Found {} classes",c.size());
// Now process the incoming classes
Set<Class<? extends Endpoint>> discoveredExtendedEndpoints = new HashSet<>();
Set<Class<?>> discoveredAnnotatedEndpoints = new HashSet<>();
Set<Class<? extends ServerApplicationConfig>> serverAppConfigs = new HashSet<>();
filterClasses(c,discoveredExtendedEndpoints,discoveredAnnotatedEndpoints,serverAppConfigs);
LOG.debug("Discovered {} extends Endpoint classes",discoveredExtendedEndpoints.size());
LOG.debug("Discovered {} @ServerEndpoint classes",discoveredAnnotatedEndpoints.size());
LOG.debug("Discovered {} ServerApplicationConfig classes",serverAppConfigs.size());
// Process the server app configs to determine endpoint filtering
boolean wasFiltered = false;
Set<ServerEndpointConfig> deployableExtendedEndpointConfigs = new HashSet<>();
Set<Class<?>> deployableAnnotatedEndpoints = new HashSet<>();
for (Class<? extends ServerApplicationConfig> clazz : serverAppConfigs)
{
LOG.debug("Found ServerApplicationConfig: {}",clazz);
try
{
ServerApplicationConfig config = (ServerApplicationConfig)clazz.newInstance();
Set<ServerEndpointConfig> seconfigs = config.getEndpointConfigs(discoveredExtendedEndpoints);
if (seconfigs != null)
{
wasFiltered = true;
deployableExtendedEndpointConfigs.addAll(seconfigs);
}
Set<Class<?>> annotatedClasses = config.getAnnotatedEndpointClasses(discoveredAnnotatedEndpoints);
if (annotatedClasses != null)
{
wasFiltered = true;
deployableAnnotatedEndpoints.addAll(annotatedClasses);
}
}
catch (InstantiationException | IllegalAccessException e)
{
throw new ServletException("Unable to instantiate: " + clazz.getName(),e);
}
}
// Default behavior if nothing filtered
if (!wasFiltered)
{
deployableAnnotatedEndpoints.addAll(discoveredAnnotatedEndpoints);
// Note: it is impossible to determine path of "extends Endpoint" discovered classes
deployableExtendedEndpointConfigs = new HashSet<>();
}
// Deploy what should be deployed.
LOG.debug("Deploying {} ServerEndpointConfig(s)",deployableExtendedEndpointConfigs.size());
for (ServerEndpointConfig config : deployableExtendedEndpointConfigs)
{
try
{
jettyContainer.addEndpoint(config);
}
catch (DeploymentException e)
{
throw new ServletException(e);
}
}
LOG.debug("Deploying {} @ServerEndpoint(s)",deployableAnnotatedEndpoints.size());
for (Class<?> annotatedClass : deployableAnnotatedEndpoints)
{
try
{
jettyContainer.addEndpoint(annotatedClass);
}
catch (DeploymentException e)
{
throw new ServletException(e);
}
}
}
@SuppressWarnings("unchecked")
private void filterClasses(Set<Class<?>> c, Set<Class<? extends Endpoint>> discoveredExtendedEndpoints, Set<Class<?>> discoveredAnnotatedEndpoints,
Set<Class<? extends ServerApplicationConfig>> serverAppConfigs)
{
for (Class<?> clazz : c)
{
if (ServerApplicationConfig.class.isAssignableFrom(clazz))
{
serverAppConfigs.add((Class<? extends ServerApplicationConfig>)clazz);
}
if (Endpoint.class.isAssignableFrom(clazz))
{
discoveredExtendedEndpoints.add((Class<? extends Endpoint>)clazz);
}
ServerEndpoint endpoint = clazz.getAnnotation(ServerEndpoint.class);
if (endpoint != null)
{
discoveredAnnotatedEndpoints.add(clazz);
}
}
}
}

View File

@ -1 +1 @@
org.eclipse.jetty.websocket.jsr356.server.deploy.ServerApplicationConfigListener
org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer

View File

@ -45,6 +45,7 @@ import org.eclipse.jetty.websocket.common.frames.TextFrame;
import org.eclipse.jetty.websocket.jsr356.server.blockhead.BlockheadClient;
import org.eclipse.jetty.websocket.jsr356.server.blockhead.HttpResponse;
import org.eclipse.jetty.websocket.jsr356.server.blockhead.IncomingFramesCapture;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
@ -144,7 +145,7 @@ public class ConfiguratorTest
context.setContextPath("/");
server.setHandler(context);
ServerContainer container = WebSocketConfiguration.configureContext(context);
ServerContainer container = WebSocketServerContainerInitializer.configureContext(context);
container.addEndpoint(CaptureHeadersSocket.class);
container.addEndpoint(EmptySocket.class);
container.addEndpoint(NoExtensionsSocket.class);

Some files were not shown because too many files have changed in this diff Show More