org.codehaus.groovy.tools.LoaderConfiguration Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of groovy-all Show documentation
Show all versions of groovy-all Show documentation
Groovy: A powerful, dynamic language for the JVM
/*
* Copyright 2003-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.groovy.tools;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Class used to configure a RootLoader from a stream or by using
* it's methods.
*
* The stream can be for example a FileInputStream from a file with
* the following format:
*
*
* # comment
* main is classname
* load path
* load file
* load pathWith${property}
* load pathWith!{required.property}
* load path/*.jar
* load path/**/*.jar
*
*
* - All lines starting with "#" are ignored.
* - The "main is" part may only be once in the file. The String
* afterwards is the name of a class with a main method.
* - The "load" command will add the given file or path to the
* classpath in this configuration object. If the path does not
* exist, the path will be ignored.
*
* - properties referenced using !{x} are required.
* - properties referenced using ${x} are not required. If the
* property does not exist the whole load instruction line will
* be ignored.
* - * is used to match zero or more characters in a file.
* - ** is used to match zero or more directories.
*
*
* Defining the main class is required unless setRequireMain(boolean) is
* called with false, before reading the configuration.
* You can use the wildcard "*" to filter the path, but only for files, not
* directories. To match directories use "**". The ${propertyname} is replaced by the value of the system's
* property name. You can use user.home here for example. If the property does
* not exist, an empty string will be used. If the path or file after the load
* command does not exist, the path will be ignored.
*
* @author Jochen Theodorou
* @version $Revision: 17789 $
* @see RootLoader
*/
public class LoaderConfiguration {
private static final String MAIN_PREFIX = "main is", LOAD_PREFIX = "load", PROP_PREFIX = "property";
private List classPath = new ArrayList();
private String main;
private boolean requireMain;
private static final char WILDCARD = '*';
private static final String ALL_WILDCARD = "" + WILDCARD + WILDCARD;
private static final String MATCH_FILE_NAME = "\\\\E[^/]+?\\\\Q";
private static final String MATCH_ALL = "\\\\E.+?\\\\Q";
/**
* creates a new loader configuration
*/
public LoaderConfiguration() {
this.requireMain = true;
}
/**
* configures this loader with a stream
*
* @param is stream used to read the configuration
* @throws IOException if reading or parsing the contents of the stream fails
*/
public void configure(InputStream is) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
int lineNumber = 0;
while (true) {
String line = reader.readLine();
if (line == null) break;
line = line.trim();
lineNumber++;
if (line.startsWith("#") || line.length() == 0) continue;
if (line.startsWith(LOAD_PREFIX)) {
String loadPath = line.substring(LOAD_PREFIX.length()).trim();
loadPath = assignProperties(loadPath);
loadFilteredPath(loadPath);
} else if (line.startsWith(MAIN_PREFIX)) {
if (main != null)
throw new IOException("duplicate definition of main in line " + lineNumber + " : " + line);
main = line.substring(MAIN_PREFIX.length()).trim();
} else if (line.startsWith(PROP_PREFIX)) {
String params = line.substring(PROP_PREFIX.length()).trim();
int index = params.indexOf('=');
if (index == -1) {
throw new IOException("unexpected property format - expecting name=value" + lineNumber + " : " + line);
}
String propName = params.substring(0, index);
String propValue= assignProperties(params.substring(index+1));
System.setProperty(propName, propValue);
} else {
throw new IOException("unexpected line in " + lineNumber + " : " + line);
}
}
if (requireMain && main == null) throw new IOException("missing main class definition in config file");
}
/*
* Expands the properties inside the given string to it's values.
*/
private String assignProperties(String str) {
int propertyIndexStart = 0, propertyIndexEnd = 0;
boolean requireProperty = false;
String result = "";
while (propertyIndexStart < str.length()) {
{
int i1 = str.indexOf("${", propertyIndexStart);
int i2 = str.indexOf("!{", propertyIndexStart);
if (i1 == -1) {
propertyIndexStart = i2;
} else if (i2 == -1) {
propertyIndexStart = i1;
} else {
propertyIndexStart = Math.min(i1, i2);
}
requireProperty = propertyIndexStart == i2;
}
if (propertyIndexStart == -1) break;
result += str.substring(propertyIndexEnd, propertyIndexStart);
propertyIndexEnd = str.indexOf("}", propertyIndexStart);
if (propertyIndexEnd == -1) break;
String propertyKey = str.substring(propertyIndexStart + 2, propertyIndexEnd);
String propertyValue = System.getProperty(propertyKey);
// assume properties contain paths
if (propertyValue == null) {
if (requireProperty) {
throw new IllegalArgumentException("Variable " + propertyKey + " in groovy-starter.conf references a non-existent System property! Try passing the property to the VM using -D" + propertyKey + "=myValue in JAVA_OPTS");
} else {
return null;
}
}
propertyValue = getSlashyPath(propertyValue);
propertyValue = correctDoubleSlash(propertyValue,propertyIndexEnd,str);
result += propertyValue;
propertyIndexEnd++;
propertyIndexStart = propertyIndexEnd;
}
if (propertyIndexStart == -1 || propertyIndexStart >= str.length()) {
result += str.substring(propertyIndexEnd);
} else if (propertyIndexEnd == -1) {
result += str.substring(propertyIndexStart);
}
return result;
}
private String correctDoubleSlash(String propertyValue, int propertyIndexEnd, String str) {
int index = propertyIndexEnd+1;
if ( index0)
{
propertyValue = propertyValue.substring(0,propertyValue.length()-1);
}
return propertyValue;
}
/*
* Load a possibly filtered path. Filters are defined
* by using the * wildcard like in any shell.
*/
private void loadFilteredPath(String filter) {
if (filter == null) return;
filter = getSlashyPath(filter);
int starIndex = filter.indexOf(WILDCARD);
if (starIndex == -1) {
addFile(new File(filter));
return;
}
boolean recursive = filter.indexOf(ALL_WILDCARD) != -1;
if (filter.lastIndexOf('/')