You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by bu...@apache.org on 2012/04/26 16:20:38 UTC
svn commit: r1330865 - in /uima/uimaj/trunk/uimaj-core/src:
main/java/org/apache/uima/ main/java/org/apache/uima/impl/
main/java/org/apache/uima/resource/impl/
main/java/org/apache/uima/resource/metadata/impl/
main/java/org/apache/uima/util/ main/java/...
Author: burn
Date: Thu Apr 26 14:20:37 2012
New Revision: 1330865
URL: http://svn.apache.org/viewvc?rev=1330865&view=rev
Log:
[UIMA-2378] Add interface Settings and move the lookup method to Settings_impl so it can be used outside UIMA annotators.
Added:
uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/Settings.java (with props)
Modified:
uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UimaContext.java
uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/impl/UimaContext_ImplBase.java
uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ConfigurationManager_impl.java
uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/ExternalOverrideSettings_impl.java
uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/impl/Settings_impl.java
uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/TestAnnotator2.java
Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UimaContext.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UimaContext.java?rev=1330865&r1=1330864&r2=1330865&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UimaContext.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UimaContext.java Thu Apr 26 14:20:37 2012
@@ -27,6 +27,7 @@ import org.apache.uima.cas.AbstractCas;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.SofaID;
import org.apache.uima.resource.ResourceAccessException;
+import org.apache.uima.resource.ResourceConfigurationException;
import org.apache.uima.resource.Session;
import org.apache.uima.util.InstrumentationFacility;
import org.apache.uima.util.Logger;
@@ -125,8 +126,9 @@ public interface UimaContext {
* @return the value of the parameter with the given name, as a String.
* Returns <code>null</code> if the parameter does not exist.
* Returns an empty string (<code>""</code>) if the parameter was not assigned a value.
+ * @throws ResourceConfigurationException if the parameter refers to an undefined variable
*/
- public String getExternalParameterValue(String aParamName);
+ public String getExternalParameterValue(String aParamName) throws ResourceConfigurationException;
/**
* Gets the <code>Logger</code> to which log output will be sent. UIMA components should use
Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/impl/UimaContext_ImplBase.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/impl/UimaContext_ImplBase.java?rev=1330865&r1=1330864&r2=1330865&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/impl/UimaContext_ImplBase.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/impl/UimaContext_ImplBase.java Thu Apr 26 14:20:37 2012
@@ -51,6 +51,7 @@ import org.apache.uima.cas.impl.CASImpl;
import org.apache.uima.jcas.JCas;
import org.apache.uima.resource.CasManager;
import org.apache.uima.resource.ResourceAccessException;
+import org.apache.uima.resource.ResourceConfigurationException;
import org.apache.uima.resource.ResourceInitializationException;
import org.apache.uima.resource.impl.ConfigurationManager_impl;
import org.apache.uima.resource.metadata.ConfigurationGroup;
@@ -478,8 +479,9 @@ public abstract class UimaContext_ImplBa
/**
* Lookup and evaluate an arbitrary (string) parameter from the External Override Settings
* Lets annotator configuration bypass the descriptor parameters.
+ * @throws ResourceConfigurationException
*/
- public String getExternalParameterValue(String name) {
+ public String getExternalParameterValue(String name) throws ResourceConfigurationException {
ConfigurationManager_impl cfgmgr = (ConfigurationManager_impl) getConfigurationManager();
return cfgmgr.getExternalParameter(mQualifiedContextName, name);
}
Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ConfigurationManager_impl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ConfigurationManager_impl.java?rev=1330865&r1=1330864&r2=1330865&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ConfigurationManager_impl.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ConfigurationManager_impl.java Thu Apr 26 14:20:37 2012
@@ -322,14 +322,11 @@ public class ConfigurationManager_impl e
* @param context - UIMA Context
* @param name - variable to look up
* @return - value of variable OR an exception message if definition is invalid
+ * @throws ResourceConfigurationException
*/
- public String getExternalParameter(String context, String name) {
+ public String getExternalParameter(String context, String name) throws ResourceConfigurationException {
ExternalOverrideSettings settings = getExternalOverrideSettings(context);
- try {
- String value = settings == null ? null : settings.resolveExternalName(name);
- return value == null ? null : escape(value);
- } catch (ResourceConfigurationException e) {
- return "*ERROR* " + e.getMessage();
- }
+ String value = settings == null ? null : settings.resolveExternalName(name);
+ return value == null ? null : escape(value);
}
}
Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/ExternalOverrideSettings_impl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/ExternalOverrideSettings_impl.java?rev=1330865&r1=1330864&r2=1330865&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/ExternalOverrideSettings_impl.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/ExternalOverrideSettings_impl.java Thu Apr 26 14:20:37 2012
@@ -9,8 +9,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import org.apache.uima.UIMAFramework;
import org.apache.uima.resource.ResourceConfigurationException;
@@ -48,11 +46,6 @@ public class ExternalOverrideSettings_im
*/
private boolean multipleEntries = false;
- /*
- * Regex that matches ${...}
- * non-greedy so stops on first '}' -- hence key cannot contain '}'
- */
- private Pattern evalPattern = Pattern.compile("\\$\\{.*?\\}");
/* (non-Javadoc)
* @see org.apache.uima.resource.metadata.ExternalOverrideSettings#getImport()
@@ -94,49 +87,6 @@ public class ExternalOverrideSettings_im
mImports = aImports;
}
- /*
- * Look up value for external name from the external override settings.
- * Perform one substitution pass on ${key} substrings. If key is undefined throw an exception.
- * Recursively evaluate the value to be substituted. NOTE: infinite loops not detected!
- * To avoid evaluation and get ${key} in the output use a property to generate the $, e.g.
- * $ = $
- * key = ${$}{key}
- * or escape the $
- * key = \${key}
- */
- public String resolveExternalName(String name) throws ResourceConfigurationException {
- String value;
- if (mProperties == null || (value = mProperties.getProperty(name)) == null) {
- return null;
- }
- Matcher matcher = evalPattern.matcher(value);
- StringBuilder result = new StringBuilder(value.length() + 100);
- int lastEnd = 0;
- while (matcher.find()) {
- // Check if the $ is escaped
- if (mProperties.isEscaped(value, matcher.start())) {
- result.append(value.substring(lastEnd, matcher.start() + 1));
- lastEnd = matcher.start() + 1; // copy the escaped $ and restart after it
- } else {
- result.append(value.substring(lastEnd, matcher.start()));
- lastEnd = matcher.end();
- String key = value.substring(matcher.start() + 2, lastEnd - 1);
- String val = resolveExternalName(key);
- if (val == null) { // External override variable "{0}" references the undefined variable "{1}"
- throw new ResourceConfigurationException(ResourceConfigurationException.EXTERNAL_OVERRIDE_INVALID,
- new Object[] { name, key });
- }
- result.append(val);
- }
- }
- if (lastEnd == 0) {
- return value;
- } else {
- result.append(value.substring(lastEnd));
- return result.toString();
- }
- }
-
/* (non-Javadoc)
* @see org.apache.uima.resource.metadata.ExternalOverrideSettings#resolveImports()
*/
@@ -217,6 +167,11 @@ public class ExternalOverrideSettings_im
}
}
+ @Override
+ public String resolveExternalName(String name) throws ResourceConfigurationException {
+ return mProperties == null ? null : mProperties.lookUp(name);
+ }
+
protected XmlizationInfo getXmlizationInfo() {
return XMLIZATION_INFO;
}
Added: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/Settings.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/Settings.java?rev=1330865&view=auto
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/Settings.java (added)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/Settings.java Thu Apr 26 14:20:37 2012
@@ -0,0 +1,60 @@
+package org.apache.uima.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Set;
+
+import org.apache.uima.resource.ResourceConfigurationException;
+
+/**
+ * A <code>Settings</code> object holds the properties used for external parameter overrides.
+ *
+ * Similar to java.util.Properties but:
+ * - supports UTF-8 (so \\uXXXX escapes are not needed or supported)
+ * - keys must be valid Java identifiers (actually must not contain '=' ':' '}' or white-space)
+ * - reverses priority in that duplicate entries are ignored, i.e. once set values cannot be changed
+ * - multiple files can be loaded
+ * - values can contain references to other values, e.g. name = .... ${key} ....
+ * - arrays are represented as strings, e.g. '[elem1,elem2]', and can span multiple lines
+ * - '\' can be used in values to escape '$' '{' '[' ',' ']'
+ *
+ * @author burn
+ *
+ */
+
+public interface Settings {
+
+ /**
+ * Load properties from an input stream.
+ * Existing properties are not changed and a warning is logged if the new value is different.
+ * May be called multiple times, so effective search is in load order.
+ * Arrays are enclosed in [] and the elements may be separated by <code>,</code> or new-line, so
+ * can span multiple lines without using a final \
+ *
+ * @param in - Stream holding properties
+ * @throws IOException
+ */
+ public void load(InputStream in) throws IOException;
+
+ /**
+ * Look up the value for a property.
+ * Perform one substitution pass on ${key} substrings replacing them with the value for key.
+ * Recursively evaluate the value to be substituted. NOTE: infinite loops not detected!
+ * If the key variable has not been defined, an exception is thrown.
+ * To avoid evaluation and get ${key} in the output escape the $ or {
+ * Arrays are returned as a comma-separated string, e.g. "[elem1,elem2]"
+ * Note: escape characters are not removed as they may affect array separators.
+ *
+ * @param name - name to look up
+ * @return - value of property
+ * @throws ResourceConfigurationException
+ */
+ public String lookUp(String name) throws ResourceConfigurationException;
+
+ /**
+ * Return a set of keys of all properties loaded
+ *
+ * @return - set of strings
+ */
+ public Set<String> getKeys();
+}
Propchange: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/Settings.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/impl/Settings_impl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/impl/Settings_impl.java?rev=1330865&r1=1330864&r2=1330865&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/impl/Settings_impl.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/impl/Settings_impl.java Thu Apr 26 14:20:37 2012
@@ -7,9 +7,13 @@ import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.apache.uima.UIMAFramework;
+import org.apache.uima.resource.ResourceConfigurationException;
import org.apache.uima.util.Level;
+import org.apache.uima.util.Settings;
/**
* Class that reads properties files containing external parameter overrides used by the ExternalOverrideSettings_impl
@@ -25,7 +29,7 @@ import org.apache.uima.util.Level;
*
*/
-public class Settings_impl {
+public class Settings_impl implements Settings {
protected static final String LOG_RESOURCE_BUNDLE = "org.apache.uima.impl.log_messages";
@@ -33,35 +37,40 @@ public class Settings_impl {
private Map<String, String> map;
+ /*
+ * Regex that matches ${...}
+ * non-greedy so stops on first '}' -- hence key cannot contain '}'
+ */
+ private Pattern evalPattern = Pattern.compile("\\$\\{.*?\\}");
+
public Settings_impl() {
map = new HashMap<String, String>();
}
/**
- * Get the value of a property with the specified key
- */
- public String getProperty(String key) {
- return map.get(key);
- }
-
- /*
* Return a set of keys of all properties in the map
+ *
+ * @return - set of strings
*/
public Set<String> getKeys() {
return map.keySet();
}
- /*
- * Load properties from an input stream Existing properties are not replaced (unlike java.util.Properties) May be
- * called multiple times
+ /**
+ * Load properties from an input stream.
+ * Existing properties are not replaced (unlike java.util.Properties).
+ * May be called multiple times.
+ *
+ * @param in - Stream holding properties
+ * @throws IOException
*/
public void load(InputStream in) throws IOException {
// Process each logical line (after blanks & comments removed and continuations extended)
rdr = new BufferedReader(new InputStreamReader(in, "UTF-8"));
String line;
while ((line = getLine()) != null) {
- // Split into two -- on '=' or ':' or white-space
- String[] parts = line.trim().split("\\s*[:=\\s]\\s*", 2);
+ // Remove surrounding white-space and split on first '=' or ':' or white-space
+ String[] parts = line.split("\\s*[:=\\s]\\s*", 2);
String name = parts[0];
String value;
// When RHS is empty get a split only for the := separators
@@ -76,32 +85,80 @@ public class Settings_impl {
if (!map.containsKey(name)) {
map.put(name, value);
} else {
- // Key {0} already in use ... ignoring value "{1}"
- UIMAFramework.getLogger(this.getClass()).logrb(Level.WARNING, this.getClass().getName(), "load",
- LOG_RESOURCE_BUNDLE, "UIMA_external_override_ignored__WARNING", new Object[] { name, value });
+ if (!value.equals(map.get(name))) {
+ // Key {0} already in use ... ignoring value "{1}"
+ UIMAFramework.getLogger(this.getClass()).logrb(Level.WARNING, this.getClass().getName(), "load",
+ LOG_RESOURCE_BUNDLE, "UIMA_external_override_ignored__WARNING", new Object[] { name, value });
+ }
}
}
}
+ /**
+ * Look up the value for a property.
+ * Perform one substitution pass on ${key} substrings. If key is undefined throw an exception.
+ * Recursively evaluate the value to be substituted. NOTE: infinite loops not detected!
+ * To avoid evaluation and get ${key} in the output use a property to generate the $, e.g.
+ * $ = $
+ * key = ${$}{key}
+ * or escape the $
+ * key = \${key}
+ *
+ * @param name - name to look up
+ * @return - value of property
+ * @throws ResourceConfigurationException
+ */
+ public String lookUp(String name) throws ResourceConfigurationException {
+ String value;
+ if ((value = map.get(name)) == null) {
+ return null;
+ }
+ Matcher matcher = evalPattern.matcher(value);
+ StringBuilder result = new StringBuilder(value.length() + 100);
+ int lastEnd = 0;
+ while (matcher.find()) {
+ // Check if the $ is escaped
+ if (isEscaped(value, matcher.start())) {
+ result.append(value.substring(lastEnd, matcher.start() + 1));
+ lastEnd = matcher.start() + 1; // copy the escaped $ and restart after it
+ } else {
+ result.append(value.substring(lastEnd, matcher.start()));
+ lastEnd = matcher.end();
+ String key = value.substring(matcher.start() + 2, lastEnd - 1);
+ String val = lookUp(key);
+ if (val == null) { // External override variable "{0}" references the undefined variable "{1}"
+ throw new ResourceConfigurationException(ResourceConfigurationException.EXTERNAL_OVERRIDE_INVALID,
+ new Object[] { name, key });
+ }
+ result.append(val);
+ }
+ }
+ if (lastEnd == 0) {
+ return value;
+ } else {
+ result.append(value.substring(lastEnd));
+ return result.toString();
+ }
+ }
+
/*
* Create a string representing an array from one or more logical lines
* Assert: line length > 0
*/
private String getArray(String line) throws IOException {
-
int iend = line.indexOf(']');
while (iend >= 0 && isEscaped(line, iend)) {
iend = line.indexOf(']', iend + 1);
}
if (iend >= 0) {
// Found the closing ']' - remainder of line must be empty
- if (line.substring(iend + 1, line.length()).trim().length() > 0) {
- throw new IOException("Syntax error - invalid characters after ']'");
+ if (iend + 1 < line.length()) {
+ throw new IOException("Syntax error - invalid character(s) '" +
+ line.substring(iend + 1, line.length()) + "' after end of array");
}
return line;
}
- // Trim each logical line as may be a single array element
// If line doesn't end with a , add one and append the next line(s)
// Don't add a , if line has only '[' or ']'
String nextline = getLine();
@@ -110,53 +167,60 @@ public class Settings_impl {
}
iend = line.length() - 1;
if ((line.charAt(iend) == ',' && !isEscaped(line, iend)) ||
- line.equals("[") || nextline.trim().charAt(0) == ']') {
- return line + getArray(nextline.trim());
+ line.equals("[") || nextline.charAt(0) == ']') {
+ return line + getArray(nextline);
} else {
- return line + "," + getArray(nextline.trim());
+ return line + "," + getArray(nextline);
}
}
/*
- * Reads a logical line from the input stream following the Java Properties class rules Ignore blank lines or comments
- * (first non-blank is '#' or '!') An un-escaped final '\' marks a continuation line
+ * Reads a logical line from the input stream following the Java Properties class rules.
+ * Ignore blank lines or comments (first non-blank is '#' or '!').
+ * An un-escaped final '\' marks a continuation line.
+ * Leading and trailing whitespace is removed from each physical line, and hence from the logical line.
*/
private String getLine() throws IOException {
String line = rdr.readLine();
if (line == null) {
return null;
}
- // If line is blank or a comment get another & check it again
+ // If line is blank or a comment discard it and get another
String trimmed = line.trim();
if (trimmed.length() == 0 || trimmed.charAt(0) == '#' || trimmed.charAt(0) == '!') {
return getLine();
}
- // Append further lines if should be continued
- // Don't trim as could change what a final \ is escaping
- return extendLine(line);
+ // Check the untrimmed line to see if it should be continued
+ if (!isEscaped(line, line.length())) {
+ return trimmed;
+ }
+ return extendLine(trimmed);
}
/*
- * If line should be continued read another and append it
+ * Remove final \ and append another line (or lines)
*/
private String extendLine(String line) throws IOException {
- // Check if line-end is escaped
- if (!isEscaped(line, line.length())) {
- return line;
- }
+
// Line must be continued ... remove the final \ and append the next line, etc.
int ilast = line.length() - 1;
String next = rdr.readLine();
if (next == null) {
- return line.substring(0, ilast);
+ next = "";
+ }
+ // Append the trimmed line but check the untrimmed line for a final \
+ line = line.substring(0, ilast) + next.trim();
+ if (!isEscaped(next, next.length())) {
+ return line.trim(); // Complete line may need more trimming
}
- return line.substring(0, ilast) + extendLine(next);
+ return extendLine(line);
}
/*
* Check if a character in the string is escaped, i.e. preceded by an odd number of '\'s
+ * Correctly returns false if ichar <= 0
*/
- public boolean isEscaped(String line, int ichar) {
+ private boolean isEscaped(String line, int ichar) {
int i = ichar - 1;
while (i >= 0 && line.charAt(i) == '\\') {
--i;
Modified: uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/TestAnnotator2.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/TestAnnotator2.java?rev=1330865&r1=1330864&r2=1330865&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/TestAnnotator2.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/TestAnnotator2.java Thu Apr 26 14:20:37 2012
@@ -19,6 +19,9 @@
package org.apache.uima.analysis_engine.impl;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
import junit.framework.Assert;
import org.apache.uima.UimaContext;
@@ -27,7 +30,10 @@ import org.apache.uima.analysis_engine.R
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.TypeSystem;
import org.apache.uima.impl.UimaContext_ImplBase;
+import org.apache.uima.resource.ResourceConfigurationException;
import org.apache.uima.resource.ResourceInitializationException;
+import org.apache.uima.util.Settings;
+import org.apache.uima.util.impl.Settings_impl;
/**
* Annotator class used for testing.
@@ -59,9 +65,33 @@ public class TestAnnotator2 extends CasA
// Check if can get an arbitrary external parameter from the override settings
String contextName = ((UimaContext_ImplBase) aContext).getQualifiedContextName();
if ("/ExternalOverrides/".equals(contextName)) {
- String actual = aContext.getExternalParameterValue("test.externalStringArray");
+ String actual = null;
+ try {
+ actual = aContext.getExternalParameterValue("test.externalStringArray");
+ } catch (ResourceConfigurationException e) {
+ Assert.fail(e.getMessage());
+ }
String expected = "[prefix_from_import,-,suffix_from_inline,->,prefix_from_import-suffix_from_inline]";
Assert.assertEquals(expected, actual);
+
+ // Test a stand-alone settings object
+ Settings testSettings = new Settings_impl();
+ String lines = "foo = ${bar} \n bar : [ok \n OK] \n bad = ${missing}";
+ InputStream is;
+ try {
+ is = new ByteArrayInputStream(lines.getBytes("UTF-8"));
+ testSettings.load(is);
+ String val = testSettings.lookUp("foo");
+ Assert.assertEquals("[ok,OK]", val);
+ try {
+ val = testSettings.lookUp("bad");
+ Assert.fail("\"bad\" should create an error");
+ } catch (ResourceConfigurationException e) {
+ System.err.println("Expected exception: " + e.toString());
+ }
+ } catch (Exception e) {
+ Assert.fail(e.toString());
+ }
}
}