You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by sc...@apache.org on 2014/04/04 15:50:02 UTC

svn commit: r1584687 - in /uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource: ./ impl/ metadata/impl/

Author: schor
Date: Fri Apr  4 13:50:02 2014
New Revision: 1584687

URL: http://svn.apache.org/r1584687
Log:
[UIMA-3693][UIMA-3694] skip unneeded work, synch resolve imports, make resource manager and configuration manager fields final (preferable) or volatile

Modified:
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/Resource_ImplBase.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ConfigurationManagerImplBase.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManagerPearWrapper_impl.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManager_impl.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/FsIndexCollection_impl.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/ResourceManagerConfiguration_impl.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/TypePriorities_impl.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/TypePriorityList_impl.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/TypeSystemDescription_impl.java

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/Resource_ImplBase.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/Resource_ImplBase.java?rev=1584687&r1=1584686&r2=1584687&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/Resource_ImplBase.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/Resource_ImplBase.java Fri Apr  4 13:50:02 2014
@@ -60,17 +60,16 @@ public abstract class Resource_ImplBase 
   /**
    * @see org.apache.uima.resource.Resource#initialize(org.apache.uima.resource.ResourceSpecifier,
    *      java.util.Map)
+   *      
+   * multi-thread safe, given that each instance of this class is only called on one thread, once.
+   * The critical parts that update shared information (in shared uima context) are inside a synchronize block
    */
   public boolean initialize(ResourceSpecifier aSpecifier, Map<String, Object> aAdditionalParams)
           throws ResourceInitializationException {
 
     // get name of resource, to be used in error messages
-    String name;
-    if (getMetaData() != null) {
-      name = getMetaData().getName();
-    } else {
-      name = getClass().getName();
-    }
+    final ResourceMetaData metadata1 = getMetaData();
+    String name = (metadata1 == null) ? getClass().getName() : metadata1.getName();
 
     // check for repeat initialization
     if (mInitialized) {
@@ -79,11 +78,11 @@ public abstract class Resource_ImplBase 
     }
 
     // is there a UIMAContext provided in the aAdditionalParams map?
+    // if so, use it - it could be a shared context for scale-up of the same resource
     if (aAdditionalParams != null) {
       mUimaContextAdmin = (UimaContextAdmin) aAdditionalParams.get(PARAM_UIMA_CONTEXT);
     }
-    if (mUimaContextAdmin == null) // no, we have to create one
-    {
+    if (mUimaContextAdmin == null) {// no, we have to create one    
       // get or create ResourceManager
       ResourceManager resMgr = null;
       if (aAdditionalParams != null) {
@@ -126,6 +125,7 @@ public abstract class Resource_ImplBase 
       ResourceMetaData metadata = ((ResourceCreationSpecifier) aSpecifier).getMetaData();
       name = metadata.getName();
       try {
+        // the resolveImports method has synch block around updates to the metadata
         metadata.resolveImports(getResourceManager());
       } catch (InvalidXMLException e) {
         throw new ResourceInitializationException(e);
@@ -141,20 +141,24 @@ public abstract class Resource_ImplBase 
       if (externalOverrides != null) {
         mUimaContextAdmin.setExternalOverrides(externalOverrides);
       } else {
-        if (mUimaContextAdmin.getExternalOverrides() == null) {
-          externalOverrides = new Settings_impl();
-          try {
-            externalOverrides.loadSystemDefaults();
-          } catch (ResourceConfigurationException e) {
-            throw new ResourceInitializationException(ResourceInitializationException.ERROR_INITIALIZING_FROM_DESCRIPTOR,
-                    new Object[] { name, metadata.getSourceUrlString() }, e);
+        // synch around test/set of the (possibly shared) uima-context info about external param overrides
+        synchronized(mUimaContextAdmin) {
+          if (mUimaContextAdmin.getExternalOverrides() == null) {
+            externalOverrides = new Settings_impl();
+            try {
+              externalOverrides.loadSystemDefaults();
+            } catch (ResourceConfigurationException e) {
+              throw new ResourceInitializationException(ResourceInitializationException.ERROR_INITIALIZING_FROM_DESCRIPTOR,
+                      new Object[] { name, metadata.getSourceUrlString() }, e);
+            }
+            mUimaContextAdmin.setExternalOverrides(externalOverrides);
           }
-          mUimaContextAdmin.setExternalOverrides(externalOverrides);
         }
       }
 
       // initialize configuration
       try {
+        // createContext checks and skips repeated calls with same args (on different threads, for example)
         mUimaContextAdmin.getConfigurationManager().createContext(
                 mUimaContextAdmin.getQualifiedContextName(), getMetaData(), mUimaContextAdmin.getExternalOverrides());
         mUimaContextAdmin.getConfigurationManager().setSession(mUimaContextAdmin.getSession());
@@ -179,6 +183,7 @@ public abstract class Resource_ImplBase 
         if (!aAdditionalParams.containsKey(PARAM_RESOURCE_MANAGER)) {
             aAdditionalParams.put(PARAM_RESOURCE_MANAGER, mUimaContextAdmin.getResourceManager());
         }
+        // initializeExternalResources is synchronized
         mUimaContextAdmin.getResourceManager().initializeExternalResources(resMgrCfg,
                 mUimaContextAdmin.getQualifiedContextName(), aAdditionalParams);
       }
@@ -187,6 +192,7 @@ public abstract class Resource_ImplBase 
       ExternalResourceDependency[] resourceDependencies = ((ResourceCreationSpecifier) aSpecifier)
               .getExternalResourceDependencies();
       if (resourceDependencies != null) {
+        // resolveAndValidateResourceDependencies is synchronized
         mUimaContextAdmin.getResourceManager().resolveAndValidateResourceDependencies(
                 resourceDependencies, mUimaContextAdmin.getQualifiedContextName());
       }

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ConfigurationManagerImplBase.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ConfigurationManagerImplBase.java?rev=1584687&r1=1584686&r2=1584687&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ConfigurationManagerImplBase.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ConfigurationManagerImplBase.java Fri Apr  4 13:50:02 2014
@@ -63,30 +63,42 @@ public abstract class ConfigurationManag
 
   /**
    * Map from context name to ConfigurationParameterDeclarations for that context.
+   * Not sync'd based on belief:
+   *   setup of values must be complete before any reference occurs, even in multi-threaded context.
+   *   The setup is done under a sync'd control to insure only one setup is done, and to
+   *   publish the updated results to other threads
    */
-  private Map<String, ConfigurationParameterDeclarations> mContextNameToParamDeclsMap = new HashMap<String, ConfigurationParameterDeclarations>();
+  final private Map<String, ConfigurationParameterDeclarations> mContextNameToParamDeclsMap = 
+      new HashMap<String, ConfigurationParameterDeclarations>();
 
   /**
    * Map the fully-qualified name of a parameter to the fully-qualified name of the parameter it is
    * linked to (from which it takes its value).
+   * Not sync'd based on belief:
+   *   setup of values must be complete before any reference occurs, even in multi-threaded context.
+   *   The setup is done under a sync'd control to insure only one setup is done
+   * 
    */
-  protected Map<String, String> mLinkMap = new HashMap<String, String>();
+  final protected Map<String, String> mLinkMap = new HashMap<String, String>();
 
   /**
    * Set of parameters (fully qualified names) that explicitly declare overrides. This is used to
    * prevent implicit (name-based) overrides for these parameters.
    */
-  private Set<String> mExplicitlyOverridingParameters = new HashSet<String>();
+//  final private Set<String> mExplicitlyOverridingParameters = new HashSet<String>();
 
   /**
-   * Current session. Used to store parmater overrides.
+   * Current session. Used to store parameter settings done by the
+   * settings via API tae.setConfigParameterValue(...)
+   * 
+   * can be set by multiple threads, but ought to be set to the same session object
    */
-  private Session mSession = null;
+  private volatile Session mSession = null;
 
-  /**
-   * Holds the externalOverrideSettings from the top-level Analysis Engine
-   */
-  protected OperationalProperties mOperationalProperties = null;
+//  /**
+//   * Holds the externalOverrideSettings from the top-level Analysis Engine
+//   */
+//  protected OperationalProperties mOperationalProperties = null;
 
   /*
    * (non-Javadoc)
@@ -96,15 +108,20 @@ public abstract class ConfigurationManag
   public void setSession(Session aSession) {
     mSession = aSession;
   }
-
+         
   /*
    * (non-Javadoc)
    * 
    * @see org.apache.uima.resource.ConfigurationManager#createContext(java.lang.String,
    *      org.apache.uima.resource.metadata.ResourceMetaData)
+   *      
+   * Could be called multiple times on different threads - first one does the context creation
    */
-  public void createContext(String aContextName, ResourceMetaData aResourceMetaData, Settings externalOverrides)
+  public synchronized void createContext(String aContextName, ResourceMetaData aResourceMetaData, Settings externalOverrides)
           throws ResourceConfigurationException {
+    if (mContextNameToParamDeclsMap.containsKey(aContextName)) {
+      return;
+    }
     // first internally validate settings in the ResourceMetaData (catches data type problems,
     // settings for undefined parameters, etc.)
     aResourceMetaData.validateConfigurationParameterSettings();
@@ -151,6 +168,8 @@ public abstract class ConfigurationManag
     // validate
     validateConfigurationParameterSettings(aContextName);
   }
+  
+  
 
   /*
    * (non-Javadoc)

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManagerPearWrapper_impl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManagerPearWrapper_impl.java?rev=1584687&r1=1584686&r2=1584687&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManagerPearWrapper_impl.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManagerPearWrapper_impl.java Fri Apr  4 13:50:02 2014
@@ -21,6 +21,7 @@ package org.apache.uima.resource.impl;
 
 import java.net.MalformedURLException;
 
+import org.apache.uima.analysis_engine.impl.PearAnalysisEngineWrapper;
 import org.apache.uima.internal.util.UIMAClassLoader;
 import org.apache.uima.resource.RelativePathResolver;
 import org.apache.uima.resource.ResourceManager;
@@ -41,27 +42,42 @@ public class ResourceManagerPearWrapper_
    * UIMA extension ClassLoader. ClassLoader is created if an extension classpath is specified at
    * the ResourceManager
    */
-  private UIMAClassLoader uimaCL = null;
-
+  private volatile UIMAClassLoader uimaCL = null;
+  
   /**
    * Object used for resolving relative paths. This is built by parsing the data path.
    */
-  private RelativePathResolver mRelativePathResolver;
+  private final RelativePathResolver mRelativePathResolver = new RelativePathResolver_impl();
 
+  public ResourceManagerPearWrapper_impl() {
+    super(
+        PearAnalysisEngineWrapper.newPearsParent.get().mResourceMap,
+        PearAnalysisEngineWrapper.newPearsParent.get().mInternalResourceRegistrationMap,
+        PearAnalysisEngineWrapper.newPearsParent.get().mParameterizedResourceImplClassMap,
+        PearAnalysisEngineWrapper.newPearsParent.get().mInternalParameterizedResourceImplClassMap,
+        PearAnalysisEngineWrapper.newPearsParent.get().mParameterizedResourceInstanceMap);
+//    ResourceManager_impl r = PearAnalysisEngineWrapper.newPearsParent.get();
+//    mResourceMap = r.mResourceMap;
+//    mInternalResourceRegistrationMap = r.mInternalResourceRegistrationMap;
+//    mParameterizedResourceImplClassMap = r.mParameterizedResourceImplClassMap;
+//    mInternalParameterizedResourceImplClassMap = r.mInternalParameterizedResourceImplClassMap;
+//    mParameterizedResourceInstanceMap = r.mParameterizedResourceInstanceMap;
+    mCasManager = PearAnalysisEngineWrapper.newPearsParent.get().getCasManager();   
+  }
   /**
    * Initializes from the parent, a new <code>ResourceManagerForPearWrapper_impl</code>.
    */
+  @Deprecated
   public void initializeFromParentResourceManager(ResourceManager resourceManager) {
-    ResourceManager_impl r = (ResourceManager_impl) resourceManager;
-    mRelativePathResolver = new RelativePathResolver_impl();
-    mResourceMap = r.mResourceMap;
-    mInternalResourceRegistrationMap = r.mInternalResourceRegistrationMap;
-    mParameterizedResourceImplClassMap = r.mParameterizedResourceImplClassMap;
-    mInternalParameterizedResourceImplClassMap = r.mInternalParameterizedResourceImplClassMap;
-    mParameterizedResourceInstanceMap = r.mParameterizedResourceInstanceMap;
-    synchronized(this) {
-      mCasManager = r.getCasManager();  // synchronized - avoid findbugs noise
-    }
+//    ResourceManager_impl r = (ResourceManager_impl) resourceManager;
+//    mResourceMap = r.mResourceMap;
+//    mInternalResourceRegistrationMap = r.mInternalResourceRegistrationMap;
+//    mParameterizedResourceImplClassMap = r.mParameterizedResourceImplClassMap;
+//    mInternalParameterizedResourceImplClassMap = r.mInternalParameterizedResourceImplClassMap;
+//    mParameterizedResourceInstanceMap = r.mParameterizedResourceInstanceMap;
+//    synchronized(this) {
+//      mCasManager = r.getCasManager();  // synchronized - avoid findbugs noise
+//    }
   }
  
   /**

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManager_impl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManager_impl.java?rev=1584687&r1=1584686&r2=1584687&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManager_impl.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManager_impl.java Fri Apr  4 13:50:02 2014
@@ -76,43 +76,43 @@ public class ResourceManager_impl implem
 
   /**
    * Map from qualified key names (declared in resource dependency XML) to Resource objects.
+   * 
+   * Can't be concurrentMap because it (currently) depends on storing nulls
    */
-  protected Map<String, Object> mResourceMap = new ConcurrentHashMap<String, Object>();
-
+  final protected Map<String, Object> mResourceMap;
+  
   /**
    * Internal map from resource names (declared in resource declaration XML) to ResourceRegistration
    * objects. Used during initialization only.
    */
-  protected Map<String, ResourceRegistration> mInternalResourceRegistrationMap = 
-      new ConcurrentHashMap<String, ResourceRegistration>();
+  final protected Map<String, ResourceRegistration> mInternalResourceRegistrationMap;
 
   /**
    * Map from String keys to Class objects. For ParameterizedResources only, stores the
    * implementation class corresponding to each resource name.
    */
-  protected Map<String, Class<?>> mParameterizedResourceImplClassMap = 
-      new ConcurrentHashMap<String, Class<?>>();
+  final protected Map<String, Class<?>> mParameterizedResourceImplClassMap;
 
   /**
    * Internal map from resource names (declared in resource declaration XML) to Class objects. Used
    * internally during resource initialization.
    */
-  protected Map<String, Class<?>> mInternalParameterizedResourceImplClassMap = 
-      new ConcurrentHashMap<String, Class<?>>();
+  final protected Map<String, Class<?>> mInternalParameterizedResourceImplClassMap;
 
   /**
    * Map from ParameterizedResourceKey to Resource objects. For
    * ParameterizedResources only, stores the DataResources that have already been encountered, and
    * the Resources that have been instantiated therefrom.
    */
-  protected Map<List<Object>, Object> mParameterizedResourceInstanceMap = 
-      new ConcurrentHashMap<List<Object>, Object>();
+  final protected Map<List<Object>, Object> mParameterizedResourceInstanceMap;
 
   /**
    * UIMA extension ClassLoader. ClassLoader is created if an extension classpath is specified at
    * the ResourceManager
+   * 
+   * volatile might be better than synch sets/gets
    */
-  private UIMAClassLoader uimaCL = null;
+  private volatile UIMAClassLoader uimaCL = null;
 
   /** CasManager - manages creation and pooling of CASes. */
   // volatile to support double-checked locking idiom
@@ -136,13 +136,23 @@ public class ResourceManager_impl implem
    *   simultaneously is not.
    */
   // leaving this as a synchronizedMap - for backwards compatibility
-  private Map<String,XMLizable> importCache = Collections.synchronizedMap(new HashMap<String,XMLizable>());
+  // internal users do sync around get/set pairs anyways, but can't rely on
+  // what external users do
+  //   Because internal users do a sync, only one thread at a time is using this
+  //   (for internal calls) anyways, so there's no advantage to the extra overhead
+  //   of making this a ConcurrentHashMap  (March 2014)
+  final private Map<String,XMLizable> importCache = Collections.synchronizedMap(new HashMap<String,XMLizable>());
   
   /**
    * Creates a new <code>ResourceManager_impl</code>.
    */
   public ResourceManager_impl() {
-    mRelativePathResolver = new RelativePathResolver_impl();
+    mResourceMap = Collections.synchronizedMap(new HashMap<String, Object>());
+    mInternalResourceRegistrationMap = new ConcurrentHashMap<String, ResourceRegistration>();
+    mParameterizedResourceImplClassMap =  new ConcurrentHashMap<String, Class<?>>();
+    mInternalParameterizedResourceImplClassMap = new ConcurrentHashMap<String, Class<?>>();
+    mParameterizedResourceInstanceMap =  new ConcurrentHashMap<List<Object>, Object>();
+    mRelativePathResolver = new RelativePathResolver_impl(); 
   }
 
   /**
@@ -150,9 +160,31 @@ public class ResourceManager_impl implem
    * resources.
    */
   public ResourceManager_impl(ClassLoader aClassLoader) {
+    mResourceMap = Collections.synchronizedMap(new HashMap<String, Object>());
+    mInternalResourceRegistrationMap = new ConcurrentHashMap<String, ResourceRegistration>();
+    mParameterizedResourceImplClassMap =  new ConcurrentHashMap<String, Class<?>>();
+    mInternalParameterizedResourceImplClassMap = new ConcurrentHashMap<String, Class<?>>();
+    mParameterizedResourceInstanceMap =  new ConcurrentHashMap<List<Object>, Object>();
     mRelativePathResolver = new RelativePathResolver_impl(aClassLoader);
   }
 
+  /*
+   * Version for Pear wrapper 
+   */
+  public ResourceManager_impl(
+      Map<String, Object> resourceMap,
+      Map<String, ResourceRegistration> internalResourceRegistrationMap,
+      Map<String, Class<?>> parameterizedResourceImplClassMap,
+      Map<String, Class<?>> internalParameterizedResourceImplClassMap,
+      Map<List<Object>, Object> parameterizedResourceInstanceMap) {
+    mResourceMap = resourceMap;
+    mInternalResourceRegistrationMap = internalResourceRegistrationMap;
+    mParameterizedResourceImplClassMap =  parameterizedResourceImplClassMap;
+    mInternalParameterizedResourceImplClassMap = internalParameterizedResourceImplClassMap;
+    mParameterizedResourceInstanceMap =  parameterizedResourceInstanceMap;
+    mRelativePathResolver = new RelativePathResolver_impl(); 
+  }
+  
  /**
   * Support reusing UIMA Class Loader instances to speed up
   * things including the Component Description Editor when
@@ -204,7 +236,7 @@ public class ResourceManager_impl implem
   /**
    * @see org.apache.uima.resource.ResourceManager#getExtensionClassLoader()
    */
-  public synchronized ClassLoader getExtensionClassLoader() {
+  public ClassLoader getExtensionClassLoader() {
     return uimaCL;
   }
 
@@ -409,7 +441,7 @@ public class ResourceManager_impl implem
    * @see org.apache.uima.resource.ResourceManager#initializeExternalResources(org.apache.uima.resource.metadata.ResourceManagerConfiguration,
    *      java.lang.String, java.util.Map)
    */
-  public void initializeExternalResources(ResourceManagerConfiguration aConfiguration,
+  public synchronized void initializeExternalResources(ResourceManagerConfiguration aConfiguration,
           String aQualifiedContextName, Map<String, Object> aAdditionalParams)
           throws ResourceInitializationException {
     // register resources
@@ -464,8 +496,11 @@ public class ResourceManager_impl implem
    * 
    * @see org.apache.uima.resource.ResourceManager#resolveAndValidateResourceDependencies(org.apache.uima.resource.ExternalResourceDependency[],
    *      java.lang.String)
+   *      
+   * Multi-threaded.  Partial avoidance of re-resolving, but if a resource fails to resolve, it will be 
+   *   reattempted on every call
    */
-  public void resolveAndValidateResourceDependencies(ExternalResourceDependency[] aDependencies,
+  public synchronized void resolveAndValidateResourceDependencies(ExternalResourceDependency[] aDependencies,
           String aQualifiedContextName) throws ResourceInitializationException {
     for (int i = 0; i < aDependencies.length; i++) {
       // get resource

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/FsIndexCollection_impl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/FsIndexCollection_impl.java?rev=1584687&r1=1584686&r2=1584687&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/FsIndexCollection_impl.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/FsIndexCollection_impl.java Fri Apr  4 13:50:02 2014
@@ -25,6 +25,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 import java.util.TreeSet;
 
 import org.apache.uima.UIMAFramework;
@@ -54,7 +55,7 @@ public class FsIndexCollection_impl exte
 
   private String mVendor;
 
-  private Import[] mImports;
+  private Import[] mImports = Import.EMPTY_IMPORTS;
 
   private FsIndexDescription[] mFsIndexes = new FsIndexDescription[0];
 
@@ -120,10 +121,8 @@ public class FsIndexCollection_impl exte
    * @see org.apache.uima.resource.metadata.TypeSystemDescription#getImports()
    */
   public Import[] getImports() {
-    // don't all this to return null
-    if (mImports == null)
-      mImports = new Import[0];
-    return mImports;
+    // don't allow this to return null
+    return (mImports == null) ? Import.EMPTY_IMPORTS : mImports;
   }
 
   /*
@@ -190,55 +189,65 @@ public class FsIndexCollection_impl exte
    * 
    * @see org.apache.uima.resource.metadata.TypeSystemDescription#resolveImports()
    */
-  public void resolveImports() throws InvalidXMLException {
-    resolveImports(new TreeSet<String>(), UIMAFramework.newDefaultResourceManager());
+  // support multi-threading, avoid object creation if no imports
+  public synchronized void resolveImports() throws InvalidXMLException {
+    if (getImports().length == 0) {
+      resolveImports(null, null);
+    } else {
+      resolveImports(new TreeSet<String>(), UIMAFramework.newDefaultResourceManager());
+    }
   }
 
-  public void resolveImports(ResourceManager aResourceManager) throws InvalidXMLException {
-    resolveImports(new TreeSet<String>(), aResourceManager);
+  public synchronized void resolveImports(ResourceManager aResourceManager) throws InvalidXMLException {
+    resolveImports((getImports().length == 0) ? null : new TreeSet<String>(), aResourceManager);
   }
 
-  public void resolveImports(Collection<String> aAlreadyImportedFsIndexURLs,
+  public synchronized void resolveImports(Collection<String> aAlreadyImportedFsIndexURLs,
           ResourceManager aResourceManager) throws InvalidXMLException {
-    // add our own URL, if known, to the collection of already imported URLs
-    if (getSourceUrl() != null) {
-      aAlreadyImportedFsIndexURLs.add(getSourceUrl().toString());
-    }
-    
-    List<FsIndexDescription> importedIndexes = new ArrayList<FsIndexDescription>();
-    Import[] imports = getImports();
-    for (int i = 0; i < imports.length; i++) {
-      // make sure Import's relative path base is set, to allow for users who create
-      // new import objects
-      if (imports[i] instanceof Import_impl) {
-        ((Import_impl) imports[i]).setSourceUrlIfNull(this.getSourceUrl());
+    List<FsIndexDescription> importedIndexes = null;
+    if (getImports().length != 0) {
+      // add our own URL, if known, to the collection of already imported URLs
+      if (getSourceUrl() != null) {
+        aAlreadyImportedFsIndexURLs.add(getSourceUrl().toString());
       }
-
-      URL url = imports[i].findAbsoluteUrl(aResourceManager);
-      if (!aAlreadyImportedFsIndexURLs.contains(url.toString())) {
-        aAlreadyImportedFsIndexURLs.add(url.toString());
-        try {
-          resolveImport(url, aAlreadyImportedFsIndexURLs, importedIndexes, aResourceManager);
-        } catch (IOException e) {
-          throw new InvalidXMLException(InvalidXMLException.IMPORT_FAILED_COULD_NOT_READ_FROM_URL,
-                  new Object[] { url, imports[i].getSourceUrlString() }, e);
+      
+      importedIndexes = new ArrayList<FsIndexDescription>();
+      Import[] imports = getImports();
+      for (int i = 0; i < imports.length; i++) {
+        // make sure Import's relative path base is set, to allow for users who create
+        // new import objects
+        if (imports[i] instanceof Import_impl) {
+          ((Import_impl) imports[i]).setSourceUrlIfNull(this.getSourceUrl());
+        }
+  
+        URL url = imports[i].findAbsoluteUrl(aResourceManager);
+        if (!aAlreadyImportedFsIndexURLs.contains(url.toString())) {
+          aAlreadyImportedFsIndexURLs.add(url.toString());
+          try {
+            resolveImport(url, aAlreadyImportedFsIndexURLs, importedIndexes, aResourceManager);
+          } catch (IOException e) {
+            throw new InvalidXMLException(InvalidXMLException.IMPORT_FAILED_COULD_NOT_READ_FROM_URL,
+                    new Object[] { url, imports[i].getSourceUrlString() }, e);
+          }
         }
       }
     }
     // update this object
     FsIndexDescription[] existingIndexes = this.getFsIndexes();
     if (existingIndexes == null) {
-      existingIndexes = new FsIndexDescription[0];
+      this.setFsIndexes(existingIndexes = FsIndexDescription.EMPTY_FS_INDEX_DESCRIPTIONS);
     }
-    FsIndexDescription[] newIndexes = new FsIndexDescription[existingIndexes.length
-            + importedIndexes.size()];
-    System.arraycopy(existingIndexes, 0, newIndexes, 0, existingIndexes.length);
-    for (int i = 0; i < importedIndexes.size(); i++) {
-      newIndexes[existingIndexes.length + i] = (FsIndexDescription) importedIndexes.get(i);
+    if (null != importedIndexes) {
+      FsIndexDescription[] newIndexes = new FsIndexDescription[existingIndexes.length
+              + importedIndexes.size()];
+      System.arraycopy(existingIndexes, 0, newIndexes, 0, existingIndexes.length);
+      for (int i = 0; i < importedIndexes.size(); i++) {
+        newIndexes[existingIndexes.length + i] = (FsIndexDescription) importedIndexes.get(i);
+      }
+      this.setFsIndexes(newIndexes);
     }
-    this.setFsIndexes(newIndexes);
     // clear imports
-    this.setImports(new Import[0]);
+    this.setImports(Import.EMPTY_IMPORTS);
   }
 
   private void resolveImport(URL aURL, Collection<String> aAlreadyImportedFsIndexCollectionURLs,
@@ -247,15 +256,18 @@ public class FsIndexCollection_impl exte
     //check the import cache
     FsIndexCollection desc;    
     String urlString = aURL.toString();
-    XMLizable cachedObject = aResourceManager.getImportCache().get(urlString);
-    if (cachedObject instanceof FsIndexCollection) {
-      desc = (FsIndexCollection)cachedObject;
-    } else {   
-      XMLInputSource input;
-      input = new XMLInputSource(aURL);
-      desc = UIMAFramework.getXMLParser().parseFsIndexCollection(input);
-      desc.resolveImports(aAlreadyImportedFsIndexCollectionURLs, aResourceManager);
-      aResourceManager.getImportCache().put(urlString, desc);
+    Map<String, XMLizable> importCache = aResourceManager.getImportCache();
+    synchronized(importCache) {
+      XMLizable cachedObject = importCache.get(urlString);
+      if (cachedObject instanceof FsIndexCollection) {
+        desc = (FsIndexCollection)cachedObject;
+      } else {   
+        XMLInputSource input;
+        input = new XMLInputSource(aURL);
+        desc = UIMAFramework.getXMLParser().parseFsIndexCollection(input);
+        desc.resolveImports(aAlreadyImportedFsIndexCollectionURLs, aResourceManager);
+        importCache.put(urlString, desc);
+      }
     }
     aResults.addAll(Arrays.asList(desc.getFsIndexes()));
   }

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/ResourceManagerConfiguration_impl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/ResourceManagerConfiguration_impl.java?rev=1584687&r1=1584686&r2=1584687&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/ResourceManagerConfiguration_impl.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/ResourceManagerConfiguration_impl.java Fri Apr  4 13:50:02 2014
@@ -55,7 +55,7 @@ public class ResourceManagerConfiguratio
 
   private String mVendor;
 
-  private Import[] mImports = new Import[0];
+  private Import[] mImports = Import.EMPTY_IMPORTS;
 
   private ExternalResourceBinding[] mBindings = new ExternalResourceBinding[0];
 
@@ -265,69 +265,82 @@ public class ResourceManagerConfiguratio
    * 
    * @see org.apache.uima.resource.metadata.TypeSystemDescription#resolveImports()
    */
-  public void resolveImports() throws InvalidXMLException {
-    resolveImports(new TreeSet<String>(), UIMAFramework.newDefaultResourceManager());
+  // support multi-threading, avoid object creation if no imports
+  public synchronized void resolveImports() throws InvalidXMLException {
+    if (getImports().length == 0) {
+      resolveImports(null, null);
+    } else {
+      resolveImports(new TreeSet<String>(), UIMAFramework.newDefaultResourceManager());
+    }
   }
 
-  public void resolveImports(ResourceManager aResourceManager) throws InvalidXMLException {
-    resolveImports(new TreeSet<String>(), aResourceManager);
+  public synchronized void resolveImports(ResourceManager aResourceManager) throws InvalidXMLException {
+    resolveImports((getImports().length == 0) ? null : new TreeSet<String>(), aResourceManager);
   }
 
-  public void resolveImports(Collection<String> aAlreadyImportedURLs, ResourceManager aResourceManager)
+  public synchronized void resolveImports(Collection<String> aAlreadyImportedURLs, ResourceManager aResourceManager)
           throws InvalidXMLException {
-    // add our own URL, if known, to the collection of already imported URLs
-    if (getSourceUrl() != null) {
-      aAlreadyImportedURLs.add(getSourceUrl().toString());
-    }
-    List<ExternalResourceDescription> importedResources = new ArrayList<ExternalResourceDescription>();
-    List<ExternalResourceBinding> importedBindings = new ArrayList<ExternalResourceBinding>();
-    Import[] imports = getImports();
-    for (int i = 0; i < imports.length; i++) {
-      // make sure Import's relative path base is set, to allow for users who create
-      // new import objects
-      if (imports[i] instanceof Import_impl) {
-        ((Import_impl) imports[i]).setSourceUrlIfNull(this.getSourceUrl());
+    List<ExternalResourceDescription> importedResources = null;
+    List<ExternalResourceBinding> importedBindings = null;
+    if (getImports().length != 0) {
+      // add our own URL, if known, to the collection of already imported URLs
+      if (getSourceUrl() != null) {
+        aAlreadyImportedURLs.add(getSourceUrl().toString());
       }
-      URL url = imports[i].findAbsoluteUrl(aResourceManager);
-      if (!aAlreadyImportedURLs.contains(url.toString())) {
-        aAlreadyImportedURLs.add(url.toString());
-        try {
-          resolveImport(url, aAlreadyImportedURLs, importedResources, importedBindings,
-                  aResourceManager);
-        } catch (IOException e) {
-          throw new InvalidXMLException(InvalidXMLException.IMPORT_FAILED_COULD_NOT_READ_FROM_URL,
-                  new Object[] { url, imports[i].getSourceUrlString() }, e);
+      importedResources = new ArrayList<ExternalResourceDescription>();
+      importedBindings = new ArrayList<ExternalResourceBinding>();
+      Import[] imports = getImports();
+      for (int i = 0; i < imports.length; i++) {
+        // make sure Import's relative path base is set, to allow for users who create
+        // new import objects
+        if (imports[i] instanceof Import_impl) {
+          ((Import_impl) imports[i]).setSourceUrlIfNull(this.getSourceUrl());
+        }
+        URL url = imports[i].findAbsoluteUrl(aResourceManager);
+        if (!aAlreadyImportedURLs.contains(url.toString())) {
+          aAlreadyImportedURLs.add(url.toString());
+          try {
+            resolveImport(url, aAlreadyImportedURLs, importedResources, importedBindings,
+                    aResourceManager);
+          } catch (IOException e) {
+            throw new InvalidXMLException(InvalidXMLException.IMPORT_FAILED_COULD_NOT_READ_FROM_URL,
+                    new Object[] { url, imports[i].getSourceUrlString() }, e);
+          }
         }
       }
     }
-
+    
     // update this object
     ExternalResourceDescription[] existingResources = this.getExternalResources();
     if (existingResources == null) {
-      existingResources = new ExternalResourceDescription[0];
+      this.setExternalResources(existingResources = ExternalResourceDescription.EMPTY_EXTERNAL_RESORUCE_DESCRIPTIONS);
     }
-    ExternalResourceDescription[] newResources = new ExternalResourceDescription[existingResources.length
-            + importedResources.size()];
-    System.arraycopy(existingResources, 0, newResources, 0, existingResources.length);
-    for (int i = 0; i < importedResources.size(); i++) {
-      newResources[existingResources.length + i] = (ExternalResourceDescription) importedResources
-              .get(i);
+    if (importedResources != null) {
+      ExternalResourceDescription[] newResources = new ExternalResourceDescription[existingResources.length
+              + importedResources.size()];
+      System.arraycopy(existingResources, 0, newResources, 0, existingResources.length);
+      for (int i = 0; i < importedResources.size(); i++) {
+        newResources[existingResources.length + i] = (ExternalResourceDescription) importedResources
+                .get(i);
+      }
+      this.setExternalResources(newResources);
     }
-    this.setExternalResources(newResources);
-
+    
     ExternalResourceBinding[] existingBindings = this.getExternalResourceBindings();
     if (existingBindings == null) {
-      existingBindings = new ExternalResourceBinding[0];
+      this.setExternalResourceBindings(existingBindings = ExternalResourceBinding.EMPTY_RESOURCE_BINDINGS);
     }
-    ExternalResourceBinding[] newBindings = new ExternalResourceBinding[existingBindings.length
-            + importedBindings.size()];
-    System.arraycopy(existingBindings, 0, newBindings, 0, existingBindings.length);
-    for (int i = 0; i < importedBindings.size(); i++) {
-      newBindings[existingBindings.length + i] = (ExternalResourceBinding) importedBindings.get(i);
+    if (null != importedBindings) {
+      ExternalResourceBinding[] newBindings = new ExternalResourceBinding[existingBindings.length
+              + importedBindings.size()];
+      System.arraycopy(existingBindings, 0, newBindings, 0, existingBindings.length);
+      for (int i = 0; i < importedBindings.size(); i++) {
+        newBindings[existingBindings.length + i] = (ExternalResourceBinding) importedBindings.get(i);
+      }
+      this.setExternalResourceBindings(newBindings);
     }
-    this.setExternalResourceBindings(newBindings);
     // clear imports
-    this.setImports(new Import[0]);
+    this.setImports(Import.EMPTY_IMPORTS);
   }
 
   private void resolveImport(URL aURL, Collection<String> aAlreadyImportedURLs,

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/TypePriorities_impl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/TypePriorities_impl.java?rev=1584687&r1=1584686&r2=1584687&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/TypePriorities_impl.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/TypePriorities_impl.java Fri Apr  4 13:50:02 2014
@@ -26,6 +26,7 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.TreeSet;
 
 import org.apache.uima.UIMAFramework;
@@ -48,7 +49,7 @@ import org.xml.sax.SAXException;
 public class TypePriorities_impl extends MetaDataObject_impl implements TypePriorities {
 
   static final long serialVersionUID = -4773863151055424438L;
-
+  
   private String mName;
 
   private String mVersion;
@@ -57,10 +58,10 @@ public class TypePriorities_impl extends
 
   private String mVendor;
 
-  private Import[] mImports = new Import[0];
+  private Import[] mImports = Import.EMPTY_IMPORTS;
 
   private List<TypePriorityList> mPriorityLists = new ArrayList<TypePriorityList>();
-
+  
   /**
    * @see ResourceMetaData#getName()
    */
@@ -137,20 +138,27 @@ public class TypePriorities_impl extends
 
   /**
    * @see TypePriorities#getPriorityLists()
+   * synchronized to prevent concurrent mod exceptions
    */
   public TypePriorityList[] getPriorityLists() {
-    TypePriorityList[] result = new TypePriorityList[mPriorityLists.size()];
-    mPriorityLists.toArray(result);
-    return result;
+    synchronized (mPriorityLists) { // saw concurrent mod exception 3/2014
+      TypePriorityList[] result = new TypePriorityList[mPriorityLists.size()];
+      mPriorityLists.toArray(result);
+      return result;
+    }
   }
 
   /**
    * @see TypePriorities#setPriorityLists(TypePriorityList[])
+   * could be called by thread doing resolve imports,
+   * while another thread was iterating over them
    */
   public void setPriorityLists(TypePriorityList[] aPriorityLists) {
-    mPriorityLists.clear();
-    for (int i = 0; i < aPriorityLists.length; i++) {
-      mPriorityLists.add(aPriorityLists[i]);
+    synchronized (mPriorityLists) { // saw concurrent mod exceptions 3/2014      
+      mPriorityLists.clear();
+      for (int i = 0; i < aPriorityLists.length; i++) {
+        mPriorityLists.add(aPriorityLists[i]);
+      }
     }
   }
 
@@ -158,7 +166,9 @@ public class TypePriorities_impl extends
    * @see TypePriorities#addPriorityList(TypePriorityList)
    */
   public void addPriorityList(TypePriorityList aPriorityList) {
-    mPriorityLists.add(aPriorityList);
+    synchronized (mPriorityLists) { // saw concurrent mod exceptions 3/2014 
+      mPriorityLists.add(aPriorityList);
+    }
   }
 
   /**
@@ -166,7 +176,9 @@ public class TypePriorities_impl extends
    */
   public TypePriorityList addPriorityList() {
     TypePriorityList newPriorityList = new TypePriorityList_impl();
-    mPriorityLists.add(newPriorityList);
+    synchronized (mPriorityLists) { // saw concurrent mod exceptions while iterating on this 3/2014
+      mPriorityLists.add(newPriorityList);
+    }
     return newPriorityList;
   }
 
@@ -174,63 +186,77 @@ public class TypePriorities_impl extends
    * @see TypePriorities#removePriorityList(TypePriorityList)
    */
   public void removePriorityList(TypePriorityList aPriorityList) {
-    mPriorityLists.remove(aPriorityList);
+    synchronized (mPriorityLists) { // saw concurrent mod exceptions while iterating on this 3/2014
+      mPriorityLists.remove(aPriorityList);
+    }
   }
 
   /**
    * @see TypeSystemDescription#resolveImports()
    */
-  public void resolveImports() throws InvalidXMLException {
-    resolveImports(new TreeSet<String>(), UIMAFramework.newDefaultResourceManager());
+  // support multithreading,
+  // avoid object creation if already resolved
+  public synchronized void resolveImports() throws InvalidXMLException {
+    if (getImports().length == 0) {
+      resolveImports(null, null);
+    } else {
+      resolveImports(new TreeSet<String>(), UIMAFramework.newDefaultResourceManager());
+    }
   }
 
-  public void resolveImports(ResourceManager aResourceManager) throws InvalidXMLException {
-    resolveImports(new TreeSet<String>(), aResourceManager);
+  public synchronized void resolveImports(ResourceManager aResourceManager) throws InvalidXMLException {
+    resolveImports((getImports().length == 0) ? null : new TreeSet<String>(), aResourceManager);
   }
 
-  public void resolveImports(Collection<String> aAlreadyImportedTypePrioritiesURLs,
+  public synchronized void resolveImports(Collection<String> aAlreadyImportedTypePrioritiesURLs,
           ResourceManager aResourceManager) throws InvalidXMLException {
-    // add our own URL, if known, to the collection of already imported URLs
-    if (getSourceUrl() != null) {
-      aAlreadyImportedTypePrioritiesURLs.add(getSourceUrl().toString());
-    }
-    
-    List<TypePriorityList> importedPriorityLists = new ArrayList<TypePriorityList>();
-    Import[] imports = getImports();
-    for (int i = 0; i < imports.length; i++) {
-      // make sure Import's relative path base is set, to allow for users who create
-      // new import objects
-      if (imports[i] instanceof Import_impl) {
-        ((Import_impl) imports[i]).setSourceUrlIfNull(this.getSourceUrl());
+    List<TypePriorityList> importedPriorityLists = null;
+    if (getImports().length != 0) {
+  
+      // add our own URL, if known, to the collection of already imported URLs
+      if (getSourceUrl() != null) {
+        aAlreadyImportedTypePrioritiesURLs.add(getSourceUrl().toString());
       }
-
-      URL url = imports[i].findAbsoluteUrl(aResourceManager);
-      if (!aAlreadyImportedTypePrioritiesURLs.contains(url.toString())) {
-        aAlreadyImportedTypePrioritiesURLs.add(url.toString());
-        try {
-          resolveImport(url, aAlreadyImportedTypePrioritiesURLs, importedPriorityLists,
-                  aResourceManager);
-        } catch (IOException e) {
-          throw new InvalidXMLException(InvalidXMLException.IMPORT_FAILED_COULD_NOT_READ_FROM_URL,
-                  new Object[] { url, imports[i].getSourceUrlString() }, e);
+      
+      importedPriorityLists = new ArrayList<TypePriorityList>();
+      Import[] imports = getImports();
+      for (int i = 0; i < imports.length; i++) {
+        // make sure Import's relative path base is set, to allow for users who create
+        // new import objects
+        if (imports[i] instanceof Import_impl) {
+          ((Import_impl) imports[i]).setSourceUrlIfNull(this.getSourceUrl());
+        }
+  
+        URL url = imports[i].findAbsoluteUrl(aResourceManager);
+        if (!aAlreadyImportedTypePrioritiesURLs.contains(url.toString())) {
+          aAlreadyImportedTypePrioritiesURLs.add(url.toString());
+          try {
+            resolveImport(url, aAlreadyImportedTypePrioritiesURLs, importedPriorityLists,
+                    aResourceManager);
+          } catch (IOException e) {
+            throw new InvalidXMLException(InvalidXMLException.IMPORT_FAILED_COULD_NOT_READ_FROM_URL,
+                    new Object[] { url, imports[i].getSourceUrlString() }, e);
+          }
         }
       }
     }
-    // update this object
+    //update this object
     TypePriorityList[] existingPriorityLists = this.getPriorityLists();
     if (existingPriorityLists == null) {
-      existingPriorityLists = new TypePriorityList[0];
+      this.setPriorityLists(existingPriorityLists = TypePriorityList.EMPTY_TYPE_PRIORITY_LISTS);
     }
-    TypePriorityList[] newPriorityLists = new TypePriorityList[existingPriorityLists.length
-            + importedPriorityLists.size()];
-    System.arraycopy(existingPriorityLists, 0, newPriorityLists, 0, existingPriorityLists.length);
-    for (int i = 0; i < importedPriorityLists.size(); i++) {
-      newPriorityLists[existingPriorityLists.length + i] = (TypePriorityList) importedPriorityLists
-              .get(i);
+    if (importedPriorityLists != null ) {
+      TypePriorityList[] newPriorityLists = new TypePriorityList[existingPriorityLists.length
+              + importedPriorityLists.size()];
+      System.arraycopy(existingPriorityLists, 0, newPriorityLists, 0, existingPriorityLists.length);
+      for (int i = 0; i < importedPriorityLists.size(); i++) {
+        newPriorityLists[existingPriorityLists.length + i] = (TypePriorityList) importedPriorityLists
+                .get(i);
+      }
+      this.setPriorityLists(newPriorityLists);
     }
-    this.setPriorityLists(newPriorityLists);
     // clear imports
-    this.setImports(new Import[0]);
+    this.setImports(Import.EMPTY_IMPORTS);
   }
 
   private void resolveImport(URL aURL, Collection<String> aAlreadyImportedTypePrioritiesURLs,
@@ -239,15 +265,18 @@ public class TypePriorities_impl extends
     //check the import cache
     TypePriorities desc;    
     String urlString = aURL.toString();
-    XMLizable cachedObject = aResourceManager.getImportCache().get(urlString);
-    if (cachedObject instanceof TypePriorities) {
-      desc = (TypePriorities)cachedObject;
-    } else {   
-      XMLInputSource input;
-      input = new XMLInputSource(aURL);
-      desc = UIMAFramework.getXMLParser().parseTypePriorities(input);
-      desc.resolveImports(aAlreadyImportedTypePrioritiesURLs, aResourceManager);
-      aResourceManager.getImportCache().put(urlString, desc);
+    Map<String, XMLizable> importCache = aResourceManager.getImportCache();
+    synchronized(importCache) {
+      XMLizable cachedObject = importCache.get(urlString);
+      if (cachedObject instanceof TypePriorities) {
+        desc = (TypePriorities)cachedObject;
+      } else {   
+        XMLInputSource input;
+        input = new XMLInputSource(aURL);
+        desc = UIMAFramework.getXMLParser().parseTypePriorities(input);
+        desc.resolveImports(aAlreadyImportedTypePrioritiesURLs, aResourceManager);
+        importCache.put(urlString, desc);
+      }
     }
     aResults.addAll(Arrays.asList(desc.getPriorityLists()));
   }
@@ -277,12 +306,13 @@ public class TypePriorities_impl extends
   public Object clone() {
     TypePriorities_impl clone = (TypePriorities_impl) super.clone();
     clone.mPriorityLists = new ArrayList<TypePriorityList>();
-    Iterator<TypePriorityList> priListIter = mPriorityLists.iterator();
-    while (priListIter.hasNext()) {
-      TypePriorityList priList = priListIter.next();
-      clone.addPriorityList((TypePriorityList) priList.clone());
+    synchronized (mPriorityLists) { // saw concurrent mod exceptions while iterating on this 3/2014
+      Iterator<TypePriorityList> priListIter = mPriorityLists.iterator();
+      while (priListIter.hasNext()) {
+        TypePriorityList priList = priListIter.next();
+        clone.addPriorityList((TypePriorityList) priList.clone());
+      }
     }
-
     return clone;
   }
 

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/TypePriorityList_impl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/TypePriorityList_impl.java?rev=1584687&r1=1584686&r2=1584687&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/TypePriorityList_impl.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/TypePriorityList_impl.java Fri Apr  4 13:50:02 2014
@@ -37,8 +37,9 @@ public class TypePriorityList_impl exten
 
   /**
    * @see TypePriorityList#getTypes()
+   * synchronized to prevent concurrent modification exceptions
    */
-  public String[] getTypes() {
+  public synchronized String[] getTypes() {
     String[] result = new String[mTypeNames.size()];
     mTypeNames.toArray(result);
     return result;
@@ -47,7 +48,7 @@ public class TypePriorityList_impl exten
   /**
    * @see TypePriorityList#setTypes(java.lang.String[])
    */
-  public void setTypes(String[] aTypeNames) {
+  public synchronized void setTypes(String[] aTypeNames) {
     mTypeNames.clear();
     for (int i = 0; i < aTypeNames.length; i++) {
       mTypeNames.add(aTypeNames[i]);
@@ -57,25 +58,25 @@ public class TypePriorityList_impl exten
   /**
    * @see TypePriorityList#addType(java.lang.String)
    */
-  public void addType(String aTypeName) {
+  public synchronized void addType(String aTypeName) {
     mTypeNames.add(aTypeName);
-
   }
 
   /**
    * @see TypePriorityList#removeType(java.lang.String)
    */
-  public void removeType(String aTypeName) {
+  public synchronized void removeType(String aTypeName) {
     mTypeNames.remove(aTypeName);
   }
 
   /*
    * (non-Javadoc) Special purpose clone method to deal with ArrayList.
    */
-  public Object clone() {
+  public synchronized Object clone() {
+    //surprise: super.clone sets the final field to the same array list as the original
     TypePriorityList_impl clone = (TypePriorityList_impl) super.clone();
-
-    clone.mTypeNames = new ArrayList<String>();
+    
+    clone.mTypeNames = new ArrayList();  // because above clone has set it to the == object
     for (String name : mTypeNames) {
       clone.addType(name);
     }

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/TypeSystemDescription_impl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/TypeSystemDescription_impl.java?rev=1584687&r1=1584686&r2=1584687&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/TypeSystemDescription_impl.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/TypeSystemDescription_impl.java Fri Apr  4 13:50:02 2014
@@ -25,6 +25,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 import java.util.TreeSet;
 
 import org.apache.uima.UIMAFramework;
@@ -47,7 +48,7 @@ public class TypeSystemDescription_impl 
         TypeSystemDescription {
 
   static final long serialVersionUID = -3372766232454730201L;
-
+  
   private String mName;
 
   private String mVersion;
@@ -56,7 +57,7 @@ public class TypeSystemDescription_impl 
 
   private String mVendor;
 
-  private Import[] mImports = new Import[0];
+  private Import[] mImports = Import.EMPTY_IMPORTS;
 
   /** Descriptions of all Types in this type system. */
   private TypeDescription[] mTypes = new TypeDescription[0];
@@ -194,54 +195,63 @@ public class TypeSystemDescription_impl 
   /**
    * @see TypeSystemDescription#resolveImports()
    */
-  public void resolveImports() throws InvalidXMLException {
-    resolveImports(new TreeSet<String>(), UIMAFramework.newDefaultResourceManager());
+  // allow these calls to be done multiple times on this same object, in different threads
+  public synchronized void resolveImports() throws InvalidXMLException {
+    if (getImports().length == 0) {
+      resolveImports(null, null);
+    } else {
+      resolveImports(new TreeSet<String>(), UIMAFramework.newDefaultResourceManager());
+    }
   }
 
-  public void resolveImports(ResourceManager aResourceManager) throws InvalidXMLException {
-    resolveImports(new TreeSet<String>(), aResourceManager);
+  public synchronized void resolveImports(ResourceManager aResourceManager) throws InvalidXMLException {
+    resolveImports((getImports().length == 0) ? null : new TreeSet<String>(), aResourceManager);
   }
 
-  public void resolveImports(Collection<String> aAlreadyImportedTypeSystemURLs,
+  public synchronized void resolveImports(Collection<String> aAlreadyImportedTypeSystemURLs,
           ResourceManager aResourceManager) throws InvalidXMLException {
-    // add our own URL, if known, to the collection of already imported URLs
-    if (getSourceUrl() != null) {
-      aAlreadyImportedTypeSystemURLs.add(getSourceUrl().toString());
-    }
-
-    List<TypeDescription> importedTypes = new ArrayList<TypeDescription>();
-    Import[] imports = getImports();
-    for (int i = 0; i < imports.length; i++) {
-      // make sure Import's relative path base is set, to allow for users who create
-      // new import objects
-      if (imports[i] instanceof Import_impl) {
-        ((Import_impl) imports[i]).setSourceUrlIfNull(this.getSourceUrl());
+    List<TypeDescription> importedTypes = null;
+    if (getImports().length != 0) {
+      // add our own URL, if known, to the collection of already imported URLs
+      if (getSourceUrl() != null) {
+        aAlreadyImportedTypeSystemURLs.add(getSourceUrl().toString());
       }
-      URL url = imports[i].findAbsoluteUrl(aResourceManager);
-      if (!aAlreadyImportedTypeSystemURLs.contains(url.toString())) {
-        aAlreadyImportedTypeSystemURLs.add(url.toString());
-        try {
-          resolveImport(url, aAlreadyImportedTypeSystemURLs, importedTypes, aResourceManager);
-        } catch (IOException e) {
-          throw new InvalidXMLException(InvalidXMLException.IMPORT_FAILED_COULD_NOT_READ_FROM_URL,
-                  new Object[] { url, imports[i].getSourceUrlString() }, e);
+  
+      importedTypes = new ArrayList<TypeDescription>();
+      Import[] imports = getImports();
+      for (int i = 0; i < imports.length; i++) {
+        // make sure Import's relative path base is set, to allow for users who create
+        // new import objects
+        if (imports[i] instanceof Import_impl) {
+          ((Import_impl) imports[i]).setSourceUrlIfNull(this.getSourceUrl());
+        }
+        URL url = imports[i].findAbsoluteUrl(aResourceManager);
+        if (!aAlreadyImportedTypeSystemURLs.contains(url.toString())) {
+          aAlreadyImportedTypeSystemURLs.add(url.toString());
+          try {
+            resolveImport(url, aAlreadyImportedTypeSystemURLs, importedTypes, aResourceManager);
+          } catch (IOException e) {
+            throw new InvalidXMLException(InvalidXMLException.IMPORT_FAILED_COULD_NOT_READ_FROM_URL,
+                    new Object[] { url, imports[i].getSourceUrlString() }, e);
+          }
         }
       }
     }
-    // update this object
+    // maybe update this object
     TypeDescription[] existingTypes = this.getTypes();
     if (existingTypes == null) {
-      existingTypes = new TypeDescription[0];
+      this.setTypes(existingTypes = TypeDescription.EMPTY_TYPE_DESCRIPTIONS);
     }
-    TypeDescription[] newTypes = new TypeDescription[existingTypes.length + importedTypes.size()];
-    System.arraycopy(existingTypes, 0, newTypes, 0, existingTypes.length);
-    for (int i = 0; i < importedTypes.size(); i++) {
-      newTypes[existingTypes.length + i] = (TypeDescription) importedTypes.get(i);
+    if (null != importedTypes) {      
+      TypeDescription[] newTypes = new TypeDescription[existingTypes.length + importedTypes.size()];
+      System.arraycopy(existingTypes, 0, newTypes, 0, existingTypes.length);
+      for (int i = 0; i < importedTypes.size(); i++) {
+        newTypes[existingTypes.length + i] = (TypeDescription) importedTypes.get(i);
+      }
+      this.setTypes(newTypes);
     }
-    this.setTypes(newTypes);
-
     // clear imports
-    this.setImports(new Import[0]);
+    this.setImports(Import.EMPTY_IMPORTS);
   }
 
   private void resolveImport(URL aURL, Collection<String> aAlreadyImportedTypeSystemURLs,
@@ -250,15 +260,18 @@ public class TypeSystemDescription_impl 
     //check the import cache
     TypeSystemDescription desc;    
     String urlString = aURL.toString();
-    XMLizable cachedObject = aResourceManager.getImportCache().get(urlString);
-    if (cachedObject instanceof TypeSystemDescription) {
-      desc = (TypeSystemDescription)cachedObject;
-    } else {   
-      XMLInputSource input;
-      input = new XMLInputSource(aURL);
-      desc = UIMAFramework.getXMLParser().parseTypeSystemDescription(input);
-      desc.resolveImports(aAlreadyImportedTypeSystemURLs, aResourceManager);
-      aResourceManager.getImportCache().put(urlString, desc);
+    Map<String, XMLizable> importCache = aResourceManager.getImportCache();
+    synchronized(importCache) {
+      XMLizable cachedObject = importCache.get(urlString);
+      if (cachedObject instanceof TypeSystemDescription) {
+        desc = (TypeSystemDescription)cachedObject;
+      } else {   
+        XMLInputSource input;
+        input = new XMLInputSource(aURL);
+        desc = UIMAFramework.getXMLParser().parseTypeSystemDescription(input);
+        desc.resolveImports(aAlreadyImportedTypeSystemURLs, aResourceManager);
+        importCache.put(urlString, desc);
+      }
     }
     aResults.addAll(Arrays.asList(desc.getTypes()));
   }