All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.start.Config Maven / Gradle / Ivy

There is a newer version: 12.0.13
Show newest version
//
//  ========================================================================
//  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.start;

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.io.Reader;
import java.io.StringReader;
import java.net.URL;
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.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;

/**
 * 

* It allows an application to be started with the command "java -jar start.jar". *

* *

* The behaviour of Main is controlled by the "org/eclipse/start/start.config" 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: *

* *

* Each line contains entry in the format: *

* *
 *   SUBJECT [ [!] CONDITION [AND|OR] ]*
 * 
* *

* where SUBJECT: *

*
    *
  • ends with ".class" is the Main class to run.
  • *
  • ends with ".xml" is a configuration file for the command line
  • *
  • ends with "/" is a directory from which to add all jar and zip files.
  • *
  • ends with "/*" is a directory from which to add all unconsidered jar and zip files.
  • *
  • ends with "/**" is a directory from which to recursively add all unconsidered jar and zip files.
  • *
  • Containing = are used to assign system properties.
  • *
  • Containing ~= are used to assign start properties.
  • *
  • Containing /= are used to assign a canonical path.
  • *
  • all other subjects are treated as files to be added to the classpath.
  • *
* *

* property expansion: *

*
    *
  • ${name} is expanded to a start property
  • *
  • $(name) is expanded to either a start property or a system property.
  • *
  • The start property ${version} is defined as the version of the start.jar
  • *
* *

* Files starting with "/" are considered absolute, all others are relative to the home directory. *

* *

* CONDITION is one of: *

*
    *
  • always
  • *
  • never
  • *
  • available classname - true if class on classpath
  • *
  • property name - true if set as start property
  • *
  • system name - true if set as system property
  • *
  • exists file - true if file/dir exists
  • *
  • java OPERATOR version - java version compared to literal
  • *
  • nargs OPERATOR number - number of command line args compared to literal
  • *
  • OPERATOR := one of "<",">","<=",">=", * "==","!="
  • *
* *

* CONDITIONS can be combined with AND OR or !, with AND being the * assume operator for a list of CONDITIONS. *

* *

* 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. *

* *

* The configuration file may be divided into sections with option names like: [ssl,default] *

* *

* Note: a special discovered section identifier [=path_to_directory/*] is allowed to auto-create section * IDs, based on directory names found in the path specified in the "path_to_directory/" part of the identifier. *

* *

* 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. : *

* *
 *    java -jar start.jar OPTIONS=jetty,jsp,ssl
 * 
* *

* The tag '*' is always appended to the options, so any section with the * tag is always applied. *

* *

* The property map maintained by this class is static and shared between all instances in the same classloader *

*/ public class Config { public static final String DEFAULT_SECTION = ""; static { String ver = System.getProperty("jetty.version", null); if(ver == null) { Package pkg = Config.class.getPackage(); if (pkg != null && "Eclipse.org - Jetty".equals(pkg.getImplementationVendor()) && (pkg.getImplementationVersion() != null)) { ver = pkg.getImplementationVersion(); } } if (ver == null) { ver = "Unknown"; } _version = ver; } /** * Natural language sorting for key names. */ private final Comparator keySorter = new Comparator() { private final 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 static final Map __properties = new HashMap(); private final Map _classpaths = new HashMap(); private final List _xml = new ArrayList(); private String _classname = null; private int argCount = 0; private final Set _activeOptions = new TreeSet(new Comparator() { // Make sure "*" is always at the end of the list public int compare(String o1, String o2) { if ("*".equals(o1)) { return 1; } if ("*".equals(o2)) { return -1; } return o1.compareTo(o2); } }); private boolean addClasspathComponent(List 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 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 sections, File dir, boolean recurse) throws IOException { List entries = new ArrayList(); 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()) { if (recurse) addJars(sections,entry,recurse); } else { String name = entry.getName().toLowerCase(Locale.ENGLISH); 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 = getProperty(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 active classpath, as dictated by OPTIONS= entries. * * @return the Active classpath * @see #getCombinedClasspath(Collection) */ public Classpath getActiveClasspath() { return getCombinedClasspath(_activeOptions); } /** * 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 optionIds * 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 optionIds) { Classpath cp = new Classpath(); cp.overlay(_classpaths.get(DEFAULT_SECTION)); for (String optionId : optionIds) { Classpath otherCp = _classpaths.get(optionId); if (otherCp == null) { throw new IllegalArgumentException("No such OPTIONS: " + optionId); } cp.overlay(otherCp); } cp.overlay(_classpaths.get("*")); return cp; } public String getMainClassname() { return _classname; } public static void clearProperties() { __properties.clear(); } public static Properties getProperties() { Properties properties = new Properties(); // Add System Properties First Enumeration ensysprop = System.getProperties().propertyNames(); while(ensysprop.hasMoreElements()) { String name = (String)ensysprop.nextElement(); properties.put(name, System.getProperty(name)); } // Add Config Properties Next (overwriting any System Properties that exist) for (String key : __properties.keySet()) { properties.put(key,__properties.get(key)); } return properties; } public static String getProperty(String name) { if ("version".equalsIgnoreCase(name)) { return _version; } // Search Config Properties First if (__properties.containsKey(name)) { return __properties.get(name); } // Return what exists in System.Properties otherwise. return System.getProperty(name); } public static String getProperty(String name, String defaultValue) { // Search Config Properties First if (__properties.containsKey(name)) return __properties.get(name); // Return what exists in System.Properties otherwise. return System.getProperty(name, defaultValue); } /** * Get the classpath for the named section * * @param sectionId * @return the classpath for the specified section id */ public Classpath getSectionClasspath(String sectionId) { return _classpaths.get(sectionId); } /** * Get the list of section Ids. * * @return the set of unique section ids */ public Set getSectionIds() { Set ids = new TreeSet(keySorter); ids.addAll(_classpaths.keySet()); return ids; } public List getXmlConfigs() { return _xml; } private boolean isAvailable(List options, String classname) { // Try default/parent class loader first. try { Class.forName(classname); return true; } catch (NoClassDefFoundError e) { debug(e); } catch (ClassNotFoundException e) { debug("ClassNotFoundException (parent class loader): " + classname); } // Try option classloaders instead ClassLoader loader; Classpath classpath; for (String optionId : options) { classpath = _classpaths.get(optionId); 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("ClassNotFoundException (section class loader: " + optionId + "): " + classname); } } 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 stream the stream to read from * @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 options = new ArrayList(); options.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("]")) { String identifier = trim.substring(1,trim.length() - 1); // Normal case: section identifier (possibly separated by commas) options = Arrays.asList(identifier.split(",")); List option_ids=new ArrayList(); // Ensure section classpaths exist for (String optionId : options) { if (optionId.charAt(0) == '=') continue; if (!_classpaths.containsKey(optionId)) _classpaths.put(optionId,new Classpath()); if (!option_ids.contains(optionId)) option_ids.add(optionId); } // Process Dynamic for (String optionId : options) { if (optionId.charAt(0) != '=') continue; option_ids = processDynamicSectionIdentifier(optionId.substring(1),option_ids); } options = option_ids; continue; } 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(options,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); continue; } // 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); continue; } // 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); continue; } // 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(options,dir,false); continue; } // 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(options,dir,true); continue; } // Add raw classpath directory to classpath if (subject.endsWith("/")) { // class directory File cd = new File(fixPath(file)); String d = cd.getCanonicalPath(); boolean added = addClasspathComponent(options,d); debug((added?" CLASSPATH+=":" !") + d); continue; } // Add XML configuration if (subject.toLowerCase(Locale.ENGLISH).endsWith(".xml")) { // Config file File f = new File(fixPath(file)); if (f.exists()) _xml.add(f.getCanonicalPath()); debug(" ARGS+=" + f); continue; } // Set the main class to execute (overrides any previously set) if (subject.toLowerCase(Locale.ENGLISH).endsWith(".class")) { // Class String cn = expand(subject.substring(0,subject.length() - 6)); if (cn != null && cn.length() > 0) { debug(" CLASS=" + cn); _classname = cn; } continue; } // Add raw classpath entry if (subject.toLowerCase(Locale.ENGLISH).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(options,cn); } continue; } // single JAR file File f = new File(fixPath(file)); if (f.exists()) { String d = f.getCanonicalPath(); boolean added = addClasspathComponent(options,d); if (!added) { added = addClasspathPath(options,expand(subject)); } debug((added?" CLASSPATH+=":" !") + d); } } catch (Exception e) { System.err.println("on line: '" + line + "'"); e.printStackTrace(); } } } finally { close(buf); } } private List processDynamicSectionIdentifier(String dynamicPathId,List sections) throws IOException { String rawPath; boolean deep; if (dynamicPathId.endsWith("/*")) { deep=false; rawPath = fixPath(dynamicPathId.substring(0,dynamicPathId.length() - 1)); } else if (dynamicPathId.endsWith("/**")) { deep=true; rawPath = fixPath(dynamicPathId.substring(0,dynamicPathId.length() - 2)); } else { String msg = "Illegal dynamic path [" + dynamicPathId + "]"; throw new IOException(msg); } File parentDir = new File(expand(rawPath)); if (!parentDir.exists()) return sections; debug("dynamic: " + parentDir); File dirs[] = parentDir.listFiles(new FileFilter() { public boolean accept(File path) { return path.isDirectory(); } }); List dyn_sections = new ArrayList(); List super_sections = new ArrayList(); if (sections!=null) super_sections.addAll(sections); for (File dir : dirs) { String id = dir.getName(); if (!_classpaths.keySet().contains(id)) _classpaths.put(id, new Classpath()); dyn_sections.clear(); if (sections!=null) dyn_sections.addAll(sections); dyn_sections.add(id); super_sections.add(id); debug("dynamic: " + dyn_sections); addJars(dyn_sections,dir,deep); } return super_sections; } 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); if (DEBUG) { System.setProperty("org.eclipse.jetty.util.log.stderr.DEBUG","true"); System.setProperty("org.eclipse.jetty.start.DEBUG","true"); } } if (name.equals("OPTIONS")) { _activeOptions.clear(); String ids[] = value.split(","); for (String id : ids) { addActiveOption(id); } } __properties.put(name,value); } public void addActiveOption(String option) { _activeOptions.add(option); __properties.put("OPTIONS",join(_activeOptions,",")); } public Set getActiveOptions() { return _activeOptions; } public void removeActiveOption(String option) { _activeOptions.remove(option); __properties.put("OPTIONS",join(_activeOptions,",")); } private String join(Collection coll, String delim) { StringBuffer buf = new StringBuffer(); Iterator i = coll.iterator(); boolean hasNext = i.hasNext(); while (hasNext) { buf.append(String.valueOf(i.next())); hasNext = i.hasNext(); if (hasNext) buf.append(delim); } return buf.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy