284510 Enhance jetty-start for diagnosis and unit testing

Merging in changes made on /jetty-start-enhancement/ branch



git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@587 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
Joakim Erdfelt 2009-07-23 21:50:09 +00:00
parent 778489d7cf
commit bb50e1bac8
27 changed files with 2470 additions and 682 deletions

View File

@ -4,6 +4,7 @@ jetty-7.0.0.RC2-SNAPSHOT
+ 283818 fixed merge of forward parameters
+ backport jetty-8 annotation parsing to jetty-7
+ Disassociate method on IdentityService
+ 284510 Enhance jetty-start for diagnosis and unit testing
jetty-7.0.0.RC1 15 June 2009
+ JETTY-1066 283357 400 response for bad URIs

View File

@ -15,6 +15,7 @@ package org.eclipse.jetty.start;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
@ -26,11 +27,10 @@ import java.util.Vector;
/**
* Class to handle CLASSPATH construction
*
*/
public class Classpath {
Vector _elements = new Vector();
private final Vector<File> _elements = new Vector<File>();
public Classpath()
{}
@ -42,7 +42,12 @@ public class Classpath {
public File[] getElements()
{
return (File[])_elements.toArray(new File[_elements.size()]);
return _elements.toArray(new File[_elements.size()]);
}
public int count()
{
return _elements.size();
}
public boolean addComponent(String component)
@ -92,18 +97,28 @@ public class Classpath {
}
}
return added;
}
}
public void dump(PrintStream out)
{
int i = 0;
for (File element : _elements)
{
out.printf("%2d: %s\n",i++,element.getAbsolutePath());
}
}
@Override
public String toString()
{
StringBuffer cp = new StringBuffer(1024);
int cnt = _elements.size();
if (cnt >= 1) {
cp.append( ((File)(_elements.elementAt(0))).getPath() );
cp.append( ((_elements.elementAt(0))).getPath() );
}
for (int i=1; i < cnt; i++) {
cp.append(File.pathSeparatorChar);
cp.append( ((File)(_elements.elementAt(i))).getPath() );
cp.append( ((_elements.elementAt(i))).getPath() );
}
return cp.toString();
}
@ -113,7 +128,7 @@ public class Classpath {
URL[] urls = new URL[cnt];
for (int i=0; i < cnt; i++) {
try {
String u=((File)(_elements.elementAt(i))).toURL().toString();
String u=((_elements.elementAt(i))).toURL().toString();
urls[i] = new URL(encodeFileURL(u));
} catch (MalformedURLException e) {}
}
@ -128,7 +143,7 @@ public class Classpath {
return new Loader(urls, parent);
}
private class Loader extends URLClassLoader
private static class Loader extends URLClassLoader
{
String name;
@ -138,6 +153,7 @@ public class Classpath {
name = "StartLoader"+Arrays.asList(urls);
}
@Override
public String toString()
{
return name;
@ -189,8 +205,8 @@ public class Classpath {
}
}
buf.append('%');
buf.append(Integer.toHexString((0xf0&(int)b)>>4));
buf.append(Integer.toHexString((0x0f&(int)b)));
buf.append(Integer.toHexString((0xf0&b)>>4));
buf.append(Integer.toHexString((0x0f&b)));
continue;
}
}
@ -198,4 +214,29 @@ public class Classpath {
return buf.toString();
}
/**
* Overlay another classpath, copying its elements into place on this Classpath, while eliminating duplicate entries
* on the classpath.
*
* @param cpOther
* the other classpath to overlay
*/
public void overlay(Classpath cpOther)
{
for (File otherElement : cpOther._elements)
{
if (this._elements.contains(otherElement))
{
// Skip duplicate entries
continue;
}
this._elements.add(otherElement);
}
}
public boolean isEmpty()
{
return (_elements == null) || (_elements.isEmpty());
}
}

View File

@ -0,0 +1,816 @@
// ========================================================================
// Copyright (c) Webtide LLC
// ------------------------------------------------------------------------
// 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.apache.org/licenses/LICENSE-2.0.txt
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.start;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.security.Policy;
import java.text.CollationKey;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
/**
* <p>
* It allows an application to be started with the command <code>"java -jar start.jar"</code>.
* </p>
*
* <p>
* The behaviour of Main is controlled by the <code>"org/eclipse/start/start.config"</code> file obtained as a resource
* or file. This can be overridden with the START system property. The format of each line in this file is:
* </p>
*
* <p>
* Each line contains entry in the format:
* </p>
*
* <pre>
* SUBJECT [ [!] CONDITION [AND|OR] ]*
* </pre>
*
* <p>
* where SUBJECT:
* </p>
* <ul>
* <li>ends with <code>".class"</code> is the Main class to run.</li>
* <li>ends with <code>".xml"</code> is a configuration file for the command line</li>
* <li>ends with <code>"/"</code> is a directory from which to add all jar and zip files.</li>
* <li>ends with <code>"/*"</code> is a directory from which to add all unconsidered jar and zip files.</li>
* <li>ends with <code>"/**"</code> is a directory from which to recursively add all unconsidered jar and zip files.</li>
* <li>Containing <code>=</code> are used to assign system properties.</li>
* <li>Containing <code>~=</code> are used to assign start properties.</li>
* <li>Containing <code>/=</code> are used to assign a canonical path.</li>
* <li>all other subjects are treated as files to be added to the classpath.</li>
* </ul>
*
* <p>
* property expansion:
* </p>
* <ul>
* <li><code>${name}</code> is expanded to a start property</li>
* <li><code>$(name)</code> is expanded to either a start property or a system property.</li>
* <li>The start property <code>${version}</code> is defined as the version of the start.jar</li>
* </ul>
*
* <p>
* Files starting with <code>"/"</code> are considered absolute, all others are relative to the home directory.
* </p>
*
* <p>
* CONDITION is one of:
* </p>
* <ul>
* <li><code>always</code></li>
* <li><code>never</code></li>
* <li><code>available classname</code> - true if class on classpath</li>
* <li><code>property name</code> - true if set as start property</li>
* <li><code>system name</code> - true if set as system property</li>
* <li><code>exists file</code> - true if file/dir exists</li>
* <li><code>java OPERATOR version</code> - java version compared to literal</li>
* <li><code>nargs OPERATOR number</code> - number of command line args compared to literal</li>
* <li>OPERATOR := one of <code>"&lt;"</code>,<code>"&gt;"</code>,<code>"&lt;="</code>,<code>"&gt;="</code>,
* <code>"=="</code>,<code>"!="</code></li>
* </ul>
*
* <p>
* CONDITIONS can be combined with <code>AND</code> <code>OR</code> or <code>!</code>, with <code>AND</code> being the
* assume operator for a list of CONDITIONS.
* </p>
*
* <p>
* Classpath operations are evaluated on the fly, so once a class or jar is added to the classpath, subsequent available
* conditions will see that class.
* </p>
*
* <p>
* The configuration file may be divided into sections with option names like: [ssl,default]
* </p>
*
* <p>
* Clauses after a section header will only be included if they match one of the tags in the options property. By
* default options are set to "default,*" or the OPTIONS property may be used to pass in a list of tags, eg. :
* </p>
*
* <pre>
* java -jar start.jar OPTIONS=jetty,jsp,ssl
* </pre>
*
* <p>
* The tag '*' is always appended to the options, so any section with the * tag is always applied.
* </p>
*/
public class Config
{
public static final String DEFAULT_SECTION = "";
static
{
Package pkg = Config.class.getPackage();
if (pkg != null && (pkg.getImplementationVersion() != null))
_version = pkg.getImplementationVersion();
else
_version = System.getProperty("jetty.version","Unknown");
}
/**
* Natural language sorting for key names.
*/
private Comparator<String> keySorter = new Comparator<String>()
{
private Collator collator = Collator.getInstance();
public int compare(String o1, String o2)
{
CollationKey key1 = collator.getCollationKey(o1);
CollationKey key2 = collator.getCollationKey(o2);
return key1.compareTo(key2);
}
};
private static final String _version;
private static boolean DEBUG = false;
private Map<String, Classpath> _classpaths = new HashMap<String, Classpath>();
private List<String> _xml = new ArrayList<String>();
private Set<String> _policies = new HashSet<String>();
private String _classname = null;
private Map<String, String> _properties = new HashMap<String, String>();
private int argCount = 0;
private boolean addClasspathComponent(List<String> sections, String component)
{
for (String section : sections)
{
Classpath cp = _classpaths.get(section);
if (cp == null)
{
cp = new Classpath();
}
boolean added = cp.addComponent(component);
_classpaths.put(section,cp);
if (!added)
{
// First failure means all failed.
return false;
}
}
return true;
}
private boolean addClasspathPath(List<String> sections, String path)
{
for (String section : sections)
{
Classpath cp = _classpaths.get(section);
if (cp == null)
{
cp = new Classpath();
}
if (!cp.addClasspath(path))
{
// First failure means all failed.
return false;
}
_classpaths.put(section,cp);
}
return true;
}
private void addJars(List<String> sections, File dir, boolean recurse) throws IOException
{
List<File> entries = new ArrayList<File>();
File[] files = dir.listFiles();
if (files == null)
{
// No files found, skip it.
return;
}
entries.addAll(Arrays.asList(files));
Collections.sort(entries,FilenameComparator.INSTANCE);
for (File entry : entries)
{
if (entry.isDirectory() && recurse)
addJars(sections,entry,recurse);
else
{
String name = entry.getName().toLowerCase();
if (name.endsWith(".jar") || name.endsWith(".zip"))
{
String jar = entry.getCanonicalPath();
boolean added = addClasspathComponent(sections,jar);
debug((added?" CLASSPATH+=":" !") + jar);
}
}
}
}
private void close(InputStream stream)
{
if (stream == null)
return;
try
{
stream.close();
}
catch (IOException ignore)
{
/* ignore */
}
}
private void close(Reader reader)
{
if (reader == null)
return;
try
{
reader.close();
}
catch (IOException ignore)
{
/* ignore */
}
}
public static boolean isDebug()
{
return DEBUG;
}
public static void debug(String msg)
{
if (DEBUG)
{
System.err.println(msg);
}
}
public static void debug(Throwable t)
{
if (DEBUG)
{
t.printStackTrace(System.err);
}
}
private String expand(String s)
{
int i1 = 0;
int i2 = 0;
while (s != null)
{
i1 = s.indexOf("$(",i2);
if (i1 < 0)
break;
i2 = s.indexOf(")",i1 + 2);
if (i2 < 0)
break;
String name = s.substring(i1 + 2,i2);
String property = getSystemProperty(name);
s = s.substring(0,i1) + property + s.substring(i2 + 1);
}
i1 = 0;
i2 = 0;
while (s != null)
{
i1 = s.indexOf("${",i2);
if (i1 < 0)
break;
i2 = s.indexOf("}",i1 + 2);
if (i2 < 0)
break;
String name = s.substring(i1 + 2,i2);
String property = getProperty(name);
s = s.substring(0,i1) + property + s.substring(i2 + 1);
}
return s;
}
/**
* Get the default classpath.
*
* @return the default classpath
*/
public Classpath getClasspath()
{
return _classpaths.get(DEFAULT_SECTION);
}
/**
* Get the combined classpath representing the default classpath plus all named sections.
*
* NOTE: the default classpath will be prepended, and the '*' classpath will be appended.
*
* @param sectionIds
* the list of section ids to fetch
* @return the {@link Classpath} representing combination all of the selected sectionIds, combined with the default
* section id, and '*' special id.
*/
public Classpath getCombinedClasspath(Collection<String> sectionIds)
{
Classpath cp = new Classpath();
cp.overlay(_classpaths.get(DEFAULT_SECTION));
for (String sectionId : sectionIds)
{
cp.overlay(_classpaths.get(sectionId));
}
cp.overlay(_classpaths.get("*"));
return cp;
}
public String getMainClassname()
{
return _classname;
}
public String getProperty(String name)
{
if ("version".equalsIgnoreCase(name))
return _version;
return _properties.get(name);
}
public String getProperty(String name, String dftValue)
{
if (_properties.containsKey(name))
return _properties.get(name);
return dftValue;
}
/**
* Get the classpath for the named section
*
* @param sectionId
* @return
*/
public Classpath getSectionClasspath(String sectionId)
{
return _classpaths.get(sectionId);
}
/**
* Get the list of section Ids.
*
* @return
*/
public Set<String> getSectionIds()
{
Set<String> ids = new TreeSet<String>(keySorter);
ids.addAll(_classpaths.keySet());
return ids;
}
private String getSystemProperty(String name)
{
if ("version".equalsIgnoreCase(name))
return _version;
if (_properties.containsKey(name))
return _properties.get(name);
return System.getProperty(name);
}
public List<String> getXmlConfigs()
{
return _xml;
}
private boolean isAvailable(List<String> sections, String classname)
{
// Try default/parent class loader first.
try
{
Class.forName(classname);
return true;
}
catch (NoClassDefFoundError e)
{
debug(e);
}
catch (ClassNotFoundException e)
{
debug(e);
}
// Try section classloaders instead
ClassLoader loader;
Classpath classpath;
for (String sectionId : sections)
{
classpath = _classpaths.get(sectionId);
if (classpath == null)
{
// skip, no classpath
continue;
}
loader = classpath.getClassLoader();
try
{
loader.loadClass(classname);
return true;
}
catch (NoClassDefFoundError e)
{
debug(e);
}
catch (ClassNotFoundException e)
{
debug(e);
}
}
return false;
}
/**
* Parse the configuration
*
* @param buf
* @throws IOException
*/
public void parse(CharSequence buf) throws IOException
{
parse(new StringReader(buf.toString()));
}
/**
* Parse the configuration
*
* @param buf
* @throws IOException
*/
public void parse(InputStream stream) throws IOException
{
InputStreamReader reader = null;
try
{
reader = new InputStreamReader(stream);
parse(reader);
}
finally
{
close(reader);
}
}
public void parse(Reader reader) throws IOException
{
BufferedReader buf = null;
try
{
buf = new BufferedReader(reader);
List<String> sections = new ArrayList<String>();
sections.add(DEFAULT_SECTION);
_classpaths.put(DEFAULT_SECTION,new Classpath());
Version java_version = new Version(System.getProperty("java.version"));
Version ver = new Version();
String line = null;
while ((line = buf.readLine()) != null)
{
String trim = line.trim();
if (trim.length() == 0) // empty line
continue;
if (trim.startsWith("#")) // comment
continue;
// handle options
if (trim.startsWith("[") && trim.endsWith("]"))
{
sections = Arrays.asList(trim.substring(1,trim.length() - 1).split(","));
// Ensure section classpaths exist
for (String sectionId : sections)
{
if (!_classpaths.containsKey(sectionId))
{
_classpaths.put(sectionId,new Classpath());
}
}
}
try
{
StringTokenizer st = new StringTokenizer(line);
String subject = st.nextToken();
boolean expression = true;
boolean not = false;
String condition = null;
// Evaluate all conditions
while (st.hasMoreTokens())
{
condition = st.nextToken();
if (condition.equalsIgnoreCase("!"))
{
not = true;
continue;
}
if (condition.equalsIgnoreCase("OR"))
{
if (expression)
break;
expression = true;
continue;
}
if (condition.equalsIgnoreCase("AND"))
{
if (!expression)
break;
continue;
}
boolean eval = true;
if (condition.equals("true") || condition.equals("always"))
{
eval = true;
}
else if (condition.equals("false") || condition.equals("never"))
{
eval = false;
}
else if (condition.equals("available"))
{
String class_to_check = st.nextToken();
eval = isAvailable(sections,class_to_check);
}
else if (condition.equals("exists"))
{
try
{
eval = false;
File file = new File(expand(st.nextToken()));
eval = file.exists();
}
catch (Exception e)
{
debug(e);
}
}
else if (condition.equals("property"))
{
String property = getProperty(st.nextToken());
eval = property != null && property.length() > 0;
}
else if (condition.equals("system"))
{
String property = System.getProperty(st.nextToken());
eval = property != null && property.length() > 0;
}
else if (condition.equals("java"))
{
String operator = st.nextToken();
String version = st.nextToken();
ver.parse(version);
eval = (operator.equals("<") && java_version.compare(ver) < 0) || (operator.equals(">") && java_version.compare(ver) > 0)
|| (operator.equals("<=") && java_version.compare(ver) <= 0) || (operator.equals("=<") && java_version.compare(ver) <= 0)
|| (operator.equals("=>") && java_version.compare(ver) >= 0) || (operator.equals(">=") && java_version.compare(ver) >= 0)
|| (operator.equals("==") && java_version.compare(ver) == 0) || (operator.equals("!=") && java_version.compare(ver) != 0);
}
else if (condition.equals("nargs"))
{
String operator = st.nextToken();
int number = Integer.parseInt(st.nextToken());
eval = (operator.equals("<") && argCount < number) || (operator.equals(">") && argCount > number)
|| (operator.equals("<=") && argCount <= number) || (operator.equals("=<") && argCount <= number)
|| (operator.equals("=>") && argCount >= number) || (operator.equals(">=") && argCount >= number)
|| (operator.equals("==") && argCount == number) || (operator.equals("!=") && argCount != number);
}
else
{
System.err.println("ERROR: Unknown condition: " + condition);
eval = false;
}
expression &= not?!eval:eval;
not = false;
}
String file = expand(subject);
debug((expression?"T ":"F ") + line);
if (!expression)
continue;
// Setting of a start property
if (subject.indexOf("~=") > 0)
{
int i = file.indexOf("~=");
String property = file.substring(0,i);
String value = fixPath(file.substring(i + 2));
debug(" " + property + "~=" + value);
setProperty(property,value);
}
else
// Setting of start property with canonical path
if (subject.indexOf("/=") > 0)
{
int i = file.indexOf("/=");
String property = file.substring(0,i);
String value = fixPath(file.substring(i + 2));
String canonical = new File(value).getCanonicalPath();
debug(" " + property + "/=" + value + "==" + canonical);
setProperty(property,canonical);
}
else
// Setting of system property
if (subject.indexOf("=") > 0)
{
int i = file.indexOf("=");
String property = file.substring(0,i);
String value = fixPath(file.substring(i + 1));
debug(" " + property + "=" + value);
System.setProperty(property,value);
}
else
// Add all unconsidered JAR and ZIP files to classpath
if (subject.endsWith("/*"))
{
// directory of JAR files - only add jars and zips within the directory
File dir = new File(fixPath(file.substring(0,file.length() - 1)));
addJars(sections,dir,false);
}
else
// Recursively add all unconsidered JAR and ZIP files to classpath
if (subject.endsWith("/**"))
{
//directory hierarchy of jar files - recursively add all jars and zips in the hierarchy
File dir = new File(fixPath(file.substring(0,file.length() - 2)));
addJars(sections,dir,true);
}
else
// Add raw classpath directory to classpath
if (subject.endsWith("/"))
{
// class directory
File cd = new File(fixPath(file));
String d = cd.getCanonicalPath();
boolean added = addClasspathComponent(sections,d);
debug((added?" CLASSPATH+=":" !") + d);
}
else
// Add XML configuration
if (subject.toLowerCase().endsWith(".xml"))
{
// Config file
File f = new File(fixPath(file));
if (f.exists())
_xml.add(f.getCanonicalPath());
debug(" ARGS+=" + f);
}
else
// Set the main class to execute (overrides any previously set)
if (subject.toLowerCase().endsWith(".class"))
{
// Class
String cn = expand(subject.substring(0,subject.length() - 6));
if (cn != null && cn.length() > 0)
{
debug(" CLASS=" + cn);
_classname = cn;
}
}
else
// Add raw classpath entry
if (subject.toLowerCase().endsWith(".path"))
{
// classpath (jetty.class.path?) to add to runtime classpath
String cn = expand(subject.substring(0,subject.length() - 5));
if (cn != null && cn.length() > 0)
{
debug(" PATH=" + cn);
addClasspathPath(sections,cn);
}
}
else
// Add Security Policy file reference
if (subject.toLowerCase().endsWith(".policy"))
{
//policy file to parse
String cn = expand(subject.substring(0,subject.length()));
if (cn != null && cn.length() > 0)
{
debug(" POLICY=" + cn);
_policies.add(fixPath(cn));
}
}
else
{
// single JAR file
File f = new File(fixPath(file));
if (f.exists())
{
String d = f.getCanonicalPath();
boolean added = addClasspathComponent(sections,d);
if (!added)
{
added = addClasspathPath(sections,expand(subject));
}
debug((added?" CLASSPATH+=":" !") + d);
}
}
}
catch (Exception e)
{
System.err.println("on line: '" + line + "'");
e.printStackTrace();
}
}
}
finally
{
close(buf);
}
}
private String fixPath(String path)
{
return path.replace('/',File.separatorChar);
}
public void parse(URL url) throws IOException
{
InputStream stream = null;
InputStreamReader reader = null;
try
{
stream = url.openStream();
reader = new InputStreamReader(stream);
parse(reader);
}
finally
{
close(reader);
close(stream);
}
}
public void setArgCount(int argCount)
{
this.argCount = argCount;
}
public void setProperty(String name, String value)
{
if (name.equals("DEBUG"))
{
DEBUG = Boolean.parseBoolean(value);
}
_properties.put(name,value);
}
public Policy getPolicyInstance(ClassLoader cl) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException,
InstantiationException, IllegalAccessException, InvocationTargetException
{
Class<?> jettyPolicy = cl.loadClass("org.eclipse.jetty.policy.JettyPolicy");
Constructor<?> c = jettyPolicy.getConstructor(new Class[]
{ Set.class, Map.class });
Object policyClass = c.newInstance(_policies,_properties);
if (policyClass instanceof Policy)
{
return (Policy)policyClass;
}
throw new ClassCastException("Unable to cast to " + Policy.class.getName() + " : " + policyClass.getClass().getName());
}
}

View File

@ -0,0 +1,67 @@
// ========================================================================
// Copyright (c) Webtide LLC
// ------------------------------------------------------------------------
// 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.apache.org/licenses/LICENSE-2.0.txt
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.start;
import java.io.File;
import java.text.CollationKey;
import java.text.Collator;
import java.util.Comparator;
/**
* Smart comparator for filenames, with natural language sorting, and files sorted before sub directories.
*/
public class FilenameComparator implements Comparator<File>
{
public static final FilenameComparator INSTANCE = new FilenameComparator();
private Collator collator = Collator.getInstance();
public int compare(File o1, File o2)
{
if (o1.isFile())
{
if (o2.isFile())
{
CollationKey key1 = toKey(o1);
CollationKey key2 = toKey(o2);
return key1.compareTo(key2);
}
else
{
// Push o2 directories below o1 files
return -1;
}
}
else
{
if (o2.isDirectory())
{
CollationKey key1 = toKey(o1);
CollationKey key2 = toKey(o2);
return key1.compareTo(key2);
}
else
{
// Push o2 files above o1 directories
return 1;
}
}
}
private CollationKey toKey(File f)
{
return collator.getCollationKey(f.getAbsolutePath());
}
}

View File

@ -0,0 +1,167 @@
// ========================================================================
// Copyright (c) Webtide LLC
// ------------------------------------------------------------------------
// 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.apache.org/licenses/LICENSE-2.0.txt
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.start;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Attempt to determine the version of the Jar File based on common version locations.
*/
public class JarVersion
{
private static JarEntry findEntry(JarFile jar, String regex)
{
Pattern pattern = Pattern.compile(regex);
Matcher matcher;
Enumeration<JarEntry> en = jar.entries();
while (en.hasMoreElements())
{
JarEntry entry = en.nextElement();
matcher = pattern.matcher(entry.getName());
if (matcher.matches())
{
return entry;
}
}
return null;
}
private static String getBundleVersion(Manifest manifest)
{
Attributes attribs = manifest.getMainAttributes();
if (attribs == null)
return null;
String version = attribs.getValue("Bundle-Version");
if (version == null)
return null;
return stripV(version);
}
private static String getMainManifestImplVersion(Manifest manifest)
{
Attributes attribs = manifest.getMainAttributes();
if (attribs == null)
return null;
String version = attribs.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
if (version == null)
return null;
return stripV(version);
}
private static String getMavenVersion(JarFile jar) throws IOException
{
JarEntry pomProp = findEntry(jar,"META-INF/maven/.*/pom\\.properties$");
if (pomProp == null)
return null;
InputStream stream = null;
try
{
stream = jar.getInputStream(pomProp);
Properties props = new Properties();
props.load(stream);
String version = props.getProperty("version");
if (version == null)
return null;
return stripV(version);
}
finally
{
Main.close(stream);
}
}
private static String getSubManifestImplVersion(Manifest manifest)
{
Map<String, Attributes> entries = manifest.getEntries();
for (Attributes attribs : entries.values())
{
if (attribs == null)
continue; // skip entry
String version = attribs.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
if (version == null)
continue; // empty, no value, skip it
return stripV(version);
}
return null; // no valid impl version entries found
}
public static String getVersion(File file)
{
try
{
JarFile jar = new JarFile(file);
String version = null;
Manifest manifest = jar.getManifest();
version = getMainManifestImplVersion(manifest);
if (version != null)
return version;
version = getSubManifestImplVersion(manifest);
if (version != null)
return version;
version = getBundleVersion(manifest);
if (version != null)
return version;
version = getMavenVersion(jar);
if (version != null)
return version;
return "(not specified)";
}
catch (IOException e)
{
return "(error: " + e.getClass().getSimpleName() + " " + e.getMessage() + ")";
}
}
private static String stripV(String version)
{
if (version.charAt(0) == 'v')
return version.substring(1);
return version;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -63,10 +63,8 @@ public class Monitor extends Thread
}
catch(Exception e)
{
if (Main.DEBUG)
e.printStackTrace();
else
System.err.println(e.toString());
Config.debug(e);
System.err.println(e.toString());
}
if (_socket!=null)
this.start();
@ -74,6 +72,7 @@ public class Monitor extends Thread
System.err.println("WARN: Not listening on monitor port: "+_port);
}
@Override
public void run()
{
while (true)
@ -89,7 +88,7 @@ public class Monitor extends Thread
continue;
String cmd=lin.readLine();
if (Main.DEBUG) System.err.println("command="+cmd);
Config.debug("command=" + cmd);
if ("stop".equals(cmd))
{
try {socket.close();}catch(Exception e){e.printStackTrace();}
@ -104,10 +103,8 @@ public class Monitor extends Thread
}
catch(Exception e)
{
if (Main.DEBUG)
e.printStackTrace();
else
System.err.println(e.toString());
Config.debug(e);
System.err.println(e.toString());
}
finally
{

View File

@ -0,0 +1,50 @@
Usage: java -jar start.jar [options] [properties] [configs]
Run Jetty Server Standalone.
Common Options:
--help This help / usage information.
--version Print the version information for Jetty, then exit.
--stop Stop the running Jetty instance.
Advanced Options:
--secure Enable Security:
* JVM Security Manager
* Security Policies
* Secure Logging
* Audit Logging
--exec-print Print the command line that the start.jar uses to start
jetty, then exit.
(useful in shell scripts)
--list-modes List available classpath mode options, then exit.
(see OPTION property in section below)
Properties:
Execution properties, similar in scope to JVM Properties.
NOTE: Not all properties are listed here.
org.eclipse.jetty.util.log.class=[class]
A Low Level Jetty Logger Implementation to use
(default: org.eclipse.jetty.util.log.Slf4jLog)
org.eclipse.jetty.util.log.DEBUG=[boolean]
Debug logs will be produced, along with the default logging levels of
INFO, WARN, and ERROR
(default: false)
org.eclipse.jetty.util.log.VERBOSE=[boolean]
Verbose logging is produced, including ignored exceptions
(default: false)
org.eclipse.jetty.util.log.IGNORED=[boolean]
Ignored exceptions are logged, independent of DEBUG and VERBOSE settings
(default: false)
STOP.PORT=[number]
The port to use to stop the running Jetty server.
Required along with STOP.KEY if you want to use the --stop option above.
STOP.KEY=[alphanumeric]
The passphrase defined to stop the server.
Requried along with STOP.PORT if you want to use the --stop option above.
OPTIONS=[mode,mode,...]
Classpath Options to use. Eg: All, Server, jmx, webapp, plus, etc...
(default: "default,*")
@OPTIONS@
Configs:
XML Configurations to use.
@CONFIGS@

View File

@ -0,0 +1,562 @@
// ========================================================================
// Copyright (c) Webtide LLC
// ------------------------------------------------------------------------
// 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.apache.org/licenses/LICENSE-2.0.txt
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.start;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import junit.framework.TestCase;
public class ConfigTest extends TestCase
{
private File jettyHomeDir;
private File resourcesDir;
private void assertEquals(String msg, Classpath expected, Classpath actual)
{
assertNotNull(msg + " : expected classpath should not be null",expected);
assertNotNull(msg + " : actual classpath should not be null",actual);
assertTrue(msg + " : expected should have an entry",expected.count() >= 1);
assertTrue(msg + " : actual should have an entry",actual.count() >= 1);
if (expected.count() != actual.count())
{
expected.dump(System.err);
actual.dump(System.err);
assertEquals(msg + " : count",expected.count(),actual.count());
}
List<File> actualEntries = Arrays.asList(actual.getElements());
List<File> expectedEntries = Arrays.asList(expected.getElements());
int len = expectedEntries.size();
for (int i = 0; i < len; i++)
{
File expectedFile = expectedEntries.get(i);
File actualFile = actualEntries.get(i);
if (!expectedFile.equals(actualFile))
{
expected.dump(System.err);
actual.dump(System.err);
assertEquals(msg + ": entry [" + i + "]",expectedEntries.get(i),actualEntries.get(i));
}
}
}
private void assertEquals(String msg, Collection<String> expected, Collection<String> actual)
{
assertTrue(msg + " : expected should have an entry",expected.size() >= 1);
assertEquals(msg + " : size",expected.size(),actual.size());
for (String expectedVal : expected)
{
assertTrue(msg + " : should contain <" + expectedVal + ">",actual.contains(expectedVal));
}
}
private String getJettyEtcFile(String name)
{
File etc = new File(getTestableJettyHome(),"etc");
return new File(etc,name).getAbsolutePath();
}
private File getJettyHomeDir()
{
if (jettyHomeDir == null)
{
jettyHomeDir = new File(getTestResourcesDir(),"jetty.home");
}
return jettyHomeDir;
}
private String getTestableJettyHome()
{
return getJettyHomeDir().getAbsolutePath();
}
private File getTestResourcesDir()
{
if (resourcesDir == null)
{
File src = new File(System.getProperty("user.dir"),"src");
File test = new File(src,"test");
resourcesDir = new File(test,"resources");
}
return resourcesDir;
}
/**
* Test for SUBJECT "/=" for assign canonical path
*/
public void testSubjectAssignCanonicalPath() throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append("test.resources.dir/=src/test/resources\n");
Config cfg = new Config();
cfg.parse(buf);
assertEquals(getTestResourcesDir().getCanonicalPath(),cfg.getProperty("test.resources.dir"));
}
/**
* Test for SUBJECT "~=" for assigning Start Properties
*/
public void testSubjectAssignStartProperty() throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append("test.jetty.start.text~=foo\n");
buf.append("test.jetty.start.quote~=Eatagramovabits\n");
Config options = new Config();
options.parse(buf);
assertEquals("foo",options.getProperty("test.jetty.start.text"));
assertEquals("Eatagramovabits",options.getProperty("test.jetty.start.quote"));
}
/**
* Test for SUBJECT "=" for assigning System Properties
*/
public void testSubjectAssignSystemProperty() throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append("test.jetty.start.text=foo\n");
buf.append("test.jetty.start.quote=Eatagramovabits\n");
Config options = new Config();
options.parse(buf);
assertEquals("foo",System.getProperty("test.jetty.start.text"));
assertEquals("Eatagramovabits",System.getProperty("test.jetty.start.quote"));
}
/**
* Test for SUBJECT ending with "/**", all jar and zip components in dir (deep, recursive)
*/
public void testSubjectComponentDirDeep() throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append("$(jetty.home)/lib/**\n");
String jettyHome = getTestableJettyHome();
Config options = new Config();
options.setProperty("jetty.home",jettyHome);
options.parse(buf);
Classpath actual = options.getClasspath();
Classpath expected = new Classpath();
File lib = new File(getJettyHomeDir(),"lib");
expected.addComponent(new File(lib,"core.jar"));
expected.addComponent(new File(lib,"example.jar"));
expected.addComponent(new File(lib,"http.jar"));
expected.addComponent(new File(lib,"io.jar"));
expected.addComponent(new File(lib,"JSR.ZIP"));
expected.addComponent(new File(lib,"LOGGING.JAR"));
expected.addComponent(new File(lib,"server.jar"));
expected.addComponent(new File(lib,"spec.zip"));
expected.addComponent(new File(lib,"util.jar"));
expected.addComponent(new File(lib,"xml.jar"));
File ext = new File(lib,"ext");
expected.addComponent(new File(ext,"custom-impl.jar"));
assertEquals("Components (Deep)",expected,actual);
}
/**
* Test for SUBJECT ending with "/*", all jar and zip components in dir (shallow, no recursion)
*/
public void testSubjectComponentDirShallow() throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append("# Example of any shallow components in /lib/\n");
buf.append("$(jetty.home)/lib/*\n");
String jettyHome = getTestableJettyHome();
Config options = new Config();
options.setProperty("jetty.home",jettyHome);
options.parse(buf);
Classpath actual = options.getClasspath();
Classpath expected = new Classpath();
File lib = new File(getJettyHomeDir(),"lib");
expected.addComponent(new File(lib,"core.jar"));
expected.addComponent(new File(lib,"example.jar"));
expected.addComponent(new File(lib,"http.jar"));
expected.addComponent(new File(lib,"io.jar"));
expected.addComponent(new File(lib,"JSR.ZIP"));
expected.addComponent(new File(lib,"LOGGING.JAR"));
expected.addComponent(new File(lib,"server.jar"));
expected.addComponent(new File(lib,"spec.zip"));
expected.addComponent(new File(lib,"util.jar"));
expected.addComponent(new File(lib,"xml.jar"));
assertEquals("Components (Shallow)",expected,actual);
}
/**
* Test for SUBJECT ending with ".class", a Main Class
*/
public void testSubjectMainClass() throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append("org.eclipse.jetty.xml.XmlConfiguration.class");
Config options = new Config();
options.parse(buf);
assertEquals("org.eclipse.jetty.xml.XmlConfiguration",options.getMainClassname());
}
/**
* Test for SUBJECT ending with ".class", a Main Class
*/
public void testSubjectMainClassConditionalPropertySet() throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append("org.eclipse.jetty.xml.XmlConfiguration.class\n");
buf.append("${start.class}.class property start.class");
Config options = new Config();
options.setProperty("start.class","net.company.server.Start");
options.parse(buf);
assertEquals("net.company.server.Start",options.getMainClassname());
}
/**
* Test for SUBJECT ending with ".class", a Main Class
*/
public void testSubjectMainClassConditionalPropertyUnset() throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append("org.eclipse.jetty.xml.XmlConfiguration.class\n");
buf.append("${start.class}.class property start.class");
Config options = new Config();
// The "start.class" property is unset.
options.parse(buf);
assertEquals("org.eclipse.jetty.xml.XmlConfiguration",options.getMainClassname());
}
/**
* Test for SUBJECT ending with "/", a simple Classpath Entry
*/
public void testSubjectSimpleComponent() throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append("$(jetty.home)/resources/\n");
String jettyHome = getTestableJettyHome();
Config options = new Config();
options.setProperty("jetty.home",jettyHome);
options.parse(buf);
Classpath actual = options.getClasspath();
Classpath expected = new Classpath();
expected.addComponent(new File(getJettyHomeDir(),"resources"));
assertEquals("Simple Component",expected,actual);
}
/**
* Test for SUBJECT ending with "/", a simple Classpath Entry
*/
public void testSubjectSimpleComponentMultiple() throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append("$(jetty.home)/resources/\n");
buf.append("$(jetty.home)/etc/\n");
String jettyHome = getTestableJettyHome();
Config options = new Config();
options.setProperty("jetty.home",jettyHome);
options.parse(buf);
Classpath actual = options.getClasspath();
Classpath expected = new Classpath();
expected.addComponent(new File(getJettyHomeDir(),"resources"));
expected.addComponent(new File(getJettyHomeDir(),"etc"));
assertEquals("Simple Component",expected,actual);
}
/**
* Test for SUBJECT ending with "/", a simple Classpath Entry
*/
public void testSubjectSimpleComponentNotExists() throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append("$(jetty.home)/resources/\n");
buf.append("$(jetty.home)/foo/\n");
String jettyHome = getTestableJettyHome();
Config options = new Config();
options.setProperty("jetty.home",jettyHome);
options.parse(buf);
Classpath actual = options.getClasspath();
Classpath expected = new Classpath();
expected.addComponent(new File(getJettyHomeDir(),"resources"));
assertEquals("Simple Component",expected,actual);
}
/**
* Test for SUBJECT ending with ".xml", an XML Configuration File
*/
public void testSubjectXmlConfigAlt() throws IOException
{
StringBuffer buf = new StringBuffer();
// Doesn't exist
buf.append("$(jetty.home)/etc/jetty.xml nargs == 0\n");
// test-alt does exist.
buf.append("./src/test/resources/test-alt.xml nargs == 0 AND ! exists $(jetty.home)/etc/jetty.xml");
String jettyHome = getTestableJettyHome();
Config options = new Config();
options.setProperty("jetty.home",jettyHome);
options.parse(buf);
List<String> actual = options.getXmlConfigs();
String expected = new File("src/test/resources/test-alt.xml").getAbsolutePath();
assertEquals("XmlConfig.size",1,actual.size());
assertEquals(expected,actual.get(0));
}
/**
* Test for SUBJECT ending with ".xml", an XML Configuration File
*/
public void testSubjectXmlConfigDefault() throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append("$(jetty.home)/etc/test-jetty.xml nargs == 0\n");
buf.append("./jetty-server/src/main/config/etc/test-jetty.xml nargs == 0 AND ! exists $(jetty.home)/etc/test-jetty.xml");
String jettyHome = getTestableJettyHome();
Config options = new Config();
options.setProperty("jetty.home",jettyHome);
options.parse(buf);
List<String> actual = options.getXmlConfigs();
String expected = getJettyEtcFile("test-jetty.xml");
assertEquals("XmlConfig.size",1,actual.size());
assertEquals(expected,actual.get(0));
}
/**
* Test for SUBJECT ending with ".xml", an XML Configuration File.
*/
public void testSubjectXmlConfigMultiple() throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append("$(jetty.home)/etc/test-jetty.xml nargs == 0\n");
buf.append("$(jetty.home)/etc/test-jetty-ssl.xml nargs == 0\n");
buf.append("$(jetty.home)/etc/test-jetty-security.xml nargs == 0\n");
String jettyHome = getTestableJettyHome();
Config options = new Config();
options.setProperty("jetty.home",jettyHome);
options.parse(buf);
List<String> actual = options.getXmlConfigs();
List<String> expected = new ArrayList<String>();
expected.add(getJettyEtcFile("test-jetty.xml"));
expected.add(getJettyEtcFile("test-jetty-ssl.xml"));
expected.add(getJettyEtcFile("test-jetty-security.xml"));
assertEquals("Multiple XML Configs",expected,actual);
}
/**
* Test Section Handling
*/
public void testSectionClasspathSingle() throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append("[All]\n");
buf.append("$(jetty.home)/lib/core-test.jar\n");
buf.append("$(jetty.home)/lib/util.jar\n");
String jettyHome = getTestableJettyHome();
Config options = new Config();
options.setProperty("jetty.home",jettyHome);
options.parse(buf);
Classpath defaultClasspath = options.getClasspath();
assertNotNull("Default Classpath should not be null",defaultClasspath);
Classpath foocp = options.getSectionClasspath("Foo");
assertNull("Foo Classpath should not exist",foocp);
Classpath allcp = options.getSectionClasspath("All");
assertNotNull("Classpath section 'All' should exist",allcp);
File lib = new File(getJettyHomeDir(),"lib");
Classpath expected = new Classpath();
expected.addComponent(new File(lib,"core-test.jar"));
expected.addComponent(new File(lib,"util.jar"));
assertEquals("Single Classpath Section",expected,allcp);
}
/**
* Test Section Handling
*/
public void testSectionClasspathAvailable() throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append("[All]\n");
buf.append("$(jetty.home)/lib/core.jar ! available org.eclipse.jetty.dummy.Handler\n");
buf.append("$(jetty.home)/lib/util.jar ! available org.eclipse.jetty.dummy.StringUtils\n");
String jettyHome = getTestableJettyHome();
Config options = new Config();
options.setProperty("jetty.home",jettyHome);
options.parse(buf);
Classpath defaultClasspath = options.getClasspath();
assertNotNull("Default Classpath should not be null",defaultClasspath);
Classpath foocp = options.getSectionClasspath("Foo");
assertNull("Foo Classpath should not exist",foocp);
Classpath allcp = options.getSectionClasspath("All");
assertNotNull("Classpath section 'All' should exist",allcp);
File lib = new File(getJettyHomeDir(),"lib");
Classpath expected = new Classpath();
expected.addComponent(new File(lib,"core.jar"));
expected.addComponent(new File(lib,"util.jar"));
assertEquals("Single Classpath Section",expected,allcp);
}
/**
* Test Section Handling, with multiple defined sections.
*/
public void testSectionClasspathMultiples() throws IOException
{
StringBuffer buf = new StringBuffer();
buf.append("# default\n");
buf.append("$(jetty.home)/lib/spec.zip\n");
buf.append("\n");
buf.append("[*]\n");
buf.append("$(jetty.home)/lib/io.jar\n");
buf.append("$(jetty.home)/lib/util.jar\n");
buf.append("\n");
buf.append("[All,server,default]\n");
buf.append("$(jetty.home)/lib/core.jar\n");
buf.append("$(jetty.home)/lib/server.jar\n");
buf.append("$(jetty.home)/lib/http.jar\n");
buf.append("\n");
buf.append("[All,xml,default]\n");
buf.append("$(jetty.home)/lib/xml.jar\n");
buf.append("\n");
buf.append("[All,logging]\n");
buf.append("$(jetty.home)/lib/LOGGING.JAR\n");
String jettyHome = getTestableJettyHome();
Config cfg = new Config();
cfg.setProperty("jetty.home",jettyHome);
cfg.parse(buf);
Classpath defaultClasspath = cfg.getClasspath();
assertNotNull("Default Classpath should not be null",defaultClasspath);
Classpath foocp = cfg.getSectionClasspath("Foo");
assertNull("Foo Classpath should not exist",foocp);
// Test if entire section list can be fetched
Set<String> sections = cfg.getSectionIds();
Set<String> expected = new HashSet<String>();
expected.add(Config.DEFAULT_SECTION);
expected.add("*");
expected.add("All");
expected.add("server");
expected.add("default");
expected.add("xml");
expected.add("logging");
assertEquals("Multiple Section IDs",expected,sections);
// Test fetch of specific section by name works
Classpath cpAll = cfg.getSectionClasspath("All");
assertNotNull("Classpath section 'All' should exist",cpAll);
File lib = new File(getJettyHomeDir(),"lib");
Classpath expectedAll = new Classpath();
expectedAll.addComponent(new File(lib,"core.jar"));
expectedAll.addComponent(new File(lib,"server.jar"));
expectedAll.addComponent(new File(lib,"http.jar"));
expectedAll.addComponent(new File(lib,"xml.jar"));
expectedAll.addComponent(new File(lib,"LOGGING.JAR"));
assertEquals("Classpath 'All' Section",expectedAll,cpAll);
// Test combined classpath fetch of multiple sections works
List<String> activated = new ArrayList<String>();
activated.add("server");
activated.add("logging");
Classpath cpCombined = cfg.getCombinedClasspath(activated);
Classpath expectedCombined = new Classpath();
// from default
expectedCombined.addComponent(new File(lib,"spec.zip"));
// from 'server'
expectedCombined.addComponent(new File(lib,"core.jar"));
expectedCombined.addComponent(new File(lib,"server.jar"));
expectedCombined.addComponent(new File(lib,"http.jar"));
// from 'logging'
expectedCombined.addComponent(new File(lib,"LOGGING.JAR"));
// from '*'
expectedCombined.addComponent(new File(lib,"io.jar"));
expectedCombined.addComponent(new File(lib,"util.jar"));
assertEquals("Classpath combined 'server,logging'",expectedCombined,cpCombined);
}
}

View File

@ -0,0 +1,59 @@
// ========================================================================
// Copyright (c) Webtide LLC
// ------------------------------------------------------------------------
// 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.apache.org/licenses/LICENSE-2.0.txt
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.start;
import junit.framework.TestCase;
public class VersionTest extends TestCase
{
public void testDefaultVersion()
{
Version version = new Version();
assertEquals("Default version difference to 0.0.0",0,version.compare(new Version("0.0.0")));
}
public void testNewerVersion() {
assertIsNewer("0.0.0", "0.0.1");
assertIsNewer("0.1.0", "0.1.1");
assertIsNewer("1.5.0", "1.6.0");
// assertIsNewer("1.6.0_12", "1.6.0_16"); // JDK version spec?
}
public void testOlderVersion() {
assertIsOlder("0.0.1", "0.0.0");
assertIsOlder("0.1.1", "0.1.0");
assertIsOlder("1.6.0", "1.5.0");
}
private void assertIsOlder(String basever, String testver)
{
Version vbase = new Version(basever);
Version vtest = new Version(testver);
assertTrue("Version [" + testver + "] should be older than [" + basever + "]",
vtest.compare(vbase) == -1);
}
private void assertIsNewer(String basever, String testver)
{
Version vbase = new Version(basever);
Version vtest = new Version(testver);
assertTrue("Version [" + testver + "] should be newer than [" + basever + "]",
vtest.compare(vbase) == 1);
}
}

View File

@ -0,0 +1 @@
<!-- nothing in here, just used to test the start.config logic in ConfigTest.java -->

View File

@ -0,0 +1 @@
<!-- nothing in here, just used to test the start.config logic in ConfigTest.java -->

View File

@ -0,0 +1 @@
<!-- nothing in here, just used to test the start.config logic in ConfigTest.java -->

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,5 @@
Many of these files are zero length on purpose.
Of those jars that have content, a simple "Hello World" style class has been
compiled (included) to allow the ConfigTest of available classes.
This directory is used by the various tests, and having legitimate jar/zip files
is often not important.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
# Nothing of importance, just used by ConfigTest.java

View File

@ -0,0 +1 @@
<!-- nothing in here, just used to test the start.config logic in ConfigTest.java -->