Merge branch 'jetty-7' into release-7
This commit is contained in:
commit
262019a5e1
|
@ -59,6 +59,11 @@
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||||
|
<artifactId>jetty-test-helper</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-jndi</artifactId>
|
<artifactId>jetty-jndi</artifactId>
|
||||||
|
|
|
@ -526,7 +526,7 @@ public class AnnotationParser
|
||||||
public void parse (Resource dir, ClassNameResolver resolver)
|
public void parse (Resource dir, ClassNameResolver resolver)
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
if (!dir.isDirectory() || !dir.exists())
|
if (!dir.isDirectory() || !dir.exists() || dir.getName().startsWith("."))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
@ -538,10 +538,14 @@ public class AnnotationParser
|
||||||
Resource res = dir.addPath(files[f]);
|
Resource res = dir.addPath(files[f]);
|
||||||
if (res.isDirectory())
|
if (res.isDirectory())
|
||||||
parse(res, resolver);
|
parse(res, resolver);
|
||||||
String name = res.getName();
|
else
|
||||||
if (name.endsWith(".class"))
|
|
||||||
{
|
{
|
||||||
if ((resolver == null)|| (!resolver.isExcluded(name) && (!isParsed(name) || resolver.shouldOverride(name))))
|
String fullname = res.getName();
|
||||||
|
String filename = res.getFile().getName();
|
||||||
|
|
||||||
|
if (isValidClassFileName(filename))
|
||||||
|
{
|
||||||
|
if ((resolver == null)|| (!resolver.isExcluded(fullname) && (!isParsed(fullname) || resolver.shouldOverride(fullname))))
|
||||||
{
|
{
|
||||||
Resource r = Resource.newResource(res.getURL());
|
Resource r = Resource.newResource(res.getURL());
|
||||||
scanClass(r.getInputStream());
|
scanClass(r.getInputStream());
|
||||||
|
@ -549,6 +553,7 @@ public class AnnotationParser
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LOG.warn(Log.EXCEPTION,ex);
|
LOG.warn(Log.EXCEPTION,ex);
|
||||||
|
@ -581,8 +586,12 @@ public class AnnotationParser
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
//skip directories
|
||||||
|
if (entry.isDirectory())
|
||||||
|
return;
|
||||||
|
|
||||||
String name = entry.getName();
|
String name = entry.getName();
|
||||||
if (name.toLowerCase(Locale.ENGLISH).endsWith(".class"))
|
if (isValidClassFilePath(name) && isValidClassFileName(name))
|
||||||
{
|
{
|
||||||
String shortName = name.replace('/', '.').substring(0,name.length()-6);
|
String shortName = name.replace('/', '.').substring(0,name.length()-6);
|
||||||
if ((resolver == null)
|
if ((resolver == null)
|
||||||
|
@ -625,8 +634,12 @@ public class AnnotationParser
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
//skip directories
|
||||||
|
if (entry.isDirectory())
|
||||||
|
return;
|
||||||
|
|
||||||
String name = entry.getName();
|
String name = entry.getName();
|
||||||
if (name.toLowerCase(Locale.ENGLISH).endsWith(".class"))
|
if (isValidClassFilePath(name) && isValidClassFileName(name))
|
||||||
{
|
{
|
||||||
String shortName = name.replace('/', '.').substring(0,name.length()-6);
|
String shortName = name.replace('/', '.').substring(0,name.length()-6);
|
||||||
|
|
||||||
|
@ -650,6 +663,14 @@ public class AnnotationParser
|
||||||
scanner.scan(null, uris, true);
|
scanner.scan(null, uris, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a single jar file for classes.
|
||||||
|
*
|
||||||
|
* @param uri
|
||||||
|
* @param resolver
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
public void parse (URI uri, final ClassNameResolver resolver)
|
public void parse (URI uri, final ClassNameResolver resolver)
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
|
@ -659,10 +680,79 @@ public class AnnotationParser
|
||||||
parse(uris, resolver);
|
parse(uris, resolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scan a class for annotations.
|
||||||
|
*
|
||||||
|
* @param is
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private void scanClass (InputStream is)
|
private void scanClass (InputStream is)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
ClassReader reader = new ClassReader(is);
|
ClassReader reader = new ClassReader(is);
|
||||||
reader.accept(new MyClassVisitor(), ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);
|
reader.accept(new MyClassVisitor(), ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that the given path represents a valid class file name.
|
||||||
|
* The check is fairly cursory, checking that:
|
||||||
|
* <ul>
|
||||||
|
* <li> the name ends with .class</li>
|
||||||
|
* <li> it isn't a dot file or in a hidden directory </li>
|
||||||
|
* <li> the name of the class at least begins with a valid identifier for a class name </li>
|
||||||
|
* </ul>
|
||||||
|
* @param path
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean isValidClassFileName (String name)
|
||||||
|
{
|
||||||
|
//no name cannot be valid
|
||||||
|
if (name == null || name.length()==0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//skip anything that is not a class file
|
||||||
|
if (!name.toLowerCase(Locale.ENGLISH).endsWith(".class"))
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled()) LOG.debug("Not a class: {}",name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//skip any classfiles that are not a valid java identifier
|
||||||
|
int c0 = 0;
|
||||||
|
int ldir = name.lastIndexOf('/', name.length()-6);
|
||||||
|
c0 = (ldir > -1 ? ldir+1 : c0);
|
||||||
|
if (!Character.isJavaIdentifierStart(name.charAt(c0)))
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled()) LOG.debug("Not a java identifier: {}"+name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that the given path does not contain hidden directories
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean isValidClassFilePath (String path)
|
||||||
|
{
|
||||||
|
//no path is not valid
|
||||||
|
if (path == null || path.length()==0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
|
||||||
|
//skip any classfiles that are in a hidden directory
|
||||||
|
if (path.startsWith(".") || path.contains("/."))
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled()) LOG.debug("Contains hidden dirs: {}"+path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,25 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.annotations;
|
package org.eclipse.jetty.annotations;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
|
import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
|
||||||
import org.eclipse.jetty.annotations.AnnotationParser.Value;
|
import org.eclipse.jetty.annotations.AnnotationParser.Value;
|
||||||
|
import org.eclipse.jetty.toolchain.test.FS;
|
||||||
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
|
import org.eclipse.jetty.toolchain.test.TestingDir;
|
||||||
|
import org.eclipse.jetty.util.IO;
|
||||||
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -31,6 +45,46 @@ import static org.junit.Assert.fail;
|
||||||
|
|
||||||
public class TestAnnotationParser
|
public class TestAnnotationParser
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TestingDir testdir = new TestingDir();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static class TrackingAnnotationHandler implements DiscoverableAnnotationHandler
|
||||||
|
{
|
||||||
|
public final Set<String> foundClasses;
|
||||||
|
|
||||||
|
public TrackingAnnotationHandler()
|
||||||
|
{
|
||||||
|
this.foundClasses = new HashSet<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
|
||||||
|
List<Value> values)
|
||||||
|
{
|
||||||
|
foundClasses.add(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void handleMethod(String className, String methodName, int access, String desc, String signature, String[] exceptions, String annotation,
|
||||||
|
List<Value> values)
|
||||||
|
{
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
|
||||||
|
List<Value> values)
|
||||||
|
{
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSampleAnnotation() throws Exception
|
public void testSampleAnnotation() throws Exception
|
||||||
{
|
{
|
||||||
|
@ -62,21 +116,6 @@ public class TestAnnotationParser
|
||||||
public void handleMethod(String className, String methodName, int access, String desc, String signature, String[] exceptions, String annotation,
|
public void handleMethod(String className, String methodName, int access, String desc, String signature, String[] exceptions, String annotation,
|
||||||
List<Value> values)
|
List<Value> values)
|
||||||
{
|
{
|
||||||
System.err.println("Sample annotated method : classname="+className+" methodName="+methodName+" access="+access+" desc="+desc+" signature="+signature);
|
|
||||||
|
|
||||||
org.objectweb.asm.Type retType = org.objectweb.asm.Type.getReturnType(desc);
|
|
||||||
System.err.println("REturn type = "+retType);
|
|
||||||
org.objectweb.asm.Type[] params = org.objectweb.asm.Type.getArgumentTypes(desc);
|
|
||||||
if (params == null)
|
|
||||||
System.err.println("No params");
|
|
||||||
else
|
|
||||||
System.err.println(params.length+" params");
|
|
||||||
|
|
||||||
if (exceptions == null)
|
|
||||||
System.err.println("No exceptions");
|
|
||||||
else
|
|
||||||
System.err.println(exceptions.length+" exceptions");
|
|
||||||
|
|
||||||
assertEquals("org.eclipse.jetty.annotations.ClassA", className);
|
assertEquals("org.eclipse.jetty.annotations.ClassA", className);
|
||||||
assertTrue(methods.contains(methodName));
|
assertTrue(methods.contains(methodName));
|
||||||
assertEquals("org.eclipse.jetty.annotations.Sample", annotation);
|
assertEquals("org.eclipse.jetty.annotations.Sample", annotation);
|
||||||
|
@ -100,8 +139,7 @@ public class TestAnnotationParser
|
||||||
|
|
||||||
});
|
});
|
||||||
long end = System.currentTimeMillis();
|
long end = System.currentTimeMillis();
|
||||||
|
//System.err.println("Time to parse class: "+((end-start)));
|
||||||
System.err.println("Time to parse class: "+((end-start)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -116,11 +154,6 @@ public class TestAnnotationParser
|
||||||
List<Value> values)
|
List<Value> values)
|
||||||
{
|
{
|
||||||
assertTrue("org.eclipse.jetty.annotations.ClassB".equals(className));
|
assertTrue("org.eclipse.jetty.annotations.ClassB".equals(className));
|
||||||
|
|
||||||
for (Value anv: values)
|
|
||||||
{
|
|
||||||
System.err.println(anv.toString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
|
public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
|
||||||
|
@ -135,14 +168,73 @@ public class TestAnnotationParser
|
||||||
{
|
{
|
||||||
assertTrue("org.eclipse.jetty.annotations.ClassB".equals(className));
|
assertTrue("org.eclipse.jetty.annotations.ClassB".equals(className));
|
||||||
assertTrue("a".equals(methodName));
|
assertTrue("a".equals(methodName));
|
||||||
for (Value anv: values)
|
|
||||||
{
|
|
||||||
System.err.println(anv.toString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.registerAnnotationHandler("org.eclipse.jetty.annotations.Multi", new MultiAnnotationHandler());
|
parser.registerAnnotationHandler("org.eclipse.jetty.annotations.Multi", new MultiAnnotationHandler());
|
||||||
parser.parse(classNames, null);
|
parser.parse(classNames, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHiddenFilesInJar () throws Exception
|
||||||
|
{
|
||||||
|
File badClassesJar = MavenTestingUtils.getTestResourceFile("bad-classes.jar");
|
||||||
|
AnnotationParser parser = new AnnotationParser();
|
||||||
|
parser.parse(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
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasedirExclusion() throws Exception
|
||||||
|
{
|
||||||
|
// Build up basedir, which itself has a path segment that violates java package and classnaming.
|
||||||
|
// The basedir should have no effect on annotation scanning.
|
||||||
|
// Intentionally using a base director name that starts with a "."
|
||||||
|
// This mimics what you see in jenkins, hudson, hadoop, solr, camel, and selenium for their
|
||||||
|
// installed and/or managed webapps
|
||||||
|
File basedir = testdir.getFile(".base/workspace/classes");
|
||||||
|
FS.ensureEmpty(basedir);
|
||||||
|
|
||||||
|
// Copy in class that is known to have annotations.
|
||||||
|
copyClass(ClassA.class,basedir);
|
||||||
|
|
||||||
|
// Setup Tracker
|
||||||
|
TrackingAnnotationHandler tracker = new TrackingAnnotationHandler();
|
||||||
|
|
||||||
|
// Setup annotation scanning
|
||||||
|
AnnotationParser parser = new AnnotationParser();
|
||||||
|
parser.registerAnnotationHandler(Sample.class.getName(), tracker);
|
||||||
|
|
||||||
|
// Parse
|
||||||
|
parser.parse(Resource.newResource(basedir),null);
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
assertTrue(tracker.foundClasses.contains(ClassA.class.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyClass(Class<?> clazz, File basedir) throws IOException
|
||||||
|
{
|
||||||
|
String classname = clazz.getName().replace('.',File.separatorChar) + ".class";
|
||||||
|
URL url = this.getClass().getResource('/'+classname);
|
||||||
|
assertTrue(url != null);
|
||||||
|
|
||||||
|
String classpath = classname.substring(0,classname.lastIndexOf(File.separatorChar));
|
||||||
|
FS.ensureDirExists(new File(basedir,classpath));
|
||||||
|
|
||||||
|
InputStream in = null;
|
||||||
|
OutputStream out = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
in = url.openStream();
|
||||||
|
out = new FileOutputStream(new File(basedir,classname));
|
||||||
|
IO.copy(in,out);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IO.close(out);
|
||||||
|
IO.close(in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -27,6 +27,7 @@ import org.eclipse.jetty.deploy.ConfigurationManager;
|
||||||
import org.eclipse.jetty.deploy.util.FileID;
|
import org.eclipse.jetty.deploy.util.FileID;
|
||||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
|
import org.eclipse.jetty.webapp.WebAppContext;
|
||||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||||
|
|
||||||
/** Context directory App Provider.
|
/** Context directory App Provider.
|
||||||
|
@ -37,6 +38,8 @@ import org.eclipse.jetty.xml.XmlConfiguration;
|
||||||
public class ContextProvider extends ScanningAppProvider
|
public class ContextProvider extends ScanningAppProvider
|
||||||
{
|
{
|
||||||
private ConfigurationManager _configurationManager;
|
private ConfigurationManager _configurationManager;
|
||||||
|
private boolean _parentLoaderPriority = false;
|
||||||
|
private String _defaultsDescriptor;
|
||||||
|
|
||||||
public ContextProvider()
|
public ContextProvider()
|
||||||
{
|
{
|
||||||
|
@ -79,7 +82,22 @@ public class ContextProvider extends ScanningAppProvider
|
||||||
|
|
||||||
if (resource.exists() && FileID.isXmlFile(file))
|
if (resource.exists() && FileID.isXmlFile(file))
|
||||||
{
|
{
|
||||||
XmlConfiguration xmlc = new XmlConfiguration(resource.getURL());
|
XmlConfiguration xmlc = new XmlConfiguration(resource.getURL())
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void initializeDefaults(Object context)
|
||||||
|
{
|
||||||
|
super.initializeDefaults(context);
|
||||||
|
|
||||||
|
if (context instanceof WebAppContext)
|
||||||
|
{
|
||||||
|
WebAppContext webapp = (WebAppContext)context;
|
||||||
|
webapp.setParentLoaderPriority(_parentLoaderPriority);
|
||||||
|
if (_defaultsDescriptor!=null)
|
||||||
|
webapp.setDefaultsDescriptor(_defaultsDescriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
xmlc.getIdMap().put("Server",getDeploymentManager().getServer());
|
xmlc.getIdMap().put("Server",getDeploymentManager().getServer());
|
||||||
if (getConfigurationManager() != null)
|
if (getConfigurationManager() != null)
|
||||||
|
@ -90,4 +108,43 @@ public class ContextProvider extends ScanningAppProvider
|
||||||
throw new IllegalStateException("App resouce does not exist "+resource);
|
throw new IllegalStateException("App resouce does not exist "+resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/** Get the parentLoaderPriority.
|
||||||
|
* @return the parentLoaderPriority
|
||||||
|
*/
|
||||||
|
public boolean isParentLoaderPriority()
|
||||||
|
{
|
||||||
|
return _parentLoaderPriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/** Set the parentLoaderPriority.
|
||||||
|
* <p>If the context created is a WebAppContext, then set the
|
||||||
|
* default value for {@link WebAppContext#setParentLoaderPriority(boolean)}.
|
||||||
|
* @param parentLoaderPriority the parentLoaderPriority to set
|
||||||
|
*/
|
||||||
|
public void setParentLoaderPriority(boolean parentLoaderPriority)
|
||||||
|
{
|
||||||
|
_parentLoaderPriority = parentLoaderPriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/** Get the defaultsDescriptor.
|
||||||
|
* @return the defaultsDescriptor
|
||||||
|
*/
|
||||||
|
public String getDefaultsDescriptor()
|
||||||
|
{
|
||||||
|
return _defaultsDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/** Set the defaultsDescriptor.
|
||||||
|
* <p>If the context created is a WebAppContext, then set the
|
||||||
|
* default value for {@link WebAppContext#setDefaultsDescriptor(String)}
|
||||||
|
* @param defaultsDescriptor the defaultsDescriptor to set
|
||||||
|
*/
|
||||||
|
public void setDefaultsDescriptor(String defaultsDescriptor)
|
||||||
|
{
|
||||||
|
_defaultsDescriptor = defaultsDescriptor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1079,11 +1079,14 @@ public class HttpGenerator extends AbstractGenerator
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
|
Buffer header=_header;
|
||||||
|
Buffer buffer=_buffer;
|
||||||
|
Buffer content=_content;
|
||||||
return String.format("%s{s=%d,h=%d,b=%d,c=%d}",
|
return String.format("%s{s=%d,h=%d,b=%d,c=%d}",
|
||||||
getClass().getSimpleName(),
|
getClass().getSimpleName(),
|
||||||
_state,
|
_state,
|
||||||
_header == null ? -1 : _header.length(),
|
header == null ? -1 : header.length(),
|
||||||
_buffer == null ? -1 : _buffer.length(),
|
buffer == null ? -1 : buffer.length(),
|
||||||
_content == null ? -1 : _content.length());
|
content == null ? -1 : content.length());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,16 +63,57 @@ public class NoSqlSession extends AbstractSession
|
||||||
{
|
{
|
||||||
synchronized (this)
|
synchronized (this)
|
||||||
{
|
{
|
||||||
if (_dirty==null)
|
|
||||||
_dirty=new HashSet<String>();
|
|
||||||
_dirty.add(name);
|
|
||||||
Object old = super.doPutOrRemove(name,value);
|
Object old = super.doPutOrRemove(name,value);
|
||||||
|
|
||||||
if (_manager.getSavePeriod()==-2)
|
if (_manager.getSavePeriod()==-2)
|
||||||
|
{
|
||||||
save(true);
|
save(true);
|
||||||
|
}
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAttribute(String name, Object value)
|
||||||
|
{
|
||||||
|
if ( updateAttribute(name,value) )
|
||||||
|
{
|
||||||
|
if (_dirty==null)
|
||||||
|
{
|
||||||
|
_dirty=new HashSet<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
_dirty.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* a boolean version of the setAttribute method that lets us manage the _dirty set
|
||||||
|
*/
|
||||||
|
protected boolean updateAttribute (String name, Object value)
|
||||||
|
{
|
||||||
|
Object old=null;
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
checkValid();
|
||||||
|
old=doPutOrRemove(name,value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value==null || !value.equals(old))
|
||||||
|
{
|
||||||
|
if (old!=null)
|
||||||
|
unbindValue(name,old);
|
||||||
|
if (value!=null)
|
||||||
|
bindValue(name,value);
|
||||||
|
|
||||||
|
_manager.doSessionAttributeListeners(this,name,old,value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
protected void checkValid() throws IllegalStateException
|
protected void checkValid() throws IllegalStateException
|
||||||
|
|
|
@ -20,11 +20,10 @@ package org.eclipse.jetty.plus.jaas.spi;
|
||||||
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import javax.security.auth.Subject;
|
import javax.security.auth.Subject;
|
||||||
import javax.security.auth.callback.CallbackHandler;
|
import javax.security.auth.callback.CallbackHandler;
|
||||||
|
@ -46,7 +45,7 @@ public class PropertyFileLoginModule extends AbstractLoginModule
|
||||||
|
|
||||||
private static final Logger LOG = Log.getLogger(PropertyFileLoginModule.class);
|
private static final Logger LOG = Log.getLogger(PropertyFileLoginModule.class);
|
||||||
|
|
||||||
private static Map<String, PropertyUserStore> _propertyUserStores = new HashMap<String, PropertyUserStore>();
|
private static ConcurrentHashMap<String, PropertyUserStore> _propertyUserStores = new ConcurrentHashMap<String, PropertyUserStore>();
|
||||||
|
|
||||||
private int _refreshInterval = 0;
|
private int _refreshInterval = 0;
|
||||||
private String _filename = DEFAULT_FILENAME;
|
private String _filename = DEFAULT_FILENAME;
|
||||||
|
@ -68,32 +67,36 @@ public class PropertyFileLoginModule extends AbstractLoginModule
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupPropertyUserStore(Map<String, ?> options)
|
private void setupPropertyUserStore(Map<String, ?> options)
|
||||||
{
|
|
||||||
if (_propertyUserStores.get(_filename) == null)
|
|
||||||
{
|
{
|
||||||
parseConfig(options);
|
parseConfig(options);
|
||||||
|
|
||||||
PropertyUserStore _propertyUserStore = new PropertyUserStore();
|
if (_propertyUserStores.get(_filename) == null)
|
||||||
_propertyUserStore.setConfig(_filename);
|
{
|
||||||
_propertyUserStore.setRefreshInterval(_refreshInterval);
|
PropertyUserStore propertyUserStore = new PropertyUserStore();
|
||||||
|
propertyUserStore.setConfig(_filename);
|
||||||
|
propertyUserStore.setRefreshInterval(_refreshInterval);
|
||||||
|
|
||||||
|
PropertyUserStore prev = _propertyUserStores.putIfAbsent(_filename, propertyUserStore);
|
||||||
|
if (prev == null)
|
||||||
|
{
|
||||||
LOG.debug("setupPropertyUserStore: Starting new PropertyUserStore. PropertiesFile: " + _filename + " refreshInterval: " + _refreshInterval);
|
LOG.debug("setupPropertyUserStore: Starting new PropertyUserStore. PropertiesFile: " + _filename + " refreshInterval: " + _refreshInterval);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_propertyUserStore.start();
|
propertyUserStore.start();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
LOG.warn("Exception while starting propertyUserStore: ",e);
|
LOG.warn("Exception while starting propertyUserStore: ",e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_propertyUserStores.put(_filename,_propertyUserStore);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseConfig(Map<String, ?> options)
|
private void parseConfig(Map<String, ?> options)
|
||||||
{
|
{
|
||||||
_filename = (String)options.get("file") != null?(String)options.get("file"):DEFAULT_FILENAME;
|
_filename = (String)options.get("file");
|
||||||
|
_filename = (_filename == null? DEFAULT_FILENAME : _filename);
|
||||||
String refreshIntervalString = (String)options.get("refreshInterval");
|
String refreshIntervalString = (String)options.get("refreshInterval");
|
||||||
_refreshInterval = refreshIntervalString == null?_refreshInterval:Integer.parseInt(refreshIntervalString);
|
_refreshInterval = refreshIntervalString == null?_refreshInterval:Integer.parseInt(refreshIntervalString);
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,8 @@ public class RequestLogHandler extends HandlerWrapper
|
||||||
super.handle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (_requestLog != null && baseRequest.getDispatcherType().equals(DispatcherType.REQUEST))
|
||||||
{
|
{
|
||||||
if (continuation.isAsync())
|
if (continuation.isAsync())
|
||||||
{
|
{
|
||||||
|
@ -90,6 +92,7 @@ public class RequestLogHandler extends HandlerWrapper
|
||||||
_requestLog.log(baseRequest, (Response)response);
|
_requestLog.log(baseRequest, (Response)response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public void setRequestLog(RequestLog requestLog)
|
public void setRequestLog(RequestLog requestLog)
|
||||||
|
|
|
@ -151,6 +151,7 @@ public class MultiPartFilter implements Filter
|
||||||
params.add(entry.getKey(),value);
|
params.add(entry.getKey(),value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean badFormatLogged = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Get first boundary
|
// Get first boundary
|
||||||
|
@ -160,7 +161,7 @@ public class MultiPartFilter implements Filter
|
||||||
throw new IOException("Missing content for multipart request");
|
throw new IOException("Missing content for multipart request");
|
||||||
|
|
||||||
line = line.trim();
|
line = line.trim();
|
||||||
boolean badFormatLogged = false;
|
|
||||||
while (line != null && !line.equals(boundary))
|
while (line != null && !line.equals(boundary))
|
||||||
{
|
{
|
||||||
if (!badFormatLogged)
|
if (!badFormatLogged)
|
||||||
|
@ -402,6 +403,12 @@ public class MultiPartFilter implements Filter
|
||||||
// handle request
|
// handle request
|
||||||
chain.doFilter(new Wrapper(srequest,params),response);
|
chain.doFilter(new Wrapper(srequest,params),response);
|
||||||
}
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
if (!badFormatLogged)
|
||||||
|
LOG.warn("Badly formatted multipart request");
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
deleteFiles(request);
|
deleteFiles(request);
|
||||||
|
|
|
@ -752,6 +752,38 @@ public class MultipartFilterTest
|
||||||
assertTrue(response.getContent().contains("aaaa,bbbbb"));
|
assertTrue(response.getContent().contains("aaaa,bbbbb"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBufferOverflowNoCRLF () throws Exception
|
||||||
|
{
|
||||||
|
String boundary="XyXyXy";
|
||||||
|
// generated and parsed test
|
||||||
|
HttpTester request = new HttpTester();
|
||||||
|
HttpTester response = new HttpTester();
|
||||||
|
tester.addServlet(BoundaryServlet.class,"/testb");
|
||||||
|
tester.setAttribute("fileName", "abc");
|
||||||
|
tester.setAttribute("desc", "123");
|
||||||
|
tester.setAttribute("title", "ttt");
|
||||||
|
request.setMethod("POST");
|
||||||
|
request.setVersion("HTTP/1.0");
|
||||||
|
request.setHeader("Host","tester");
|
||||||
|
request.setURI("/context/testb");
|
||||||
|
request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
|
||||||
|
|
||||||
|
String content = "--XyXyXy";
|
||||||
|
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
baos.write(content.getBytes());
|
||||||
|
|
||||||
|
for (int i=0; i< 8500; i++) //create content that will overrun default buffer size of BufferedInputStream
|
||||||
|
{
|
||||||
|
baos.write('a');
|
||||||
|
}
|
||||||
|
request.setContent(baos.toString());
|
||||||
|
|
||||||
|
response.parse(tester.getResponses(request.generate()));
|
||||||
|
assertTrue(response.getContent().contains("Buffer size exceeded"));
|
||||||
|
assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, response.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* see the testParameterMap test
|
* see the testParameterMap test
|
||||||
|
|
|
@ -18,6 +18,22 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.servlets;
|
package org.eclipse.jetty.servlets;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.http.HttpServlet;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
import org.eclipse.jetty.client.ContentExchange;
|
import org.eclipse.jetty.client.ContentExchange;
|
||||||
import org.eclipse.jetty.client.HttpClient;
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
@ -34,23 +50,9 @@ import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
import org.eclipse.jetty.util.IO;
|
import org.eclipse.jetty.util.IO;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
import org.hamcrest.core.Is;
|
|
||||||
import org.hamcrest.core.IsEqual;
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.ServletOutputStream;
|
|
||||||
import javax.servlet.http.HttpServlet;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
@ -138,7 +140,9 @@ public class ProxyServletTest
|
||||||
public void testBigDownloadWithSlowReader() throws Exception
|
public void testBigDownloadWithSlowReader() throws Exception
|
||||||
{
|
{
|
||||||
// Create a 6 MiB file
|
// Create a 6 MiB file
|
||||||
final File file = File.createTempFile("test_", null, MavenTestingUtils.getTargetTestingDir());
|
File targetTestingDir = MavenTestingUtils.getTargetTestingDir();
|
||||||
|
targetTestingDir.mkdir();
|
||||||
|
final File file = File.createTempFile("test_", null, targetTestingDir);
|
||||||
file.deleteOnExit();
|
file.deleteOnExit();
|
||||||
FileOutputStream fos = new FileOutputStream(file);
|
FileOutputStream fos = new FileOutputStream(file);
|
||||||
byte[] buffer = new byte[1024];
|
byte[] buffer = new byte[1024];
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hamcrest</groupId>
|
<groupId>org.hamcrest</groupId>
|
||||||
<artifactId>hamcrest-all</artifactId>
|
<artifactId>hamcrest-library</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hamcrest</groupId>
|
<groupId>org.hamcrest</groupId>
|
||||||
<artifactId>hamcrest-all</artifactId>
|
<artifactId>hamcrest-library</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -49,6 +49,10 @@ public class ReadLineInputStream extends BufferedInputStream
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int b=super.read();
|
int b=super.read();
|
||||||
|
|
||||||
|
if (markpos < 0)
|
||||||
|
throw new IOException("Buffer size exceeded: no line terminator");
|
||||||
|
|
||||||
if (b==-1)
|
if (b==-1)
|
||||||
{
|
{
|
||||||
int m=markpos;
|
int m=markpos;
|
||||||
|
|
|
@ -316,7 +316,9 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
||||||
if (jsp_file != null)
|
if (jsp_file != null)
|
||||||
{
|
{
|
||||||
holder.setForcedPath(jsp_file);
|
holder.setForcedPath(jsp_file);
|
||||||
holder.setClassName(jspServletClass); //only use our default instance
|
ServletHolder jsp=context.getServletHandler().getServlet("jsp");
|
||||||
|
if (jsp!=null)
|
||||||
|
holder.setClassName(jsp.getClassName());
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle load-on-startup
|
// handle load-on-startup
|
||||||
|
|
|
@ -87,7 +87,10 @@ public class WebInfConfiguration extends AbstractConfiguration
|
||||||
context.getMetaData().addContainerJar(Resource.newResource(uri));
|
context.getMetaData().addContainerJar(Resource.newResource(uri));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ClassLoader loader = context.getClassLoader();
|
ClassLoader loader = null;
|
||||||
|
if (context.getClassLoader() != null)
|
||||||
|
loader = context.getClassLoader().getParent();
|
||||||
|
|
||||||
while (loader != null && (loader instanceof URLClassLoader))
|
while (loader != null && (loader instanceof URLClassLoader))
|
||||||
{
|
{
|
||||||
URL[] urls = ((URLClassLoader)loader).getURLs();
|
URL[] urls = ((URLClassLoader)loader).getURLs();
|
||||||
|
|
|
@ -19,14 +19,16 @@
|
||||||
package org.eclipse.jetty.websocket;
|
package org.eclipse.jetty.websocket;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
import org.eclipse.jetty.io.Buffer;
|
import org.eclipse.jetty.io.Buffer;
|
||||||
import org.eclipse.jetty.io.EndPoint;
|
import org.eclipse.jetty.io.EndPoint;
|
||||||
import org.eclipse.jetty.io.EofException;
|
import org.eclipse.jetty.io.EofException;
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/**
|
||||||
/** WebSocketGenerator.
|
* WebSocketGenerator.
|
||||||
* This class generates websocket packets.
|
* This class generates websocket packets.
|
||||||
* It is fully synchronized because it is likely that async
|
* It is fully synchronized because it is likely that async
|
||||||
* threads will call the addMessage methods while other
|
* threads will call the addMessage methods while other
|
||||||
|
@ -34,20 +36,19 @@ import org.eclipse.jetty.io.EofException;
|
||||||
*/
|
*/
|
||||||
public class WebSocketGeneratorRFC6455 implements WebSocketGenerator
|
public class WebSocketGeneratorRFC6455 implements WebSocketGenerator
|
||||||
{
|
{
|
||||||
final private WebSocketBuffers _buffers;
|
private final Lock _lock = new ReentrantLock();
|
||||||
final private EndPoint _endp;
|
private final WebSocketBuffers _buffers;
|
||||||
private Buffer _buffer;
|
private final EndPoint _endp;
|
||||||
private final byte[] _mask = new byte[4];
|
private final byte[] _mask = new byte[4];
|
||||||
|
private final MaskGen _maskGen;
|
||||||
|
private Buffer _buffer;
|
||||||
private int _m;
|
private int _m;
|
||||||
private boolean _opsent;
|
private boolean _opsent;
|
||||||
private final MaskGen _maskGen;
|
|
||||||
private boolean _closed;
|
private boolean _closed;
|
||||||
|
|
||||||
public WebSocketGeneratorRFC6455(WebSocketBuffers buffers, EndPoint endp)
|
public WebSocketGeneratorRFC6455(WebSocketBuffers buffers, EndPoint endp)
|
||||||
{
|
{
|
||||||
_buffers=buffers;
|
this(buffers, endp, null);
|
||||||
_endp=endp;
|
|
||||||
_maskGen=null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebSocketGeneratorRFC6455(WebSocketBuffers buffers, EndPoint endp, MaskGen maskGen)
|
public WebSocketGeneratorRFC6455(WebSocketBuffers buffers, EndPoint endp, MaskGen maskGen)
|
||||||
|
@ -57,15 +58,24 @@ public class WebSocketGeneratorRFC6455 implements WebSocketGenerator
|
||||||
_maskGen = maskGen;
|
_maskGen = maskGen;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Buffer getBuffer()
|
public Buffer getBuffer()
|
||||||
|
{
|
||||||
|
_lock.lock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
return _buffer;
|
return _buffer;
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
public synchronized void addFrame(byte flags, byte opcode, byte[] content, int offset, int length) throws IOException
|
|
||||||
{
|
{
|
||||||
// System.err.printf("<< %s %s %s\n",TypeUtil.toHexString(flags),TypeUtil.toHexString(opcode),length);
|
_lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addFrame(byte flags, byte opcode, byte[] content, int offset, int length) throws IOException
|
||||||
|
{
|
||||||
|
_lock.lock();
|
||||||
|
try
|
||||||
|
{
|
||||||
if (_closed)
|
if (_closed)
|
||||||
throw new EofException("Closed");
|
throw new EofException("Closed");
|
||||||
if (opcode == WebSocketConnectionRFC6455.OP_CLOSE)
|
if (opcode == WebSocketConnectionRFC6455.OP_CLOSE)
|
||||||
|
@ -186,8 +196,18 @@ public class WebSocketGeneratorRFC6455 implements WebSocketGenerator
|
||||||
_buffer = null;
|
_buffer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized int flushBuffer() throws IOException
|
public int flushBuffer() throws IOException
|
||||||
|
{
|
||||||
|
if (!_lock.tryLock())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (!_endp.isOpen())
|
if (!_endp.isOpen())
|
||||||
throw new EofException();
|
throw new EofException();
|
||||||
|
@ -202,13 +222,23 @@ public class WebSocketGeneratorRFC6455 implements WebSocketGenerator
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized int flush() throws IOException
|
public int flush() throws IOException
|
||||||
|
{
|
||||||
|
if (!_lock.tryLock())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (_buffer == null)
|
if (_buffer == null)
|
||||||
return 0;
|
return 0;
|
||||||
int result = flushBuffer();
|
|
||||||
|
|
||||||
|
int result = flushBuffer();
|
||||||
if (!_endp.isBlocking())
|
if (!_endp.isBlocking())
|
||||||
{
|
{
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
|
@ -230,13 +260,29 @@ public class WebSocketGeneratorRFC6455 implements WebSocketGenerator
|
||||||
_buffer.compact();
|
_buffer.compact();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized boolean isBufferEmpty()
|
public boolean isBufferEmpty()
|
||||||
|
{
|
||||||
|
_lock.lock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
return _buffer == null || _buffer.length() == 0;
|
return _buffer == null || _buffer.length() == 0;
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void returnBuffer()
|
public void returnBuffer()
|
||||||
|
{
|
||||||
|
_lock.lock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (_buffer != null && _buffer.length() == 0)
|
if (_buffer != null && _buffer.length() == 0)
|
||||||
{
|
{
|
||||||
|
@ -244,6 +290,11 @@ public class WebSocketGeneratorRFC6455 implements WebSocketGenerator
|
||||||
_buffer = null;
|
_buffer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
package org.eclipse.jetty.xml;
|
package org.eclipse.jetty.xml;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A ConfigurationProcessor for non XmlConfiguration format files.
|
* A ConfigurationProcessor for non XmlConfiguration format files.
|
||||||
|
@ -32,7 +31,7 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
public interface ConfigurationProcessor
|
public interface ConfigurationProcessor
|
||||||
{
|
{
|
||||||
public void init(URL url, XmlParser.Node config, Map<String, Object> idMap, Map<String, String> properties);
|
public void init(URL url, XmlParser.Node root, XmlConfiguration configuration);
|
||||||
|
|
||||||
public Object configure( Object obj) throws Exception;
|
public Object configure( Object obj) throws Exception;
|
||||||
public Object configure() throws Exception;
|
public Object configure() throws Exception;
|
||||||
|
|
|
@ -227,7 +227,7 @@ public class XmlConfiguration
|
||||||
{
|
{
|
||||||
throw new IllegalArgumentException("Unknown XML tag:"+config.getTag());
|
throw new IllegalArgumentException("Unknown XML tag:"+config.getTag());
|
||||||
}
|
}
|
||||||
_processor.init(_url,config,_idMap, _propertyMap);
|
_processor.init(_url,config,this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -296,51 +296,63 @@ public class XmlConfiguration
|
||||||
return _processor.configure();
|
return _processor.configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/** Initialize a new Object defaults.
|
||||||
|
* <p>This method must be called by any {@link ConfigurationProcessor} when it
|
||||||
|
* creates a new instance of an object before configuring it, so that a derived
|
||||||
|
* XmlConfiguration class may inject default values.
|
||||||
|
* @param object
|
||||||
|
*/
|
||||||
|
public void initializeDefaults(Object object)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private static class JettyXmlConfiguration implements ConfigurationProcessor
|
private static class JettyXmlConfiguration implements ConfigurationProcessor
|
||||||
{
|
{
|
||||||
XmlParser.Node _config;
|
XmlParser.Node _root;
|
||||||
Map<String, Object> _idMap;
|
XmlConfiguration _configuration;
|
||||||
Map<String, String> _propertyMap;
|
|
||||||
|
|
||||||
public void init(URL url, XmlParser.Node config, Map<String, Object> idMap, Map<String, String> properties)
|
public void init(URL url, XmlParser.Node root, XmlConfiguration configuration)
|
||||||
{
|
{
|
||||||
_config=config;
|
_root=root;
|
||||||
_idMap=idMap;
|
_configuration=configuration;
|
||||||
_propertyMap=properties;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public Object configure(Object obj) throws Exception
|
public Object configure(Object obj) throws Exception
|
||||||
{
|
{
|
||||||
// Check the class of the object
|
// Check the class of the object
|
||||||
Class<?> oClass = nodeClass(_config);
|
Class<?> oClass = nodeClass(_root);
|
||||||
if (oClass != null && !oClass.isInstance(obj))
|
if (oClass != null && !oClass.isInstance(obj))
|
||||||
{
|
{
|
||||||
String loaders = (oClass.getClassLoader()==obj.getClass().getClassLoader())?"":"Object Class and type Class are from different loaders.";
|
String loaders = (oClass.getClassLoader()==obj.getClass().getClassLoader())?"":"Object Class and type Class are from different loaders.";
|
||||||
throw new IllegalArgumentException("Object of class '"+obj.getClass().getCanonicalName()+"' is not of type '" + oClass.getCanonicalName()+"'. "+loaders);
|
throw new IllegalArgumentException("Object of class '"+obj.getClass().getCanonicalName()+"' is not of type '" + oClass.getCanonicalName()+"'. "+loaders);
|
||||||
}
|
}
|
||||||
configure(obj,_config,0);
|
configure(obj,_root,0);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public Object configure() throws Exception
|
public Object configure() throws Exception
|
||||||
{
|
{
|
||||||
Class<?> oClass = nodeClass(_config);
|
Class<?> oClass = nodeClass(_root);
|
||||||
|
|
||||||
String id = _config.getAttribute("id");
|
String id = _root.getAttribute("id");
|
||||||
Object obj = id == null?null:_idMap.get(id);
|
Object obj = id == null?null:_configuration.getIdMap().get(id);
|
||||||
|
|
||||||
if (obj == null && oClass != null)
|
if (obj == null && oClass != null)
|
||||||
|
{
|
||||||
obj = oClass.newInstance();
|
obj = oClass.newInstance();
|
||||||
|
_configuration.initializeDefaults(obj);
|
||||||
|
}
|
||||||
|
|
||||||
if (oClass != null && !oClass.isInstance(obj))
|
if (oClass != null && !oClass.isInstance(obj))
|
||||||
throw new ClassCastException(oClass.toString());
|
throw new ClassCastException(oClass.toString());
|
||||||
|
|
||||||
configure(obj,_config,0);
|
configure(obj,_root,0);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,7 +380,7 @@ public class XmlConfiguration
|
||||||
{
|
{
|
||||||
String id = cfg.getAttribute("id");
|
String id = cfg.getAttribute("id");
|
||||||
if (id != null)
|
if (id != null)
|
||||||
_idMap.put(id,obj);
|
_configuration.getIdMap().put(id,obj);
|
||||||
|
|
||||||
for (; i < cfg.size(); i++)
|
for (; i < cfg.size(); i++)
|
||||||
{
|
{
|
||||||
|
@ -558,6 +570,7 @@ public class XmlConfiguration
|
||||||
}
|
}
|
||||||
Constructor<?> cons = sClass.getConstructor(vClass);
|
Constructor<?> cons = sClass.getConstructor(vClass);
|
||||||
arg[0] = cons.newInstance(arg);
|
arg[0] = cons.newInstance(arg);
|
||||||
|
_configuration.initializeDefaults(arg[0]);
|
||||||
set.invoke(obj,arg);
|
set.invoke(obj,arg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -675,7 +688,7 @@ public class XmlConfiguration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (id != null)
|
if (id != null)
|
||||||
_idMap.put(id,obj);
|
_configuration.getIdMap().put(id,obj);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -730,7 +743,7 @@ public class XmlConfiguration
|
||||||
{
|
{
|
||||||
Object n= TypeUtil.call(oClass,method,obj,arg);
|
Object n= TypeUtil.call(oClass,method,obj,arg);
|
||||||
if (id != null)
|
if (id != null)
|
||||||
_idMap.put(id,n);
|
_configuration.getIdMap().put(id,n);
|
||||||
configure(n,node,argi);
|
configure(n,node,argi);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
@ -792,6 +805,7 @@ public class XmlConfiguration
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
n = constructors[c].newInstance(arg);
|
n = constructors[c].newInstance(arg);
|
||||||
|
_configuration.initializeDefaults(n);
|
||||||
called = true;
|
called = true;
|
||||||
}
|
}
|
||||||
catch (IllegalAccessException e)
|
catch (IllegalAccessException e)
|
||||||
|
@ -809,7 +823,7 @@ public class XmlConfiguration
|
||||||
if (called)
|
if (called)
|
||||||
{
|
{
|
||||||
if (id != null)
|
if (id != null)
|
||||||
_idMap.put(id,n);
|
_configuration.getIdMap().put(id,n);
|
||||||
configure(n,node,argi);
|
configure(n,node,argi);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
@ -827,7 +841,7 @@ public class XmlConfiguration
|
||||||
private Object refObj(Object obj, XmlParser.Node node) throws Exception
|
private Object refObj(Object obj, XmlParser.Node node) throws Exception
|
||||||
{
|
{
|
||||||
String id = node.getAttribute("id");
|
String id = node.getAttribute("id");
|
||||||
obj = _idMap.get(id);
|
obj = _configuration.getIdMap().get(id);
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new IllegalStateException("No object for id=" + id);
|
throw new IllegalStateException("No object for id=" + id);
|
||||||
configure(obj,node,0);
|
configure(obj,node,0);
|
||||||
|
@ -870,12 +884,12 @@ public class XmlConfiguration
|
||||||
Object v = value(obj,item);
|
Object v = value(obj,item);
|
||||||
al = LazyList.add(al,(v == null && aClass.isPrimitive())?0:v);
|
al = LazyList.add(al,(v == null && aClass.isPrimitive())?0:v);
|
||||||
if (nid != null)
|
if (nid != null)
|
||||||
_idMap.put(nid,v);
|
_configuration.getIdMap().put(nid,v);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object array = LazyList.toArray(al,aClass);
|
Object array = LazyList.toArray(al,aClass);
|
||||||
if (id != null)
|
if (id != null)
|
||||||
_idMap.put(id,array);
|
_configuration.getIdMap().put(id,array);
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -889,7 +903,7 @@ public class XmlConfiguration
|
||||||
|
|
||||||
Map<Object, Object> map = new HashMap<Object, Object>();
|
Map<Object, Object> map = new HashMap<Object, Object>();
|
||||||
if (id != null)
|
if (id != null)
|
||||||
_idMap.put(id,map);
|
_configuration.getIdMap().put(id,map);
|
||||||
|
|
||||||
for (Object o : node)
|
for (Object o : node)
|
||||||
{
|
{
|
||||||
|
@ -925,9 +939,9 @@ public class XmlConfiguration
|
||||||
map.put(k,v);
|
map.put(k,v);
|
||||||
|
|
||||||
if (kid != null)
|
if (kid != null)
|
||||||
_idMap.put(kid,k);
|
_configuration.getIdMap().put(kid,k);
|
||||||
if (vid != null)
|
if (vid != null)
|
||||||
_idMap.put(vid,v);
|
_configuration.getIdMap().put(vid,v);
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
|
@ -947,12 +961,13 @@ public class XmlConfiguration
|
||||||
String name = node.getAttribute("name");
|
String name = node.getAttribute("name");
|
||||||
String defaultValue = node.getAttribute("default");
|
String defaultValue = node.getAttribute("default");
|
||||||
Object prop;
|
Object prop;
|
||||||
if (_propertyMap != null && _propertyMap.containsKey(name))
|
Map<String,String> property_map=_configuration.getProperties();
|
||||||
prop = _propertyMap.get(name);
|
if (property_map != null && property_map.containsKey(name))
|
||||||
|
prop = property_map.get(name);
|
||||||
else
|
else
|
||||||
prop = defaultValue;
|
prop = defaultValue;
|
||||||
if (id != null)
|
if (id != null)
|
||||||
_idMap.put(id,prop);
|
_configuration.getIdMap().put(id,prop);
|
||||||
if (prop != null)
|
if (prop != null)
|
||||||
configure(prop,node,0);
|
configure(prop,node,0);
|
||||||
return prop;
|
return prop;
|
||||||
|
@ -975,7 +990,7 @@ public class XmlConfiguration
|
||||||
String ref = node.getAttribute("ref");
|
String ref = node.getAttribute("ref");
|
||||||
if (ref != null)
|
if (ref != null)
|
||||||
{
|
{
|
||||||
value = _idMap.get(ref);
|
value = _configuration.getIdMap().get(ref);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,6 +34,7 @@ public class TestConfiguration extends HashMap<String,Object>
|
||||||
public static int VALUE=77;
|
public static int VALUE=77;
|
||||||
|
|
||||||
public TestConfiguration nested;
|
public TestConfiguration nested;
|
||||||
|
public String testString="default";
|
||||||
public Object testObject;
|
public Object testObject;
|
||||||
public int testInt;
|
public int testInt;
|
||||||
public URL url;
|
public URL url;
|
||||||
|
@ -65,6 +66,25 @@ public class TestConfiguration extends HashMap<String,Object>
|
||||||
propValue=value;
|
propValue=value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TestConfiguration getNested()
|
||||||
|
{
|
||||||
|
return nested;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNested(TestConfiguration nested)
|
||||||
|
{
|
||||||
|
this.nested = nested;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTestString()
|
||||||
|
{
|
||||||
|
return testString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTestString(String testString)
|
||||||
|
{
|
||||||
|
this.testString = testString;
|
||||||
|
}
|
||||||
|
|
||||||
public void call()
|
public void call()
|
||||||
{
|
{
|
||||||
|
@ -73,7 +93,6 @@ public class TestConfiguration extends HashMap<String,Object>
|
||||||
|
|
||||||
public TestConfiguration call(Boolean b)
|
public TestConfiguration call(Boolean b)
|
||||||
{
|
{
|
||||||
nested=new TestConfiguration();
|
|
||||||
nested.put("Arg",b);
|
nested.put("Arg",b);
|
||||||
return nested;
|
return nested;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,11 +21,12 @@ package org.eclipse.jetty.xml;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static junit.framework.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.CoreMatchers.not;
|
import static org.hamcrest.CoreMatchers.not;
|
||||||
import static org.hamcrest.CoreMatchers.nullValue;
|
import static org.hamcrest.CoreMatchers.nullValue;
|
||||||
|
@ -127,10 +128,28 @@ public class XmlConfigurationTest
|
||||||
properties.put("whatever", "xxx");
|
properties.put("whatever", "xxx");
|
||||||
|
|
||||||
URL url = XmlConfigurationTest.class.getClassLoader().getResource(_configure);
|
URL url = XmlConfigurationTest.class.getClassLoader().getResource(_configure);
|
||||||
XmlConfiguration configuration = new XmlConfiguration(url);
|
final AtomicInteger count = new AtomicInteger(0);
|
||||||
|
XmlConfiguration configuration = new XmlConfiguration(url)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void initializeDefaults(Object object)
|
||||||
|
{
|
||||||
|
if (object instanceof TestConfiguration)
|
||||||
|
{
|
||||||
|
count.incrementAndGet();
|
||||||
|
((TestConfiguration)object).setNested(null);
|
||||||
|
((TestConfiguration)object).setTestString("NEW DEFAULT");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
configuration.getProperties().putAll(properties);
|
configuration.getProperties().putAll(properties);
|
||||||
TestConfiguration tc = (TestConfiguration)configuration.configure();
|
TestConfiguration tc = (TestConfiguration)configuration.configure();
|
||||||
|
|
||||||
|
assertEquals(3,count.get());
|
||||||
|
assertEquals("NEW DEFAULT",tc.getTestString());
|
||||||
|
assertEquals("nested",tc.getNested().getTestString());
|
||||||
|
assertEquals("NEW DEFAULT",tc.getNested().getNested().getTestString());
|
||||||
|
|
||||||
assertEquals("Set String","SetValue",tc.testObject);
|
assertEquals("Set String","SetValue",tc.testObject);
|
||||||
assertEquals("Set Type",2,tc.testInt);
|
assertEquals("Set Type",2,tc.testInt);
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,16 @@
|
||||||
<Put name="Float" type="Float">2.3</Put>
|
<Put name="Float" type="Float">2.3</Put>
|
||||||
<Put name="Env"><Env name="HOME"/></Put>
|
<Put name="Env"><Env name="HOME"/></Put>
|
||||||
|
|
||||||
|
<Set name="nested">
|
||||||
|
<New class="org.eclipse.jetty.xml.TestConfiguration">
|
||||||
|
<Set name="testString">nested</Set>
|
||||||
|
<Set name="nested">
|
||||||
|
<New class="org.eclipse.jetty.xml.TestConfiguration">
|
||||||
|
</New>
|
||||||
|
</Set>
|
||||||
|
</New>
|
||||||
|
</Set>
|
||||||
|
|
||||||
<Call name="call">
|
<Call name="call">
|
||||||
</Call>
|
</Call>
|
||||||
|
|
||||||
|
|
15
pom.xml
15
pom.xml
|
@ -508,7 +508,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||||
<artifactId>jetty-test-helper</artifactId>
|
<artifactId>jetty-test-helper</artifactId>
|
||||||
<version>2.0</version>
|
<version>2.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
|
@ -528,17 +528,22 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>4.8.1</version>
|
<version>4.11</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hamcrest</groupId>
|
<groupId>org.hamcrest</groupId>
|
||||||
<artifactId>hamcrest-all</artifactId>
|
<artifactId>hamcrest-core</artifactId>
|
||||||
<version>1.1</version>
|
<version>1.3</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hamcrest</groupId>
|
||||||
|
<artifactId>hamcrest-library</artifactId>
|
||||||
|
<version>1.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mockito</groupId>
|
<groupId>org.mockito</groupId>
|
||||||
<artifactId>mockito-core</artifactId>
|
<artifactId>mockito-core</artifactId>
|
||||||
<version>1.8.5</version>
|
<version>1.9.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
|
@ -99,7 +99,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.mortbay.jetty</groupId>
|
<groupId>org.mortbay.jetty</groupId>
|
||||||
<artifactId>jetty-maven-plugin</artifactId>
|
<artifactId>jetty-maven-plugin</artifactId>
|
||||||
<version>7.5.2-SNAPSHOT</version>
|
<version>${project.version}</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<stopPort>8087</stopPort>
|
<stopPort>8087</stopPort>
|
||||||
<stopKey>foo</stopKey>
|
<stopKey>foo</stopKey>
|
||||||
|
|
|
@ -18,21 +18,18 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.test.monitor;
|
package org.eclipse.jetty.test.monitor;
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.management.MBeanServerConnection;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.client.ContentExchange;
|
import org.eclipse.jetty.client.ContentExchange;
|
||||||
import org.eclipse.jetty.client.HttpClient;
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
import org.eclipse.jetty.http.HttpMethods;
|
import org.eclipse.jetty.http.HttpMethods;
|
||||||
import org.eclipse.jetty.http.HttpStatus;
|
import org.eclipse.jetty.http.HttpStatus;
|
||||||
import org.eclipse.jetty.monitor.JMXMonitor;
|
import org.eclipse.jetty.monitor.JMXMonitor;
|
||||||
import org.eclipse.jetty.toolchain.jmx.JmxServiceConnection;
|
import org.eclipse.jetty.test.support.JettyDistro;
|
||||||
import org.eclipse.jetty.toolchain.test.JettyDistro;
|
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
|
|
|
@ -18,15 +18,13 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.test.monitor;
|
package org.eclipse.jetty.test.monitor;
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
import javax.management.MBeanServerConnection;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.client.ContentExchange;
|
import org.eclipse.jetty.client.ContentExchange;
|
||||||
import org.eclipse.jetty.client.HttpClient;
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
import org.eclipse.jetty.http.HttpMethods;
|
import org.eclipse.jetty.http.HttpMethods;
|
||||||
|
@ -40,8 +38,7 @@ import org.eclipse.jetty.monitor.jmx.MonitorAction;
|
||||||
import org.eclipse.jetty.monitor.triggers.GreaterThanAttrEventTrigger;
|
import org.eclipse.jetty.monitor.triggers.GreaterThanAttrEventTrigger;
|
||||||
import org.eclipse.jetty.monitor.triggers.LessThanOrEqualToAttrEventTrigger;
|
import org.eclipse.jetty.monitor.triggers.LessThanOrEqualToAttrEventTrigger;
|
||||||
import org.eclipse.jetty.monitor.triggers.OrEventTrigger;
|
import org.eclipse.jetty.monitor.triggers.OrEventTrigger;
|
||||||
import org.eclipse.jetty.toolchain.jmx.JmxServiceConnection;
|
import org.eclipse.jetty.test.support.JettyDistro;
|
||||||
import org.eclipse.jetty.toolchain.test.JettyDistro;
|
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
|
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.test.monitor;
|
package org.eclipse.jetty.test.monitor;
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
@ -30,7 +30,7 @@ import org.eclipse.jetty.client.HttpClient;
|
||||||
import org.eclipse.jetty.http.HttpMethods;
|
import org.eclipse.jetty.http.HttpMethods;
|
||||||
import org.eclipse.jetty.http.HttpStatus;
|
import org.eclipse.jetty.http.HttpStatus;
|
||||||
import org.eclipse.jetty.monitor.JMXMonitor;
|
import org.eclipse.jetty.monitor.JMXMonitor;
|
||||||
import org.eclipse.jetty.toolchain.test.JettyDistro;
|
import org.eclipse.jetty.test.support.JettyDistro;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
|
|
|
@ -0,0 +1,874 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// 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.test.support;
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
//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.
|
||||||
|
//========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.toolchain.test.FS;
|
||||||
|
import org.eclipse.jetty.toolchain.test.IO;
|
||||||
|
import org.eclipse.jetty.toolchain.test.JAR;
|
||||||
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
|
import org.eclipse.jetty.toolchain.test.OS;
|
||||||
|
import org.eclipse.jetty.toolchain.test.PathAssert;
|
||||||
|
import org.eclipse.jetty.toolchain.test.TestingDir;
|
||||||
|
import org.junit.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic process based executor for using the Jetty Distribution along with custom configurations to perform basic
|
||||||
|
* <p>
|
||||||
|
* Allows for a test specific directory, that is a copied jetty-distribution, and then modified for the test specific testing required.
|
||||||
|
* <p>
|
||||||
|
* Requires that you setup the maven-dependency-plugin appropriately for the base distribution you want to use, along with any other dependencies (wars, libs,
|
||||||
|
* etc..) that you may need from other maven projects.
|
||||||
|
* <p>
|
||||||
|
* Maven Dependency Plugin Setup:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
* xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
*
|
||||||
|
* <!-- Common Destination Directories -->
|
||||||
|
*
|
||||||
|
* <properties>
|
||||||
|
* <test-wars-dir>${project.build.directory}/test-wars</test-wars-dir>
|
||||||
|
* <test-libs-dir>${project.build.directory}/test-libs</test-libs-dir>
|
||||||
|
* <test-distro-dir>${project.build.directory}/test-dist</test-distro-dir>
|
||||||
|
* </properties>
|
||||||
|
*
|
||||||
|
* <build>
|
||||||
|
* <plugins>
|
||||||
|
* <plugin>
|
||||||
|
* <groupId>org.apache.maven.plugins</groupId>
|
||||||
|
* <artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
* <version>2.1</version>
|
||||||
|
* <executions>
|
||||||
|
*
|
||||||
|
* <!-- Copy LIB and WAR dependencies into place that JettyDistro can use them -->
|
||||||
|
*
|
||||||
|
* <execution>
|
||||||
|
* <id>test-lib-war-copy</id>
|
||||||
|
* <phase>process-test-resources</phase>
|
||||||
|
* <goals>
|
||||||
|
* <goal>copy</goal>
|
||||||
|
* </goals>
|
||||||
|
* <configuration>
|
||||||
|
* <artifactItems>
|
||||||
|
* <artifactItem>
|
||||||
|
* <groupId>org.mortbay.jetty.testwars</groupId>
|
||||||
|
* <artifactId>test-war-java_util_logging</artifactId>
|
||||||
|
* <version>7.3.0</version>
|
||||||
|
* <type>war</type>
|
||||||
|
* <outputDirectory>${test-wars-dir}</outputDirectory>
|
||||||
|
* </artifactItem>
|
||||||
|
* <artifactItem>
|
||||||
|
* <groupId>org.mortbay.jetty</groupId>
|
||||||
|
* <artifactId>jetty-aspect-servlet-api-2.5</artifactId>
|
||||||
|
* <version>7.3.0</version>
|
||||||
|
* <type>jar</type>
|
||||||
|
* <outputDirectory>${test-libs-dir}</outputDirectory>
|
||||||
|
* </artifactItem>
|
||||||
|
* </artifactItems>
|
||||||
|
* <overWriteIfNewer>true</overWriteIfNewer>
|
||||||
|
* <overWrite>true</overWrite>
|
||||||
|
* <stripVersion>true</stripVersion>
|
||||||
|
* </configuration>
|
||||||
|
* </execution>
|
||||||
|
*
|
||||||
|
* <!-- Extract Jetty DISTRIBUTION into place that JettyDistro can use it -->
|
||||||
|
*
|
||||||
|
* <execution>
|
||||||
|
* <id>unpack-test-dist</id>
|
||||||
|
* <phase>process-test-resources</phase>
|
||||||
|
* <goals>
|
||||||
|
* <goal>unpack</goal>
|
||||||
|
* </goals>
|
||||||
|
* <configuration>
|
||||||
|
* <artifactItems>
|
||||||
|
* <artifactItem>
|
||||||
|
* <groupId>org.eclipse.jetty</groupId>
|
||||||
|
* <artifactId>jetty-distribution</artifactId>
|
||||||
|
* <version>7.3.0</version>
|
||||||
|
* <type>zip</type>
|
||||||
|
* <overWrite>true</overWrite>
|
||||||
|
* </artifactItem>
|
||||||
|
* </artifactItems>
|
||||||
|
* <outputAbsoluteArtifactFilename>true</outputAbsoluteArtifactFilename>
|
||||||
|
* <outputDirectory>${test-distro-dir}</outputDirectory>
|
||||||
|
* <overWriteSnapshots>true</overWriteSnapshots>
|
||||||
|
* <overWriteIfNewer>true</overWriteIfNewer>
|
||||||
|
* </configuration>
|
||||||
|
* </execution>
|
||||||
|
* </executions>
|
||||||
|
* </plugin>
|
||||||
|
* </plugins>
|
||||||
|
* </build>
|
||||||
|
*
|
||||||
|
* </project>
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* If you have a specific configuration you want to setup, you'll want to prepare this configuration in an overlay directory underneath the
|
||||||
|
* <code>src/test/resources/</code> directory. <br>
|
||||||
|
* Notes:
|
||||||
|
* <ol>
|
||||||
|
* <li>The {@link JettyDistro} sets up a unique test directory (based on the constructor {@link #JettyDistro(Class)} or {@link #JettyDistro(TestingDir)}), by
|
||||||
|
* ensuring the directory is empty, then copying the <code>target/test-dist</code> directory into this new testing directory prior to the test specific changes
|
||||||
|
* to the configuration.<br>
|
||||||
|
* Note: this testing directory is a complete jetty distribution, suitable for executing via the command line for additional testing needs.</li>
|
||||||
|
* <li>The directory name you choose in <code>src/test/resources</code> will be the name you use in the {@link #overlayConfig(String)} method to provide
|
||||||
|
* replacement configurations for the Jetty Distribution.</li>
|
||||||
|
* <li>You'll want to {@link #delete(String)} any files and/or directories from the standard distribution prior to using the {@link #overlayConfig(String)}
|
||||||
|
* method.</li>
|
||||||
|
* <li>Use the {@link #copyLib(String, String)} method to copy JAR files from the <code>target/test-libs</code> directory (created and managed above using the
|
||||||
|
* <code>maven-dependency-plugin</code>) to copy the lib into the test specific.</li>
|
||||||
|
* <li>Use the {@link #copyTestWar(String)} method to copy WAR files from the <code>target/test-wars</code> directory (created and managed above using the
|
||||||
|
* <code>maven-dependency-plugin</code>) to copy the WAR into the test specific directory.</li>
|
||||||
|
* </ol>
|
||||||
|
* <p>
|
||||||
|
* Next you'll want to use Junit 4.8+ and the <code>@BeforeClass</code> and <code>@AfterClass</code> annotations to setup the <code>JettyDistro</code>
|
||||||
|
* class for setting up your testing configuration.
|
||||||
|
* <p>
|
||||||
|
* Example Test Case using {@link JettyDistro} class
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* public class MySampleTest
|
||||||
|
* {
|
||||||
|
* private static JettyDistro jetty;
|
||||||
|
*
|
||||||
|
* @BeforeClass
|
||||||
|
* public static void initJetty() throws Exception
|
||||||
|
* {
|
||||||
|
* jetty = new JettyDistro(MySampleTest.class);
|
||||||
|
*
|
||||||
|
* jetty.copyTestWar("test-war-java_util_logging.war");
|
||||||
|
* jetty.copyTestWar("test-war-policy.war");
|
||||||
|
*
|
||||||
|
* jetty.delete("webapps/test.war");
|
||||||
|
* jetty.delete("contexts/test.d");
|
||||||
|
* jetty.delete("contexts/javadoc.xml");
|
||||||
|
* jetty.delete("contexts/test.xml");
|
||||||
|
*
|
||||||
|
* jetty.overlayConfig("no_security");
|
||||||
|
*
|
||||||
|
* jetty.setDebug(true);
|
||||||
|
*
|
||||||
|
* jetty.start();
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @AfterClass
|
||||||
|
* public static void shutdownJetty() throws Exception
|
||||||
|
* {
|
||||||
|
* if (jetty != null)
|
||||||
|
* {
|
||||||
|
* jetty.stop();
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @Test
|
||||||
|
* public void testRequest() throws Exception
|
||||||
|
* {
|
||||||
|
* SimpleRequest request = new SimpleRequest(jetty.getBaseUri());
|
||||||
|
* String path = "/test-war-policy/security/PRACTICAL/testFilsystem");
|
||||||
|
* String response = request.getString(path);
|
||||||
|
* Assert.assertEquals("Success", response);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public class JettyDistro
|
||||||
|
{
|
||||||
|
private String artifactName = "jetty-distribution";
|
||||||
|
private long startTime = 60;
|
||||||
|
private TimeUnit timeUnit = TimeUnit.SECONDS;
|
||||||
|
|
||||||
|
private File jettyHomeDir;
|
||||||
|
private Process pid;
|
||||||
|
private URI baseUri;
|
||||||
|
|
||||||
|
private String jmxUrl;
|
||||||
|
|
||||||
|
private boolean _debug = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the JettyHome as belonging in a testing directory associated with a testing clazz.
|
||||||
|
*
|
||||||
|
* @param clazz
|
||||||
|
* the testing class using this JettyDistro
|
||||||
|
* @throws IOException
|
||||||
|
* if unable to copy unpacked distribution into place for the provided testing directory
|
||||||
|
*/
|
||||||
|
public JettyDistro(Class<?> clazz) throws IOException
|
||||||
|
{
|
||||||
|
this(clazz,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the JettyHome as belonging in a testing directory associated with a testing clazz.
|
||||||
|
*
|
||||||
|
* @param clazz
|
||||||
|
* the testing class using this JettyDistro
|
||||||
|
* @param artifact
|
||||||
|
* name of jetty distribution artifact
|
||||||
|
* @throws IOException
|
||||||
|
* if unable to copy unpacked distribution into place for the provided testing directory
|
||||||
|
*/
|
||||||
|
public JettyDistro(Class<?> clazz, String artifact) throws IOException
|
||||||
|
{
|
||||||
|
this.jettyHomeDir = MavenTestingUtils.getTargetTestingDir(clazz,"jettyHome");
|
||||||
|
if (artifact != null)
|
||||||
|
{
|
||||||
|
this.artifactName = artifact;
|
||||||
|
}
|
||||||
|
|
||||||
|
copyBaseDistro();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the JettyHome as belonging to a specific testing method directory
|
||||||
|
*
|
||||||
|
* @param testdir
|
||||||
|
* the testing directory to use as the JettyHome for this JettyDistro
|
||||||
|
* @throws IOException
|
||||||
|
* if unable to copy unpacked distribution into place for the provided testing directory
|
||||||
|
*/
|
||||||
|
public JettyDistro(TestingDir testdir) throws IOException
|
||||||
|
{
|
||||||
|
this.jettyHomeDir = testdir.getDir();
|
||||||
|
copyBaseDistro();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the JettyHome as belonging to a specific testing method directory
|
||||||
|
*
|
||||||
|
* @param testdir
|
||||||
|
* the testing directory to use as the JettyHome for this JettyDistro
|
||||||
|
* @param artifact
|
||||||
|
* name of jetty distribution artifact
|
||||||
|
* @throws IOException
|
||||||
|
* if unable to copy unpacked distribution into place for the provided testing directory
|
||||||
|
*/
|
||||||
|
public JettyDistro(TestingDir testdir, String artifact) throws IOException
|
||||||
|
{
|
||||||
|
this.jettyHomeDir = testdir.getDir();
|
||||||
|
if (artifact != null)
|
||||||
|
{
|
||||||
|
this.artifactName = artifact;
|
||||||
|
}
|
||||||
|
|
||||||
|
copyBaseDistro();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* if unable to copy unpacked distribution into place for the provided testing directory
|
||||||
|
*/
|
||||||
|
private void copyBaseDistro() throws IOException
|
||||||
|
{
|
||||||
|
// The outputDirectory for the maven side dependency:unpack goal.
|
||||||
|
File distroUnpackDir = MavenTestingUtils.getTargetFile("test-dist");
|
||||||
|
PathAssert.assertDirExists(artifactName + " dependency:unpack",distroUnpackDir);
|
||||||
|
|
||||||
|
// The actual jetty-distribution-${version} directory is under this directory.
|
||||||
|
// Lets find it.
|
||||||
|
File subdirs[] = distroUnpackDir.listFiles(new FileFilter()
|
||||||
|
{
|
||||||
|
public boolean accept(File path)
|
||||||
|
{
|
||||||
|
if (!path.isDirectory())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.getName().startsWith(artifactName + "-");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (subdirs.length == 0)
|
||||||
|
{
|
||||||
|
// No jetty-distribution found.
|
||||||
|
StringBuilder err = new StringBuilder();
|
||||||
|
err.append("No target/test-dist/");
|
||||||
|
err.append(artifactName);
|
||||||
|
err.append("-${version} directory found.");
|
||||||
|
err.append("\n To fix this, run 'mvn process-test-resources' to create the directory.");
|
||||||
|
throw new IOException(err.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subdirs.length != 1)
|
||||||
|
{
|
||||||
|
// Too many jetty-distributions found.
|
||||||
|
StringBuilder err = new StringBuilder();
|
||||||
|
err.append("Too many target/test-dist/");
|
||||||
|
err.append(artifactName);
|
||||||
|
err.append("-${version} directories found.");
|
||||||
|
for (File dir : subdirs)
|
||||||
|
{
|
||||||
|
err.append("\n ").append(dir.getAbsolutePath());
|
||||||
|
}
|
||||||
|
err.append("\n To fix this, run 'mvn clean process-test-resources' to recreate the target/test-dist directory.");
|
||||||
|
throw new IOException(err.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
File distroSrcDir = subdirs[0];
|
||||||
|
FS.ensureEmpty(jettyHomeDir);
|
||||||
|
System.out.printf("Copying Jetty Distribution: %s%n",distroSrcDir.getAbsolutePath());
|
||||||
|
System.out.printf(" To Testing Dir: %s%n",jettyHomeDir.getAbsolutePath());
|
||||||
|
IO.copyDir(distroSrcDir,jettyHomeDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the $(jetty.home) directory being used for this JettyDistro
|
||||||
|
*
|
||||||
|
* @return the jetty.home directory being used
|
||||||
|
*/
|
||||||
|
public File getJettyHomeDir()
|
||||||
|
{
|
||||||
|
return this.jettyHomeDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy a war file from ${project.basedir}/target/test-wars/${testWarFilename} into the ${jetty.home}/webapps/ directory
|
||||||
|
*
|
||||||
|
* @param testWarFilename
|
||||||
|
* the war file to copy (must exist)
|
||||||
|
* @throws IOException
|
||||||
|
* if unable to copy the war file.
|
||||||
|
*/
|
||||||
|
public void copyTestWar(String testWarFilename) throws IOException
|
||||||
|
{
|
||||||
|
File srcWar = MavenTestingUtils.getTargetFile("test-wars/" + testWarFilename);
|
||||||
|
File destWar = new File(jettyHomeDir,OS.separators("webapps/" + testWarFilename));
|
||||||
|
FS.ensureDirExists(destWar.getParentFile());
|
||||||
|
IO.copyFile(srcWar,destWar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy an arbitrary file from <code>src/test/resources/${resourcePath}</code> to the testing directory.
|
||||||
|
*
|
||||||
|
* @param resourcePath
|
||||||
|
* the relative path for file content within the <code>src/test/resources</code> directory.
|
||||||
|
* @param outputPath
|
||||||
|
* the testing directory relative output path for the file output (will result in a file with the outputPath name being created)
|
||||||
|
* @throws IOException
|
||||||
|
* if unable to copy resource file
|
||||||
|
*/
|
||||||
|
public void copyResource(String resourcePath, String outputPath) throws IOException
|
||||||
|
{
|
||||||
|
File srcFile = MavenTestingUtils.getTestResourceFile(resourcePath);
|
||||||
|
File destFile = new File(jettyHomeDir,OS.separators(outputPath));
|
||||||
|
FS.ensureDirExists(destFile.getParentFile());
|
||||||
|
IO.copyFile(srcFile,destFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy an arbitrary file from <code>target/test-libs/${libFilename}</code> to the testing directory.
|
||||||
|
*
|
||||||
|
* @param libFilename
|
||||||
|
* the <code>target/test-libs/${libFilename}</code> to copy
|
||||||
|
* @param outputPath
|
||||||
|
* the destination testing directory relative output path for the lib. (will result in a file with the outputPath name being created)
|
||||||
|
* @throws IOException
|
||||||
|
* if unable to copy lib
|
||||||
|
*/
|
||||||
|
public void copyLib(String libFilename, String outputPath) throws IOException
|
||||||
|
{
|
||||||
|
File srcLib = MavenTestingUtils.getTargetFile("test-libs/" + libFilename);
|
||||||
|
File destLib = new File(jettyHomeDir,OS.separators(outputPath));
|
||||||
|
FS.ensureDirExists(destLib.getParentFile());
|
||||||
|
IO.copyFile(srcLib,destLib);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the <code>${project.basedir}/src/main/config/</code> tree into the testing directory.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* if unable to copy the directory tree
|
||||||
|
*/
|
||||||
|
public void copyProjectMainConfig() throws IOException
|
||||||
|
{
|
||||||
|
File srcDir = MavenTestingUtils.getProjectDir("src/main/config");
|
||||||
|
IO.copyDir(srcDir,jettyHomeDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a <code>${jetty.home}/lib/self/${jarFilename}</code> jar file from the content in the <code>${project.basedir}/target/classes/</code> directory.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* if unable to copy the directory tree
|
||||||
|
*/
|
||||||
|
public void createProjectLib(String jarFilename) throws IOException
|
||||||
|
{
|
||||||
|
File srcDir = MavenTestingUtils.getTargetFile("classes");
|
||||||
|
File libSelfDir = new File(jettyHomeDir,OS.separators("lib/self"));
|
||||||
|
FS.ensureDirExists(libSelfDir);
|
||||||
|
File jarFile = new File(libSelfDir,jarFilename);
|
||||||
|
JAR.create(srcDir,jarFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpack an arbitrary config from <code>target/test-configs/${configFilename}</code> to the testing directory.
|
||||||
|
*
|
||||||
|
* @param configFilename
|
||||||
|
* the <code>target/test-configs/${configFilename}</code> to copy
|
||||||
|
* @throws IOException
|
||||||
|
* if unable to unpack config file
|
||||||
|
*/
|
||||||
|
public void unpackConfig(String configFilename) throws IOException
|
||||||
|
{
|
||||||
|
File srcConfig = MavenTestingUtils.getTargetFile("test-configs/" + configFilename);
|
||||||
|
JAR.unpack(srcConfig,jettyHomeDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a File or Directory found in the ${jetty.home} directory.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* the path to delete. (can be a file or directory)
|
||||||
|
*/
|
||||||
|
public void delete(String path)
|
||||||
|
{
|
||||||
|
File jettyPath = new File(jettyHomeDir,OS.separators(path));
|
||||||
|
FS.delete(jettyPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the baseUri being used for this Jetty Process Instance.
|
||||||
|
*
|
||||||
|
* @return the base URI for this Jetty Process Instance.
|
||||||
|
*/
|
||||||
|
public URI getBaseUri()
|
||||||
|
{
|
||||||
|
return this.baseUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the JMX URL being used for this Jetty Process Instance.
|
||||||
|
*
|
||||||
|
* @return the JMX URL for this Jetty Process Instance.
|
||||||
|
*/
|
||||||
|
public String getJmxUrl()
|
||||||
|
{
|
||||||
|
return this.jmxUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take the directory contents from ${project.basedir}/src/test/resources/${testConfigName}/ and copy it over whatever happens to be at ${jetty.home}
|
||||||
|
*
|
||||||
|
* @param testConfigName
|
||||||
|
* the src/test/resources/ directory name to use as the source diretory for the configuration we are interested in.
|
||||||
|
* @throws IOException
|
||||||
|
* if unable to copy directory.
|
||||||
|
*/
|
||||||
|
public void overlayConfig(String testConfigName) throws IOException
|
||||||
|
{
|
||||||
|
File srcDir = MavenTestingUtils.getTestResourceDir(testConfigName);
|
||||||
|
IO.copyDir(srcDir,jettyHomeDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the jetty server
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* if unable to start the server.
|
||||||
|
*/
|
||||||
|
public void start() throws IOException
|
||||||
|
{
|
||||||
|
List<String> commands = new ArrayList<String>();
|
||||||
|
commands.add(getJavaBin());
|
||||||
|
|
||||||
|
commands.add("-Djetty.home=" + jettyHomeDir.getAbsolutePath());
|
||||||
|
|
||||||
|
// Do a dry run first to get the exact command line for Jetty process
|
||||||
|
commands.add("-jar");
|
||||||
|
commands.add("start.jar");
|
||||||
|
commands.add("jetty.port=0");
|
||||||
|
if (_debug)
|
||||||
|
{
|
||||||
|
commands.add("-D.DEBUG=true");
|
||||||
|
}
|
||||||
|
commands.add("--dry-run");
|
||||||
|
|
||||||
|
ProcessBuilder pbCmd = new ProcessBuilder(commands);
|
||||||
|
pbCmd.directory(jettyHomeDir);
|
||||||
|
|
||||||
|
String cmdLine = null;
|
||||||
|
Process pidCmd = pbCmd.start();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cmdLine = readOutputLine(pidCmd);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
pidCmd.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdLine == null || !cmdLine.contains("XmlConfiguration"))
|
||||||
|
{
|
||||||
|
Assert.fail("Unable to get Jetty command line");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to breakdown commandline into parts, as spaces in command line will cause failures.
|
||||||
|
List<String> execCommands = splitAndUnescapeCommandLine(cmdLine);
|
||||||
|
|
||||||
|
System.out.printf("Executing: %s%n",cmdLine);
|
||||||
|
System.out.printf("Working Dir: %s%n",jettyHomeDir.getAbsolutePath());
|
||||||
|
|
||||||
|
pbCmd = new ProcessBuilder(execCommands);
|
||||||
|
pid = pbCmd.start();
|
||||||
|
|
||||||
|
ConsoleParser parser = new ConsoleParser();
|
||||||
|
List<String[]> jmxList = parser.newPattern("JMX Remote URL: (.*)",0);
|
||||||
|
List<String[]> connList = parser.newPattern("Started [A-Za-z]*Connector@([0-9]*\\.[0-9]*\\.[0-9]*\\.[0-9]*):([0-9]*)",1);
|
||||||
|
// DISABLED: This is what exists in Jetty 9+
|
||||||
|
// List<String[]> connList = parser.newPattern("Started [A-Za-z]*Connector@.*[\\({]([0-9]*\\.[0-9]*\\.[0-9]*\\.[0-9]*):([0-9]*)[\\)}].*",1);
|
||||||
|
|
||||||
|
startPump("STDOUT",parser,this.pid.getInputStream());
|
||||||
|
startPump("STDERR",parser,this.pid.getErrorStream());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
parser.waitForDone(this.startTime,this.timeUnit);
|
||||||
|
|
||||||
|
if (!jmxList.isEmpty())
|
||||||
|
{
|
||||||
|
this.jmxUrl = jmxList.get(0)[0];
|
||||||
|
System.out.printf("## Found JMX connector at %s%n",this.jmxUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!connList.isEmpty())
|
||||||
|
{
|
||||||
|
String[] params = connList.get(0);
|
||||||
|
if (params.length == 2)
|
||||||
|
{
|
||||||
|
this.baseUri = URI.create("http://localhost:" + params[1] + "/");
|
||||||
|
}
|
||||||
|
System.out.printf("## Found Jetty connector at host: %s port: %s%n",(Object[])params);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (InterruptedException e)
|
||||||
|
{
|
||||||
|
pid.destroy();
|
||||||
|
Assert.fail("Unable to get required information within time limit");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> splitAndUnescapeCommandLine(CharSequence rawCmdLine)
|
||||||
|
{
|
||||||
|
List<String> cmds = new ArrayList<String>();
|
||||||
|
|
||||||
|
int len = rawCmdLine.length();
|
||||||
|
StringBuilder arg = new StringBuilder();
|
||||||
|
boolean escaped = false;
|
||||||
|
boolean inQuote = false;
|
||||||
|
char c;
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
c = rawCmdLine.charAt(i);
|
||||||
|
if (escaped)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 'r':
|
||||||
|
arg.append('\r');
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
arg.append('\f');
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
arg.append('\t');
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
arg.append('\n');
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
arg.append('\b');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
arg.append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
escaped = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\\')
|
||||||
|
{
|
||||||
|
escaped = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((c == ' ') && (!inQuote))
|
||||||
|
{
|
||||||
|
// the delim!
|
||||||
|
cmds.add(String.valueOf(arg.toString()));
|
||||||
|
arg.setLength(0);
|
||||||
|
}
|
||||||
|
else if (c == '"')
|
||||||
|
{
|
||||||
|
inQuote = !inQuote;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arg.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmds.add(String.valueOf(arg.toString()));
|
||||||
|
|
||||||
|
return cmds;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readOutputLine(Process pidCmd) throws IOException
|
||||||
|
{
|
||||||
|
InputStream in = null;
|
||||||
|
InputStreamReader reader = null;
|
||||||
|
BufferedReader buf = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
in = pidCmd.getInputStream();
|
||||||
|
reader = new InputStreamReader(in);
|
||||||
|
buf = new BufferedReader(reader);
|
||||||
|
return buf.readLine();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IO.close(buf);
|
||||||
|
IO.close(reader);
|
||||||
|
IO.close(in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ConsoleParser
|
||||||
|
{
|
||||||
|
private List<ConsolePattern> patterns = new ArrayList<ConsolePattern>();
|
||||||
|
private CountDownLatch latch;
|
||||||
|
private int count;
|
||||||
|
|
||||||
|
public List<String[]> newPattern(String exp, int cnt)
|
||||||
|
{
|
||||||
|
ConsolePattern pat = new ConsolePattern(exp,cnt);
|
||||||
|
patterns.add(pat);
|
||||||
|
count += cnt;
|
||||||
|
|
||||||
|
return pat.getMatches();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void parse(String line)
|
||||||
|
{
|
||||||
|
for (ConsolePattern pat : patterns)
|
||||||
|
{
|
||||||
|
Matcher mat = pat.getMatcher(line);
|
||||||
|
if (mat.find())
|
||||||
|
{
|
||||||
|
int num = 0, count = mat.groupCount();
|
||||||
|
String[] match = new String[count];
|
||||||
|
while (num++ < count)
|
||||||
|
{
|
||||||
|
match[num - 1] = mat.group(num);
|
||||||
|
}
|
||||||
|
pat.getMatches().add(match);
|
||||||
|
|
||||||
|
if (pat.getCount() > 0)
|
||||||
|
{
|
||||||
|
getLatch().countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void waitForDone(long timeout, TimeUnit unit) throws InterruptedException
|
||||||
|
{
|
||||||
|
getLatch().await(timeout,unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CountDownLatch getLatch()
|
||||||
|
{
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
if (latch == null)
|
||||||
|
{
|
||||||
|
latch = new CountDownLatch(count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return latch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ConsolePattern
|
||||||
|
{
|
||||||
|
private Pattern pattern;
|
||||||
|
private List<String[]> matches;
|
||||||
|
private int count;
|
||||||
|
|
||||||
|
ConsolePattern(String exp, int cnt)
|
||||||
|
{
|
||||||
|
pattern = Pattern.compile(exp);
|
||||||
|
matches = new ArrayList<String[]>();
|
||||||
|
count = cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matcher getMatcher(String line)
|
||||||
|
{
|
||||||
|
return pattern.matcher(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String[]> getMatches()
|
||||||
|
{
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCount()
|
||||||
|
{
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startPump(String mode, ConsoleParser parser, InputStream inputStream)
|
||||||
|
{
|
||||||
|
ConsoleStreamer pump = new ConsoleStreamer(mode,inputStream);
|
||||||
|
pump.setParser(parser);
|
||||||
|
Thread thread = new Thread(pump,"ConsoleStreamer/" + mode);
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enable debug on the jetty process
|
||||||
|
*
|
||||||
|
* @param debug
|
||||||
|
*/
|
||||||
|
public void setDebug(boolean debug)
|
||||||
|
{
|
||||||
|
_debug = debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getJavaBin()
|
||||||
|
{
|
||||||
|
String javaexes[] = new String[]
|
||||||
|
{ "java", "java.exe" };
|
||||||
|
|
||||||
|
File javaHomeDir = new File(System.getProperty("java.home"));
|
||||||
|
for (String javaexe : javaexes)
|
||||||
|
{
|
||||||
|
File javabin = new File(javaHomeDir,OS.separators("bin/" + javaexe));
|
||||||
|
if (javabin.exists() && javabin.isFile())
|
||||||
|
{
|
||||||
|
return javabin.getAbsolutePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.fail("Unable to find java bin");
|
||||||
|
return "java";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop the jetty server
|
||||||
|
*/
|
||||||
|
public void stop()
|
||||||
|
{
|
||||||
|
System.out.println("Stopping JettyDistro ...");
|
||||||
|
if (pid != null)
|
||||||
|
{
|
||||||
|
// TODO: maybe issue a STOP instead?
|
||||||
|
pid.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple streamer for the console output from a Process
|
||||||
|
*/
|
||||||
|
private static class ConsoleStreamer implements Runnable
|
||||||
|
{
|
||||||
|
private String mode;
|
||||||
|
private BufferedReader reader;
|
||||||
|
private ConsoleParser parser;
|
||||||
|
|
||||||
|
public ConsoleStreamer(String mode, InputStream is)
|
||||||
|
{
|
||||||
|
this.mode = mode;
|
||||||
|
this.reader = new BufferedReader(new InputStreamReader(is));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParser(ConsoleParser connector)
|
||||||
|
{
|
||||||
|
this.parser = connector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
String line;
|
||||||
|
// System.out.printf("ConsoleStreamer/%s initiated%n",mode);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while ((line = reader.readLine()) != (null))
|
||||||
|
{
|
||||||
|
if (parser != null)
|
||||||
|
{
|
||||||
|
parser.parse(line);
|
||||||
|
}
|
||||||
|
System.out.println("[" + mode + "] " + line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ignore)
|
||||||
|
{
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IO.close(reader);
|
||||||
|
}
|
||||||
|
// System.out.printf("ConsoleStreamer/%s finished%n",mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartTime(long startTime, TimeUnit timeUnit)
|
||||||
|
{
|
||||||
|
this.startTime = startTime;
|
||||||
|
this.timeUnit = timeUnit;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue