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 2016/08/22 21:32:38 UTC

svn commit: r1757287 - in /uima/uimaj/trunk/uimaj-core/src: main/java/org/apache/uima/ main/java/org/apache/uima/analysis_engine/asb/impl/ main/java/org/apache/uima/analysis_engine/impl/ main/java/org/apache/uima/impl/ main/java/org/apache/uima/resourc...

Author: burn
Date: Mon Aug 22 21:32:38 2016
New Revision: 1757287

URL: http://svn.apache.org/viewvc?rev=1757287&view=rev
Log:
UIMA-5043 Add methods to access Settings from the UimaContext; POJOs can use UimaContextHolder to get the context

Added:
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UimaContextHolder.java   (with props)
    uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/util/UimaContextHolderTest.java   (with props)
Modified:
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/ResourceSpecifierFactory.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UimaContext.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/analysis_engine/asb/impl/FlowControllerContainer.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/PrimitiveAnalysisEngine_impl.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/impl/ResourceSpecifierFactory_impl.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/ResourceConfigurationException.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/Import_impl.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/Settings.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/impl/Settings_impl.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/impl/XMLParser_impl.java
    uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties
    uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/impl/factoryConfig.xml
    uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/impl/log_messages.properties
    uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/AnalysisEngine_implTest.java
    uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/TestAnnotator2.java
    uima/uimaj/trunk/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/AnnotatorWithExternalOverrides.xml
    uima/uimaj/trunk/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride.settings
    uima/uimaj/trunk/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride2.settings

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/ResourceSpecifierFactory.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/ResourceSpecifierFactory.java?rev=1757287&r1=1757286&r2=1757287&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/ResourceSpecifierFactory.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/ResourceSpecifierFactory.java Mon Aug 22 21:32:38 2016
@@ -80,6 +80,7 @@ import org.apache.uima.resource.metadata
 import org.apache.uima.resource.metadata.TypePriorities;
 import org.apache.uima.resource.metadata.TypePriorityList;
 import org.apache.uima.resource.metadata.TypeSystemDescription;
+import org.apache.uima.util.Settings;
 
 /**
  * A factory used to create {@link org.apache.uima.resource.ResourceSpecifier} instances and
@@ -232,6 +233,13 @@ public interface ResourceSpecifierFactor
    * @return an instance of an object implementing <code>ConfigurationParameterSettings</code>.
    */
   public ConfigurationParameterSettings createConfigurationParameterSettings();
+  
+  /**
+   * Creates an empty <code>Settings</code> for External Override parameters.
+   * 
+   * @return an instance of an object implementing <code>Settings</code>.
+   */
+  public Settings createSettings();
 
   /**
    * Creates a <code>Capability</code>.

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=1757287&r1=1757286&r2=1757287&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 Mon Aug 22 21:32:38 2016
@@ -22,14 +22,17 @@ package org.apache.uima;
 import java.io.InputStream;
 import java.net.URI;
 import java.net.URL;
+import java.util.Set;
 
 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;
+import org.apache.uima.util.Settings;
 
 /**
  * Provides access to external resources (other than the CAS). The <code>UimaContext</code>
@@ -115,6 +118,40 @@ public interface UimaContext {
   public String[] getConfigParameterNames();
 
   /**
+   * Get the value of an external override setting.
+   * 
+   * @param name - the name of the parameter
+   * @return     - the value found in the settings file(s), or null if missing.
+   * @throws ResourceConfigurationException 
+   *                 if the value references an undefined property, or the value is an array
+   */
+  public String getSetting(String name) throws ResourceConfigurationException;
+  
+  /**
+  * Get the array of values for an external override setting.
+  * 
+  * @param name  - the name of the parameter
+  * @return      - an array of values found in the settings file(s), or null if missing.
+  * @throws ResourceConfigurationException 
+  *                  if the value references an undefined property, or the value is not an array
+  */
+  public String[] getSettingArray(String name) throws ResourceConfigurationException;
+  
+  /**
+   * Return a set containing the names of all the external override settings available
+   * 
+   * @return - set of strings
+   */
+  public Set<String> getSettingNames();
+  
+  /**
+   * Gets the <code>Settings</code> used for external parameter overrides
+   *  
+   * @return the Settings object
+   */
+  public Settings getExternalOverrides();
+  
+  /**
    * Gets the <code>Logger</code> to which log output will be sent. UIMA components should use
    * this facility rather than writing to their own log files (or to stdout).
    * 
@@ -492,4 +529,5 @@ public interface UimaContext {
    * @return an empty CAS. This will be an implementation of <code>aCasInterface</code>.
    */
   public <T extends AbstractCas> T getEmptyCas(Class<T> aCasInterface);
+  
 }

Added: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UimaContextHolder.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UimaContextHolder.java?rev=1757287&view=auto
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UimaContextHolder.java (added)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UimaContextHolder.java Mon Aug 22 21:32:38 2016
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.uima;
+
+/**
+ * This class holds the UimaContext for the current thread, or a parent thread.
+ * The getContext method may be used by any plain Java class invoked by an annotator,
+ * The POJO must run in the same thread or a child thread of the annotator.
+ * 
+ * For example a POJO can access the shared External Override Settings with:
+ *     String paramValue = UimaContextHolder.getContext().getSetting(paramName);
+ */
+public class UimaContextHolder {
+  
+  private static InheritableThreadLocal<UimaContext> threadLocalContext = new InheritableThreadLocal<UimaContext>();
+  
+  /**
+   * Get the UimaContext for this thread
+   * 
+   * @return      the thread-specific UimaContext
+   */
+  public static UimaContext getContext() {
+    return threadLocalContext.get();
+  }
+  
+  /**
+   * Sets the UimaContext for the current thread.
+   * <p>
+   * NOTE - Should be used only by the UIMA Framework.
+   * 
+   * @param uimaContext
+   */
+  public static void setContext(UimaContext uimaContext) {
+    threadLocalContext.set(uimaContext);;
+  }
+  
+  /**
+   * Clears the UimaContext entry for the current thread
+   * <p>
+   * NOTE - Should be used only by the UIMA Framework.
+   */
+  public static void clearContext() {
+    threadLocalContext.set(null);
+  }
+}

Propchange: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UimaContextHolder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/analysis_engine/asb/impl/FlowControllerContainer.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/analysis_engine/asb/impl/FlowControllerContainer.java?rev=1757287&r1=1757286&r2=1757287&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/analysis_engine/asb/impl/FlowControllerContainer.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/analysis_engine/asb/impl/FlowControllerContainer.java Mon Aug 22 21:32:38 2016
@@ -25,6 +25,7 @@ import java.util.Map;
 import org.apache.uima.Constants;
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.UimaContextAdmin;
+import org.apache.uima.UimaContextHolder;
 import org.apache.uima.analysis_engine.AnalysisEngine;
 import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
 import org.apache.uima.analysis_engine.impl.AnalysisEngineManagementImpl;
@@ -46,6 +47,7 @@ import org.apache.uima.resource.Resource
 import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.resource.ResourceSpecifier;
 import org.apache.uima.resource.metadata.ProcessingResourceMetaData;
+import org.apache.uima.util.Level;
 import org.apache.uima.util.Logger;
 import org.apache.uima.util.UimaTimer;
 
@@ -63,6 +65,8 @@ public class FlowControllerContainer ext
   private Object mMBeanServer;
   
   private boolean initialized = false;
+  
+  private static final String LOG_RESOURCE_BUNDLE = "org.apache.uima.impl.log_messages";
 
   /*
    * (non-Javadoc)
@@ -114,9 +118,14 @@ public class FlowControllerContainer ext
       UimaContextAdmin uimaContext = getUimaContextAdmin();
       Logger logger = UIMAFramework.getLogger(mFlowController.getClass());
       logger.setResourceManager(this.getResourceManager());
-      uimaContext.setLogger(logger);      
+      uimaContext.setLogger(logger);
+      
+      Logger classLogger = getLogger();
+      classLogger.logrb(Level.CONFIG, this.getClass().getName(), "initialize", LOG_RESOURCE_BUNDLE,
+              "UIMA_flow_controller_init_begin__CONFIG", getMetaData().getName());
       
       // initialize FlowController
+      UimaContextHolder.setContext(getFlowControllerContext());  // for use by POJOs
       mFlowController.initialize(getFlowControllerContext());
 
       mMBeanServer = null;
@@ -132,10 +141,15 @@ public class FlowControllerContainer ext
       // (Java 1.5 only)
       JmxMBeanAgent.registerMBean(getMBean(), mMBeanServer);
 
+      classLogger.logrb(Level.CONFIG, this.getClass().getName(), "initialize", LOG_RESOURCE_BUNDLE,
+              "UIMA_flow_controller_init_successful__CONFIG", getMetaData().getName());
+      
       initialized = true;
       return true;
     } catch (ResourceConfigurationException e) {
       throw new ResourceInitializationException(e);
+    } finally {
+      UimaContextHolder.clearContext();
     }
   }
 
@@ -165,9 +179,12 @@ public class FlowControllerContainer ext
    */
   public void reconfigure() throws ResourceConfigurationException {
     try {
+      UimaContextHolder.setContext(getFlowControllerContext());  // for use by POJOs
       mFlowController.reconfigure();
     } catch (ResourceInitializationException e) {
       throw new ResourceConfigurationException(e);
+    } finally {
+      UimaContextHolder.clearContext();
     }
   }
 
@@ -177,7 +194,9 @@ public class FlowControllerContainer ext
    * @see org.apache.uima.resource.Resource_ImplBase#destroy()
    */
   public void destroy() {
+    UimaContextHolder.setContext(getFlowControllerContext());  // for use by POJOs
     mFlowController.destroy();
+    UimaContextHolder.clearContext();
     super.destroy();
   }
 
@@ -200,6 +219,7 @@ public class FlowControllerContainer ext
       view = Util.getStartingView(aCAS, mSofaAware, getUimaContextAdmin().getComponentInfo());
 
       // now get the right interface(e.g. CAS or JCAS)
+      UimaContextHolder.setContext(getFlowControllerContext());  // for use by POJOs
       Class<? extends AbstractCas> requiredInterface = mFlowController.getRequiredCasInterface();
       AbstractCas casToPass = getCasManager().getCasInterface(view, requiredInterface);    
       ((CASImpl)view).switchClassLoaderLockCasCL(this.getResourceManager().getExtensionClassLoader());
@@ -221,6 +241,7 @@ public class FlowControllerContainer ext
       mTimer.stopIt();
       getMBean().reportAnalysisTime(mTimer.getDuration());
       getMBean().incrementCASesProcessed();
+      UimaContextHolder.clearContext();
     }
   }
 
@@ -228,7 +249,12 @@ public class FlowControllerContainer ext
    * @return  the required CAS interface of the FlowController
    */
   public Class<? extends AbstractCas> getRequiredCasInterface() {
-    return mFlowController.getRequiredCasInterface();
+    try {
+      UimaContextHolder.setContext(getFlowControllerContext());  // for use by POJOs
+      return mFlowController.getRequiredCasInterface();
+    } finally {
+      UimaContextHolder.clearContext();
+    }
   }
 
   public ProcessingResourceMetaData getProcessingResourceMetaData() {
@@ -248,7 +274,9 @@ public class FlowControllerContainer ext
    * @param aKeys the keys for the delegates
    */
   public void addAnalysisEngines(Collection<String> aKeys) {
+    UimaContextHolder.setContext(getFlowControllerContext());  // for use by POJOs
     mFlowController.addAnalysisEngines(aKeys);
+    UimaContextHolder.clearContext();
   }
 
   /**
@@ -258,7 +286,9 @@ public class FlowControllerContainer ext
    * @throws AnalysisEngineProcessException - 
    */
   public void removeAnalysisEngines(Collection<String> aKeys) throws AnalysisEngineProcessException {
+    UimaContextHolder.setContext(getFlowControllerContext());  // for use by POJOs
     mFlowController.removeAnalysisEngines(aKeys);
+    UimaContextHolder.clearContext();
   }
 
 
@@ -314,7 +344,9 @@ public class FlowControllerContainer ext
   }
   public void collectionProcessComplete() throws AnalysisEngineProcessException {
     if ( mFlowController != null ) {
+      UimaContextHolder.setContext(getFlowControllerContext());  // for use by POJOs
       mFlowController.collectionProcessComplete();
+      UimaContextHolder.clearContext();
     }
   }
 }

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/PrimitiveAnalysisEngine_impl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/PrimitiveAnalysisEngine_impl.java?rev=1757287&r1=1757286&r2=1757287&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/PrimitiveAnalysisEngine_impl.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/PrimitiveAnalysisEngine_impl.java Mon Aug 22 21:32:38 2016
@@ -26,6 +26,7 @@ import org.apache.uima.Constants;
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.UIMA_IllegalStateException;
 import org.apache.uima.UimaContextAdmin;
+import org.apache.uima.UimaContextHolder;
 import org.apache.uima.analysis_component.AnalysisComponent;
 import org.apache.uima.analysis_engine.AnalysisEngine;
 import org.apache.uima.analysis_engine.AnalysisEngineDescription;
@@ -235,6 +236,7 @@ public class PrimitiveAnalysisEngine_imp
       return;
     }
 
+    UimaContextHolder.setContext(getUimaContext());  // for use by POJOs
     try {
       Object userObject = annotatorClass.newInstance();
       if (userObject instanceof AnalysisComponent) {
@@ -260,16 +262,15 @@ public class PrimitiveAnalysisEngine_imp
     // initialize AnalysisComponent
     try {
       mAnalysisComponent.initialize(getUimaContext());
+      // set up the CAS pool for this AE (this won't do anything if mAnalysisComponent.getCasInstancesRequired() == 0)
+      getUimaContextAdmin().defineCasPool(mAnalysisComponent.getCasInstancesRequired(),
+              getPerformanceTuningSettings(), mSofaAware);
     } catch (Exception e) {
       throw new ResourceInitializationException(
               ResourceInitializationException.ANNOTATOR_INITIALIZATION_FAILED, new Object[] {
                   annotatorClassName, mDescription.getSourceUrlString() }, e);
-    }
-
-    // set up the CAS pool for this AE (this won't do anything if
-    // mAnalysisComponent.getCasInstancesRequired() == 0)
-    getUimaContextAdmin().defineCasPool(mAnalysisComponent.getCasInstancesRequired(),
-            getPerformanceTuningSettings(), mSofaAware);
+    } 
+    UimaContextHolder.clearContext();
   }
 
   /**
@@ -277,7 +278,9 @@ public class PrimitiveAnalysisEngine_imp
    */
   public void destroy() {
     if (mAnalysisComponent != null) {
+      UimaContextHolder.setContext(getUimaContext());  // for use by POJOs
       mAnalysisComponent.destroy();
+      UimaContextHolder.clearContext();
       getLogger().logrb(Level.CONFIG, CLASS_NAME.getName(), "destroy", LOG_RESOURCE_BUNDLE,
               "UIMA_analysis_engine_destroyed__CONFIG", getMetaData().getName());
     }
@@ -318,8 +321,10 @@ public class PrimitiveAnalysisEngine_imp
   public void batchProcessComplete() throws AnalysisEngineProcessException {
     enterBatchProcessComplete();
     try {
+      UimaContextHolder.setContext(getUimaContext());  // for use by POJOs
       getAnalysisComponent().batchProcessComplete();
     } finally {
+      UimaContextHolder.clearContext();
       exitBatchProcessComplete();
     }
   }
@@ -327,8 +332,10 @@ public class PrimitiveAnalysisEngine_imp
   public void collectionProcessComplete() throws AnalysisEngineProcessException {
     enterCollectionProcessComplete();
     try {
+      UimaContextHolder.setContext(getUimaContext());  // for use by POJOs
       getAnalysisComponent().collectionProcessComplete();
     } finally {
+      UimaContextHolder.clearContext();
       exitCollectionProcessComplete();
     }
   }
@@ -356,6 +363,7 @@ public class PrimitiveAnalysisEngine_imp
         view = Util.getStartingView(aCAS, mSofaAware, getUimaContextAdmin().getComponentInfo());
         // now get the right interface(e.g. CAS or JCAS)
         // must precede the switchClassLoader call below UIMA-2211
+        UimaContextHolder.setContext(getUimaContext());  // for use by POJOs
         Class<? extends AbstractCas> requiredInterface = mAnalysisComponent.getRequiredCasInterface();
         AbstractCas casToPass = getCasManager().getCasInterface(view, requiredInterface);
 
@@ -407,6 +415,8 @@ public class PrimitiveAnalysisEngine_imp
           ((CASImpl)view).restoreClassLoaderUnlockCas();
         }
         throw e;
+      } finally {
+        UimaContextHolder.clearContext();
       }
 
       // log end of event
@@ -509,6 +519,7 @@ public class PrimitiveAnalysisEngine_imp
   protected CAS callAnalysisComponentNext() throws AnalysisEngineProcessException,
           ResultNotSupportedException {
     try {
+      UimaContextHolder.setContext(getUimaContext());  // for use by POJOs
       AbstractCas absCas = mAnalysisComponent.next();
       getMBean().incrementCASesProcessed();
       // notify UimaContext that a CAS was returned -- it uses
@@ -537,6 +548,8 @@ public class PrimitiveAnalysisEngine_imp
         throw (AnalysisEngineProcessException) e;
       else
         throw new AnalysisEngineProcessException(e);
+    } finally {
+      UimaContextHolder.clearContext();
     }
   }
 
@@ -549,9 +562,12 @@ public class PrimitiveAnalysisEngine_imp
 
     // inform the annotator
     try {
+      UimaContextHolder.setContext(getUimaContext());  // for use by POJOs
       mAnalysisComponent.reconfigure();
     } catch (ResourceInitializationException e) {
       throw new ResourceConfigurationException(e);
+    } finally {
+      UimaContextHolder.clearContext();
     }
   }
 
@@ -584,6 +600,7 @@ public class PrimitiveAnalysisEngine_imp
         return true;
       }
       try {
+        UimaContextHolder.setContext(getUimaContext());  // for use by POJOs
         casAvailable = mMyAnalysisComponent.hasNext();
         if (!casAvailable) {
           //when hasNext returns false, by contract the AnalysisComponent is done processing its
@@ -602,6 +619,7 @@ public class PrimitiveAnalysisEngine_imp
       }
  
       finally {
+        UimaContextHolder.clearContext();
         exitProcess();
       }
     }

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/impl/ResourceSpecifierFactory_impl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/impl/ResourceSpecifierFactory_impl.java?rev=1757287&r1=1757286&r2=1757287&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/impl/ResourceSpecifierFactory_impl.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/impl/ResourceSpecifierFactory_impl.java Mon Aug 22 21:32:38 2016
@@ -89,6 +89,7 @@ import org.apache.uima.resource.metadata
 import org.apache.uima.resource.metadata.TypePriorities;
 import org.apache.uima.resource.metadata.TypePriorityList;
 import org.apache.uima.resource.metadata.TypeSystemDescription;
+import org.apache.uima.util.Settings;
 
 /**
  * Reference implementation of {@link ResourceSpecifierFactory}. Must be threadsafe.
@@ -309,6 +310,13 @@ public class ResourceSpecifierFactory_im
   }
 
   /**
+   * @see org.apache.uima.ResourceSpecifierFactory#createConfigurationParameterSettings()
+   */
+  public Settings createSettings() {
+    return (Settings) createObject(Settings.class);
+  }
+  
+  /**
    * @see org.apache.uima.ResourceSpecifierFactory#createTypePriorities()
    */
   public TypePriorities createTypePriorities() {

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=1757287&r1=1757286&r2=1757287&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 Mon Aug 22 21:32:38 2016
@@ -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.metadata.ConfigurationGroup;
 import org.apache.uima.resource.metadata.ConfigurationParameter;
@@ -276,6 +277,24 @@ public abstract class UimaContext_ImplBa
             aGroupName);
   }
 
+  @Override
+  public String getSetting(String name) throws ResourceConfigurationException {
+    Settings settings = getRootContext().getExternalOverrides();
+    return (settings == null) ? null : settings.getSetting(name);
+  }
+  
+  @Override
+  public String[] getSettingArray(String name) throws ResourceConfigurationException {
+    Settings settings = getRootContext().getExternalOverrides();
+    return (settings == null) ? null : settings.getSettingArray(name);
+  }
+  
+  @Override
+  public Set<String> getSettingNames() {
+    Settings settings = getRootContext().getExternalOverrides();
+    return (settings == null) ? null : settings.getKeys();
+  }
+  
   /**
    * Locates Resource URL's using the ResourceManager.
    * 
@@ -574,7 +593,7 @@ public abstract class UimaContext_ImplBa
   public void setExternalOverrides(Settings externalOverrides) {
     getRootContext().setExternalOverrides(externalOverrides);
   }
-  
+
   /**
    * Changes here should also be made in UimaContext_ImplBase.mapToSofaID (non-Javadoc)
    * 

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/ResourceConfigurationException.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/ResourceConfigurationException.java?rev=1757287&r1=1757286&r2=1757287&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/ResourceConfigurationException.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/ResourceConfigurationException.java Mon Aug 22 21:32:38 2016
@@ -97,6 +97,16 @@ public class ResourceConfigurationExcept
   public static final String EXTERNAL_OVERRIDE_ERROR = "external_override_error";
   
   /**
+   * Message key for a standard UIMA exception message: External override value for "{0}" has the wrong type (scalar or array)
+   */
+  public static final String EXTERNAL_OVERRIDE_TYPE_MISMATCH = "external_override_type_mismatch";
+  
+  /**
+   * Message key for a standard UIMA exception message: External override value "{0}" is not an integer
+   */
+  public static final String EXTERNAL_OVERRIDE_NUMERIC_ERROR = "external_override_numeric_error";
+  
+  /**
    * Creates a new exception with a null message.
    */
   public ResourceConfigurationException() {

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=1757287&r1=1757286&r2=1757287&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 Mon Aug 22 21:32:38 2016
@@ -20,6 +20,7 @@
 package org.apache.uima.resource.impl;
 
 import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.util.Collections;
@@ -76,16 +77,20 @@ public class ConfigurationManager_impl e
         Object paramValue = aSettings.getParameterValue(aGroupName, aParams[i].getName());
         String extName = aParams[i].getExternalOverrideName();
         if (extName != null && aExternalOverrides != null) {
-          String propValue = aExternalOverrides.lookUp(extName);
-          if (propValue != null) {
-            Object result = createParam(propValue, aParams[i].getType(), aParams[i].isMultiValued());
-            if (result == null) {
-              throw new NumberFormatException("Array mismatch assigning value of " + extName + " ('" + propValue
-                      + "') to " + aParams[i].getName());
+          if (aParams[i].isMultiValued()) {
+            String[] propValues = aExternalOverrides.getSettingArray(extName);
+            if (propValues != null) {
+              paramValue = createParams(propValues, aParams[i].getType());
+              mLinkMap.remove(qname);
+              from = "(overridden from " + extName + ")";
+            }
+          } else {
+            String propValue = aExternalOverrides.getSetting(extName);
+            if (propValue != null) {
+              paramValue = createParam(propValue, aParams[i].getType());
+              mLinkMap.remove(qname);
+              from = "(overridden from " + extName + ")";
             }
-            paramValue = result;
-            mLinkMap.remove(qname);
-            from = "(overridden from " + extName + ")";
           }
         }
         mSharedParamMap.put(qname, paramValue);
@@ -134,103 +139,68 @@ public class ConfigurationManager_impl e
   /*
    * Create the appropriate type of parameter object from the value of the external override 
    */
-  private Object createParam(String value, String paramType, boolean isArray) throws NumberFormatException {
-    boolean arrayValue = value.length() > 0 && value.charAt(0) == '[' && value.charAt(value.length()-1) == ']';
-    if (arrayValue ^ isArray) {
-      return null;  // Caller throws exception
+  private Object createParam(String value, String paramType) throws ResourceConfigurationException {
+    if (paramType.equals(ConfigurationParameter.TYPE_BOOLEAN)) {
+      return createParamForClass(value, Boolean.class);
+    } else if (paramType.equals(ConfigurationParameter.TYPE_INTEGER)) {
+      return createParamForClass(value, Integer.class);
+    } else if (paramType.equals(ConfigurationParameter.TYPE_FLOAT)) {
+      return createParamForClass(value, Float.class);
+    } else { // Must be a string
+      return value;
     }
+  }
+  
+  private Object createParams(String[] values, String paramType) {
+    if (paramType.equals(ConfigurationParameter.TYPE_BOOLEAN)) {
+      return createParamsForClass(values, Boolean.class);
+    } else if (paramType.equals(ConfigurationParameter.TYPE_INTEGER)) {
+      return createParamsForClass(values, Integer.class);
+    } else if (paramType.equals(ConfigurationParameter.TYPE_FLOAT)) {
+      return createParamsForClass(values, Float.class);
+    } else { // Must be a string
+      return values;
+    }
+  }
+  
+  /*
+   * Convert the string to the appropriate object
+   */
+  private <T> Object createParamForClass(String value, Class<T> clas) throws ResourceConfigurationException {
+    Method valOf;
     try {
-      if (paramType.equals(ConfigurationParameter.TYPE_BOOLEAN)) {
-        return createParamForClass(value, isArray, Boolean.class);
-      } else if (paramType.equals(ConfigurationParameter.TYPE_INTEGER)) {
-        return createParamForClass(value, isArray, Integer.class);
-      } else if (paramType.equals(ConfigurationParameter.TYPE_FLOAT)) {
-        return createParamForClass(value, isArray, Float.class);
-      } else { // Must be a string 
-        return createParamForClass(value, isArray, String.class);
+      valOf = clas.getMethod("valueOf", String.class);
+      return valOf.invoke(null, value);
+    } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      if (e.getCause() instanceof NumberFormatException) {
+        // External override value "{0}" is not an integer
+        throw new ResourceConfigurationException(ResourceConfigurationException.EXTERNAL_OVERRIDE_NUMERIC_ERROR, 
+                new Object[] { value });
       }
-    } catch (Exception e) {
       e.printStackTrace();
-      throw new NumberFormatException("Failed to convert '" + value + "' to " + paramType);
+      throw new ResourceConfigurationException(e);
     }
+
   }
   
-  // String does not have a valueOf(String) method so use this trivial class instead
-  static class StringX {
-    public static String valueOf(String s) {
-      return s;
-    }
-  }
-
   /*
-   * Convert the string to the appropriate object, or array of.
+   * Convert the array of strings to the appropriate array of objects.
    * Suppress the warnings about the casts.
-   * Tokenize arrays on ',' but if should have been escaped put the ',' back
    */
   @SuppressWarnings("unchecked")
-  private <T> Object createParamForClass(String value, boolean isArray, Class<T> clas) throws Exception {
-    Method valOf = null;
+  private <T> Object createParamsForClass(String[] values, Class<T> clas) {
+    Method valOf;
     try {
       valOf = clas.getMethod("valueOf", String.class);
-    } catch (NoSuchMethodException e) {
-      valOf = StringX.class.getMethod("valueOf", String.class);
-    }
-    if (isArray) {
-      value = value.substring(1, value.length()-1);
-      if (value.length() == 0) {          // If an empty string create a 0-length array 
-        return (T[]) Array.newInstance(clas, 0);
-      }
-      String[] tokens = value.split(",");
-      int nTokens = tokens.length;
-      int i;
-      for (i = 0; i < tokens.length - 1; ++i) {
-        if (endsWithEscape(tokens[i])) {
-          tokens[i+1] = tokens[i] + "," + tokens[i+1];
-          tokens[i] = null;
-          --nTokens;
-        }
-      }
-      if (endsWithEscape(tokens[i])) {
-        tokens[i] += ",";
-      }
-      T[] result = (T[]) Array.newInstance(clas, nTokens);
-      i = 0;
-      for (String token : tokens) {
-        if (token != null) {
-          result[i++] = (T) valOf.invoke(null, escape(token.trim()));
-        }
+      T[] result = (T[]) Array.newInstance(clas, values.length);
+      for (int i = 0; i < values.length; ++i) {
+        result[i] = (T) valOf.invoke(null, values[i]);
       }
       return result;
-    } else {
-      return valOf.invoke(null, escape(value));
+    } catch (NoSuchMethodException | SecurityException | IllegalAccessException
+            | IllegalArgumentException | InvocationTargetException e) {
+      throw new IllegalArgumentException(e.getCause());
     }
   }
-
-  // Finally process any escapes by replacing \x by x
-  private String escape(String token) {
-    int next = token.indexOf('\\');
-    if (next < 0) {
-      return token;
-    }
-    StringBuilder result = new StringBuilder(token.length());
-    int last = 0;
-    // For each '\' found copy up to it and restart the search after the next char
-    while (next >= 0) {
-      result.append(token.substring(last, next));
-      last = next + 1;
-      next = token.indexOf('\\', last + 1);
-    }
-    result.append(token.substring(last));
-    return result.toString();
-  }
   
-  private boolean endsWithEscape(String line) {
-    int i = line.length();
-    while (i > 0 && line.charAt(i-1) == '\\') {
-      --i;
-    }
-    // If change in i is odd then ended with an unescaped \ 
-    return ((line.length() - i) % 2 != 0);
-  }
-
 }

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/Import_impl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/Import_impl.java?rev=1757287&r1=1757286&r2=1757287&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/Import_impl.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/Import_impl.java Mon Aug 22 21:32:38 2016
@@ -22,9 +22,12 @@ package org.apache.uima.resource.metadat
 import java.net.MalformedURLException;
 import java.net.URL;
 
+import org.apache.uima.UIMAFramework;
 import org.apache.uima.resource.ResourceManager;
 import org.apache.uima.resource.metadata.Import;
 import org.apache.uima.util.InvalidXMLException;
+import org.apache.uima.util.Level;
+import org.apache.uima.util.Logger;
 import org.apache.uima.util.XMLParser;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -95,9 +98,12 @@ public class Import_impl extends MetaDat
    * @see org.apache.uima.resource.metadata.Import#findAbsoluteUrl(org.apache.uima.resource.ResourceManager)
    */
   public URL findAbsoluteUrl(ResourceManager aResourceManager) throws InvalidXMLException {
+    Logger logger = UIMAFramework.getLogger(this.getClass());
     if (getLocation() != null) {
       try {
-        return new URL(this.getRelativePathBase(), getLocation());
+        URL url = new URL(this.getRelativePathBase(), getLocation());
+        logger.log(Level.CONFIG, "Import by location: " + url);
+        return url;
       } catch (MalformedURLException e) {
         throw new InvalidXMLException(InvalidXMLException.MALFORMED_IMPORT_URL, new Object[] {
             getLocation(), getSourceUrlString() }, e);
@@ -107,6 +113,7 @@ public class Import_impl extends MetaDat
       URL url;
       try {
         url = aResourceManager.resolveRelativePath(filename);
+        logger.log(Level.CONFIG, "Import by name: " + url);
       } catch (MalformedURLException e) {
         throw new InvalidXMLException(InvalidXMLException.IMPORT_BY_NAME_TARGET_NOT_FOUND,
                 new Object[] { filename, getSourceUrlString() }, e);

Modified: 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=1757287&r1=1757286&r2=1757287&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/Settings.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/Settings.java Mon Aug 22 21:32:38 2016
@@ -62,7 +62,7 @@ public interface Settings {
    * @throws ResourceConfigurationException wraps IOException
    */
   public void loadSystemDefaults() throws ResourceConfigurationException;
-  
+
   /**
    * Look up the value for a property.
    * Perform one substitution pass on ${key} substrings replacing them with the value for key.
@@ -84,4 +84,25 @@ public interface Settings {
    * @return - set of strings
    */
   public Set<String> getKeys();
+
+  /**
+   * Get the value of an external override setting.
+   * 
+   * @param name - the name of the parameter
+   * @return     - the value found in the settings file(s), or null if missing.
+   * @throws ResourceConfigurationException 
+   *                 if the value references an undefined property, or the value is an array
+   */
+  String getSetting(String name) throws ResourceConfigurationException;
+  
+  /**
+  * Get the array of values for an external override setting.
+  * 
+  * @param name  - the name of the parameter
+  * @return      - an array of values found in the settings file(s), or null if missing.
+  * @throws ResourceConfigurationException 
+  *                  if the value references an undefined property, or the value is not an array
+  */
+  public String[] getSettingArray(String name) throws ResourceConfigurationException;
+  
 }

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=1757287&r1=1757286&r2=1757287&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 Mon Aug 22 21:32:38 2016
@@ -71,14 +71,17 @@ public class Settings_impl implements Se
    * 
    * @return - set of strings
    */
+  @Override
   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.
+   * 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 if name characters illegal
@@ -123,11 +126,13 @@ public class Settings_impl implements Se
   }
 
   /**
-   * Load the files specified in the system property UimaExternalOverrides
-   *
+   * Load properties from the comma-separated list of files specified in the system property 
+   *   UimaExternalOverrides
+   * Files are loaded in order --- so in descending priority.
+   * Any existing entries are removed first.
+   * 
    * @throws ResourceConfigurationException wraps IOException
    */
-  
   public void loadSystemDefaults() throws ResourceConfigurationException {
     String fnames = System.getProperty("UimaExternalOverrides");
     if (fnames != null) {
@@ -152,17 +157,18 @@ public class Settings_impl implements Se
   
   /**
    * Look up the value for a property.
-   * Perform one substitution pass on ${key} substrings. If key is undefined throw an exception.
+   * 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!
-   * To avoid evaluation and get ${key} in the output use a property to generate the $, e.g. 
-   *   $   = $
-   *   key = ${$}{key}
-   * or escape the $
-   *   key = \${key}
+   * 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. 
+   * 
+   * Used by getSetting and getSettingArray
    * 
    * @param name - name to look up
    * @return     - value of property
-   * @throws ResourceConfigurationException if override variable references undefined variable
+   * @throws ResourceConfigurationException if the value references an undefined property
    */
   public String lookUp(String name) throws ResourceConfigurationException {
     String value;
@@ -197,6 +203,97 @@ public class Settings_impl implements Se
     }
   }
   
+  /**
+   * @see org.apache.uima.util.Settings#getSetting1(java.lang.String)
+   */
+  @Override
+  public String getSetting(String name) throws ResourceConfigurationException {
+    String value = lookUp(name);
+    if (value == null) {
+      return null;
+    }
+    // Arrays start with '[' and end with an ] that is not escaped
+    if (value.length() >= 2 && value.charAt(0) == '[' && value.charAt(value.length() - 1) == ']'
+            && value.charAt(value.length() - 2) != '\\') {
+      // External override value for "{0}" has the wrong type (scalar or array)
+      throw new ResourceConfigurationException(ResourceConfigurationException.EXTERNAL_OVERRIDE_TYPE_MISMATCH, 
+              new Object[] { name });
+    }
+    return value;
+  }
+
+  /**
+   * @see org.apache.uima.util.Settings#getSettingArray(java.lang.String)
+   */
+  @Override
+  public String[] getSettingArray(String name) throws ResourceConfigurationException {
+    String value = lookUp(name);
+    if (value == null) {
+      return null;
+    }
+    if (!(value.length() >= 2 && value.charAt(0) == '[' && value.charAt(value.length() - 1) == ']' && value
+            .charAt(value.length() - 2) != '\\')) {
+      // External override value for "{0}" has the wrong type (scalar or array)
+      throw new ResourceConfigurationException(ResourceConfigurationException.EXTERNAL_OVERRIDE_TYPE_MISMATCH, 
+              new Object[] { name });
+    }
+    value = value.substring(1, value.length() - 1);
+    if (value.length() == 0) { // If an empty string create a 0-length array
+      return new String[0];
+    }
+    // Split on commas but rejoin tokens if a comma is escaped
+    String[] tokens = value.split(",");
+    int nTokens = tokens.length;
+    int last = tokens.length - 1;
+    for (int i = 0; i < last; ++i) {
+      if (endsWithEscape(tokens[i])) {
+        tokens[i + 1] = tokens[i] + "," + tokens[i + 1];
+        tokens[i] = null;
+        --nTokens;
+      }
+    }
+    if (endsWithEscape(tokens[last])) {
+      tokens[last] += ",";
+    }
+    String[] result = new String[nTokens];
+    int i = 0;
+    for (String token : tokens) {
+      if (token != null) {
+        result[i++] = escape(token.trim());
+      }
+    }
+    return result;
+  }
+
+  // Final step is to process any escapes by replacing \x by x
+  private String escape(String token) {
+    int next = token.indexOf('\\');
+    if (next < 0) {
+      return token;
+    }
+    StringBuilder result = new StringBuilder(token.length());
+    int last = 0;
+    // For each '\' found copy up to it and restart the search after the
+    // next char
+    while (next >= 0) {
+      result.append(token.substring(last, next));
+      last = next + 1;
+      next = token.indexOf('\\', last + 1);
+    }
+    result.append(token.substring(last));
+    return result.toString();
+  }
+
+  private boolean endsWithEscape(String line) {
+    int i = line.length();
+    while (i > 0 && line.charAt(i - 1) == '\\') {
+      --i;
+    }
+    // If change in i is odd then ended with an unescaped \
+    return ((line.length() - i) % 2 != 0);
+  }
+
+  
   /*
    * Create a string representing an array from one or more logical lines
    * Assert: line length &gt; 0

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/impl/XMLParser_impl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/impl/XMLParser_impl.java?rev=1757287&r1=1757286&r2=1757287&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/impl/XMLParser_impl.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/impl/XMLParser_impl.java Mon Aug 22 21:32:38 2016
@@ -888,6 +888,7 @@ public CasInitializerDescription parseCa
   /**
    * Configures this XMLParser by registering a mapping between the name of an XML element and the
    * Class of object to be built from elements with that name.
+   * Ignores entries with no name, i.e. are not configured via XML
    * 
    * @param aElementName
    *          the name of an XML element
@@ -903,6 +904,9 @@ public CasInitializerDescription parseCa
    */
   @SuppressWarnings("unchecked")
   public void addMapping(String aElementName, String aClassName) throws ClassNotFoundException {
+    if (aElementName == null) {
+      return;
+    }
     // resolve the class name and ensure that it implements XMLizable
     Class<? extends XMLizable> cls = (Class<? extends XMLizable>) Class.forName(aClassName);
     if (XMLizable.class.isAssignableFrom(cls)) {

Modified: uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties?rev=1757287&r1=1757286&r2=1757287&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties Mon Aug 22 21:32:38 2016
@@ -134,6 +134,10 @@ external_override_invalid = External ove
 
 external_override_error = Error loading external overrides from "{0}"
 
+external_override_type_mismatch = External override value for "{0}" has the wrong type (scalar or array)
+
+external_override_numeric_error = External override value "{0}" is not an integer
+
 #--------------------------------
 #ResourceProcessException
 #--------------------------------
@@ -573,4 +577,4 @@ DESERIALIZING_COMPRESSED_BINARY_UNSUPPOR
 DEREF_FS_OTHER_CAS = Dereferencing a FeatureStructure of a CAS in a different CAS''s context. This can happen if you try to set a feature structure reference to a value of a feature structure belonging to an entirely different CAS. FS = "{0}", CAS = "{1}".
 ILLEGAL_FEAT_SET = While a FeatureStructure was in the index, an illegal attempt was made to modify Feature "{0}" which is used as a key in one or more indices; the Feature Structure being modified was "{1}".
 LENIENT_NOT_SUPPORTED = Lenient deserialization not support for input of type {0}.
-SWITCH_CLASS_LOADER_NESTED = Multiply nested classloaders not supported.  Original base loader: {0}, current nested loader: {1}, trying to switch to loader: {2}.
+SWITCH_CLASS_LOADER_NESTED = Multiply nested classloaders not supported.  Original base loader: {0}, current nested loader: {1}, trying to switch to loader: {2}.
\ No newline at end of file

Modified: uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/impl/factoryConfig.xml
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/impl/factoryConfig.xml?rev=1757287&r1=1757286&r2=1757287&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/impl/factoryConfig.xml (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/impl/factoryConfig.xml Mon Aug 22 21:32:38 2016
@@ -58,6 +58,7 @@
 	  	             factoryClass="org.apache.uima.impl.CustomResourceFactory_impl"/>
 	</resource>
 
+    <!--  element attribute may be omitted if has no XML specification -->
 	<resourceSpecifier>
 		<binding element="analysisEngineDescription" interface="org.apache.uima.analysis_engine.AnalysisEngineDescription" class="org.apache.uima.analysis_engine.impl.AnalysisEngineDescription_impl"/>
 		<binding element="analysisEngineMetaData" interface="org.apache.uima.analysis_engine.metadata.AnalysisEngineMetaData" class="org.apache.uima.analysis_engine.metadata.impl.AnalysisEngineMetaData_impl"/>
@@ -137,7 +138,6 @@
 	    <binding element="errorRateThreshold" interface="org.apache.uima.collection.metadata.CasProcessorErrorRateThreshold" class="org.apache.uima.collection.impl.metadata.cpe.CasProcessorErrorRateThresholdImpl"/>
 	    <binding element="timeout" interface="org.apache.uima.collection.metadata.CasProcessorTimeout" class="org.apache.uima.collection.impl.metadata.cpe.CasProcessorTimeoutImpl"/>
 	    <binding element="sofaNameMappings" interface="org.apache.uima.collection.metadata.CpeSofaMappings" class="org.apache.uima.collection.impl.metadata.cpe.CpeSofaMappingsImpl"/>
-		<binding element="externalOverrideSettings" interface="org.apache.uima.resource.metadata.ExternalOverrideSettings" class="org.apache.uima.resource.metadata.impl.ExternalOverrideSettings_impl"/>	
-
+        <binding interface="org.apache.uima.util.Settings" class="org.apache.uima.util.impl.Settings_impl"/>
 	</resourceSpecifier>
-</factoryConfig>
\ No newline at end of file
+</factoryConfig>

Modified: uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/impl/log_messages.properties
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/impl/log_messages.properties?rev=1757287&r1=1757286&r2=1757287&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/impl/log_messages.properties (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/impl/log_messages.properties Mon Aug 22 21:32:38 2016
@@ -45,6 +45,10 @@ UIMA_analysis_engine_init_successful__CO
 
 UIMA_analysis_engine_destroyed__CONFIG = AnalysisEngine [{0}] destroyed.
 
+UIMA_flow_controller_init_begin__CONFIG = FlowController [{0}] initialization begin
+
+UIMA_flow_controller_init_successful__CONFIG = FlowController [{0}] initialization successful
+
 UIMA_asb_init_begin__CONFIG = ASB initialization begin
 
 UIMA_asb_init_successful__CONFIG = ASB initialization successful

Modified: uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/AnalysisEngine_implTest.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/AnalysisEngine_implTest.java?rev=1757287&r1=1757286&r2=1757287&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/AnalysisEngine_implTest.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/AnalysisEngine_implTest.java Mon Aug 22 21:32:38 2016
@@ -328,15 +328,20 @@ public class AnalysisEngine_implTest ext
       desc = UIMAFramework.getXMLParser().parseAnalysisEngineDescription(in);
       ae1 = new PrimitiveAnalysisEngine_impl();
       ae1.initialize(desc, null);
-      String[] arrayParam = (String[]) ae1.getUimaContext().getConfigParameterValue("StringArrayParam");
-      Assert.assertNotNull(arrayParam);
-      Assert.assertEquals(5, arrayParam.length);
-      String[] expect = { "Prefix", "-", "Suffix", "->", "Prefix-Suffix" };
-      Assert.assertTrue(Arrays.equals(expect, arrayParam));
-      Integer[] intArr = (Integer[]) ae1.getUimaContext().getConfigParameterValue("IntegerArrayParam");
-      Assert.assertEquals(4, intArr.length);
+      String[] strArray = (String[]) ae1.getUimaContext().getConfigParameterValue("StringArrayParam");
+      Assert.assertNotNull(strArray);
+      Assert.assertEquals(5, strArray.length);
+      String[] strExpect = { "Prefix", "-", "Suffix", "->", "Prefix-Suffix" };
+      Assert.assertTrue(Arrays.equals(strExpect, strArray));
+      Integer[] intArray = (Integer[]) ae1.getUimaContext().getConfigParameterValue("IntegerArrayParam");
+      Assert.assertNotNull(intArray);
+      Assert.assertEquals(4, intArray.length);
+      Integer[] intExpect = { 1, 22, 333, 4444 };
+      Assert.assertTrue(Arrays.equals(intExpect, intArray));
       Float[] floats = (Float[]) ae1.getUimaContext().getConfigParameterValue("FloatArrayParam");
       Assert.assertTrue(floats != null && floats.length == 0);       // Should be an empty array
+      Integer intValue = (Integer) ae1.getUimaContext().getConfigParameterValue("IntegerParam");
+      Assert.assertEquals(43,  intValue.intValue());  // Will be 42 if external override not defined
       System.clearProperty("UimaExternalOverrides");
       
       ae1.destroy();
@@ -348,7 +353,7 @@ public class AnalysisEngine_implTest ext
       in = new XMLInputSource(JUnitExtension.getFile("TextAnalysisEngineImplTest/AggregateWithExternalOverrides.xml"));
       desc = UIMAFramework.getXMLParser().parseAnalysisEngineDescription(in);
       Map<String,Object> additionalParams = new HashMap<String,Object>();
-      Settings extSettings = new Settings_impl();
+      Settings extSettings = UIMAFramework.getResourceSpecifierFactory().createSettings();
       FileInputStream fis = new FileInputStream(new File(resDir,"testExternalOverride2.settings"));
       extSettings.load(fis);
       fis.close();

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=1757287&r1=1757286&r2=1757287&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 Mon Aug 22 21:32:38 2016
@@ -19,12 +19,19 @@
 
 package org.apache.uima.analysis_engine.impl;
 
+import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
+import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.List;
+import java.util.Map.Entry;
 
 import junit.framework.Assert;
 
+import org.apache.uima.UIMAFramework;
 import org.apache.uima.UimaContext;
+import org.apache.uima.UimaContextHolder;
 import org.apache.uima.analysis_component.CasAnnotator_ImplBase;
 import org.apache.uima.analysis_engine.ResultSpecification;
 import org.apache.uima.cas.CAS;
@@ -33,6 +40,7 @@ import org.apache.uima.impl.UimaContext_
 import org.apache.uima.resource.ResourceConfigurationException;
 import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.util.Settings;
+import org.apache.uima.util.UimaContextHolderTest;
 import org.apache.uima.util.impl.Settings_impl;
 
 /**
@@ -65,20 +73,44 @@ public class TestAnnotator2 extends CasA
     stringParamValue = (String) aContext.getConfigParameterValue("StringParam");
     
     // Check if can get an arbitrary external parameter from the override settings
+    // Note: this annotator launched with external overrides loaded from testExternalOverride2.settings 
     String contextName = ((UimaContext_ImplBase) aContext).getQualifiedContextName();
     if ("/ExternalOverrides/".equals(contextName)) {
+      String expected = "Context Holder Test";
+      String[] actuals = null;
+      try {
+        actuals = UimaContextHolder.getContext().getSettingArray("test.externalFloatArray");
+      } catch (ResourceConfigurationException e) {
+        Assert.fail(e.getMessage());
+      }
+      Assert.assertEquals(0, actuals.length);
+      
+      // prefix-suffix     Prefix-${suffix}
+      // suffix = should be ignored
       String actual = null;
       try {
-        Settings settings = ((UimaContext_ImplBase)aContext).getExternalOverrides();
-        actual = settings.lookUp("test.externalFloatArray");
+        actual = UimaContextHolder.getContext().getSetting("context-holder");
       } catch (ResourceConfigurationException e) {
         Assert.fail(e.getMessage());
       }
-      String expected = "[]";
       Assert.assertEquals(expected, actual);
       
+      // Test assigning an array to a string and vice-versa
+      try {
+        actual = UimaContextHolder.getContext().getSetting("test.externalFloatArray");
+        Assert.fail("\"bad\" should create an error");
+      } catch (ResourceConfigurationException e) {
+        System.err.println("Expected exception: " + e.toString());
+      }
+      try {
+        actuals = UimaContextHolder.getContext().getSettingArray("prefix-suffix");
+        Assert.fail("\"bad\" should create an error");
+      } catch (ResourceConfigurationException e) {
+        System.err.println("Expected exception: " + e.toString());
+      }
+
       // Test a stand-alone settings object
-      Settings testSettings = new Settings_impl();
+      Settings testSettings = UIMAFramework.getResourceSpecifierFactory().createSettings();
       String lines = "foo = ${bar} \n bar : [ok \n OK] \n bad = ${missing}";
       InputStream is;
       try {
@@ -96,6 +128,44 @@ public class TestAnnotator2 extends CasA
       } catch (Exception e) {
         Assert.fail(e.toString());
       }
+      
+      // Test POFO access via UimaContextHolder
+      long threadId = Thread.currentThread().getId();
+      UimaContextHolderTest testPojoAccess = new UimaContextHolderTest();
+      try {
+        actual = testPojoAccess.testSettings();
+        Assert.assertEquals(expected, actual);
+        Assert.assertEquals(threadId, testPojoAccess.threadId);
+      } catch (ResourceConfigurationException e) {
+        Assert.fail();
+      }
+      // Try from a child thread - should work
+      testPojoAccess.result = null;
+      Thread thrd = new Thread(testPojoAccess);
+      thrd.start();
+      synchronized(thrd) {
+        try {
+          thrd.wait();
+          Assert.assertEquals(expected, testPojoAccess.result);
+          Assert.assertNotSame(threadId, testPojoAccess.threadId);
+        } catch (InterruptedException e) {
+          Assert.fail();        }
+      }
+      // Try from a process - should fail
+      String[] args = {
+              System.getProperty("java.home")+"/bin/java",
+              "-cp", 
+              System.getProperty("java.class.path"), 
+              UimaContextHolderTest.class.getName()};
+      ProcessBuilder pb = new ProcessBuilder(args);
+      try {
+        Process proc = pb.start();
+        int rc = proc.waitFor();
+        Assert.assertEquals(0, rc);
+      } catch (IOException | InterruptedException e) {
+        Assert.fail();
+      }
+      
     }
     // Used to check initialization order by testManyDelegates
     allContexts  = allContexts + contextName.substring(1);

Added: uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/util/UimaContextHolderTest.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/util/UimaContextHolderTest.java?rev=1757287&view=auto
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/util/UimaContextHolderTest.java (added)
+++ uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/util/UimaContextHolderTest.java Mon Aug 22 21:32:38 2016
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.uima.util;
+
+import org.apache.uima.UimaContext;
+import org.apache.uima.UimaContextHolder;
+import org.apache.uima.resource.ResourceConfigurationException;
+
+/*
+ * Test POJO access via the UimaContextHolder
+ * Should work when invoked by a child thread, 
+ * but fail when invoked by a separate process via main 
+ */
+public class UimaContextHolderTest implements Runnable {
+
+  public String result = null;
+  public long threadId = 0;
+  static String nocontextError = "ERROR: No UimaContext accessible";
+
+  public String testSettings() throws ResourceConfigurationException {
+    threadId  = Thread.currentThread().getId();
+    UimaContext uimaContext = UimaContextHolder.getContext();
+    if (uimaContext == null) {
+      return nocontextError;
+    }
+    return uimaContext.getSetting("context-holder");
+  }
+
+  @Override
+  public void run() {
+    try {
+      result  = testSettings();
+    } catch (ResourceConfigurationException e) {
+      e.printStackTrace();
+    }
+  }
+
+  /*
+   * When invoked as an independent thread should report no UimaContext available
+   */
+  public static void main(String[] args) {
+    UimaContextHolderTest contextHolder = new UimaContextHolderTest();
+    try {
+      String result = contextHolder.testSettings();
+      if (!result.equals(nocontextError)) {
+        System.exit(99);
+      }
+    } catch (ResourceConfigurationException e) {
+      System.exit(98);
+    }
+  }
+}

Propchange: uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/util/UimaContextHolderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: uima/uimaj/trunk/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/AnnotatorWithExternalOverrides.xml
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/AnnotatorWithExternalOverrides.xml?rev=1757287&r1=1757286&r2=1757287&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/AnnotatorWithExternalOverrides.xml (original)
+++ uima/uimaj/trunk/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/AnnotatorWithExternalOverrides.xml Mon Aug 22 21:32:38 2016
@@ -49,6 +49,7 @@
       </configurationParameter>  
       <configurationParameter>
         <name>IntegerParam</name>
+        <externalOverrideName>test.externalInteger</externalOverrideName>
         <description/>
         <type>Integer</type>
         <multiValued>false</multiValued>

Modified: uima/uimaj/trunk/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride.settings
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride.settings?rev=1757287&r1=1757286&r2=1757287&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride.settings (original)
+++ uima/uimaj/trunk/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride.settings Mon Aug 22 21:32:38 2016
@@ -20,4 +20,5 @@ prefix    Prefix
 suffix    Suffix
 test.externalStringArray = [${prefix},\-,${suffix},->,${prefix-suffix}]
 test.externalIntegerArray : [1 , 22 , 3\33,4444]  
+test.externalInteger         43
 

Modified: uima/uimaj/trunk/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride2.settings
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride2.settings?rev=1757287&r1=1757286&r2=1757287&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride2.settings (original)
+++ uima/uimaj/trunk/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride2.settings Mon Aug 22 21:32:38 2016
@@ -21,3 +21,4 @@ prefix-suffix     Prefix-${suffix}
 suffix = should be ignored
 # Empty array
 test.externalFloatArray =  []
+context-holder = Context Holder Test