Author: schor
Date: Thu Mar 20 14:09:26 2014
New Revision: 1579633

URL: http://svn.apache.org/r1579633
Log:
[UIMA-3688] improve multi-core support in Resource Manger impl

Modified:
    
uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManager_impl.java

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=1579633&r1=1579632&r2=1579633&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
 Thu Mar 20 14:09:26 2014
@@ -28,6 +28,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.UIMA_IllegalStateException;
@@ -60,6 +61,13 @@ public class ResourceManager_impl implem
    * resource bundle for log messages
    */
   protected static final String LOG_RESOURCE_BUNDLE = 
"org.apache.uima.impl.log_messages";
+  
+  protected static final Class<Resource> EMPTY_RESOURCE_CLASS = 
Resource.class; 
+
+  /**
+   * a monitor lock for synchronizing get/set of casManager ref
+   */
+  private final Object casManagerMonitor = new Object();
 
   /**
    * Object used for resolving relative paths. This is built by parsing the 
data path.
@@ -69,33 +77,36 @@ public class ResourceManager_impl implem
   /**
    * Map from qualified key names (declared in resource dependency XML) to 
Resource objects.
    */
-  protected Map<String, Object> mResourceMap = Collections.synchronizedMap(new 
HashMap<String, Object>());
+  protected Map<String, Object> mResourceMap = new ConcurrentHashMap<String, 
Object>();
 
   /**
    * Internal map from resource names (declared in resource declaration XML) 
to ResourceRegistration
    * objects. Used during initialization only.
    */
-  protected Map<String, ResourceRegistration> mInternalResourceRegistrationMap 
= Collections.synchronizedMap(new HashMap<String, ResourceRegistration>());
+  protected Map<String, ResourceRegistration> mInternalResourceRegistrationMap 
= 
+      new ConcurrentHashMap<String, ResourceRegistration>();
 
   /**
    * Map from String keys to Class objects. For ParameterizedResources only, 
stores the
    * implementation class corresponding to each resource name.
    */
-  protected Map<String, Class<?>> mParameterizedResourceImplClassMap = 
Collections.synchronizedMap(new HashMap<String, Class<?>>());
+  protected Map<String, Class<?>> mParameterizedResourceImplClassMap = 
+      new ConcurrentHashMap<String, Class<?>>();
 
   /**
    * Internal map from resource names (declared in resource declaration XML) 
to Class objects. Used
    * internally during resource initialization.
    */
-  protected Map<String, Class<?>> mInternalParameterizedResourceImplClassMap = 
Collections
-          .synchronizedMap(new HashMap<String, Class<?>>());
+  protected Map<String, Class<?>> mInternalParameterizedResourceImplClassMap = 
+      new ConcurrentHashMap<String, Class<?>>();
 
   /**
-   * Map from ArrayList(0:String,1:DataResource) keys to Resource objects. For
+   * 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 = 
Collections.synchronizedMap(new HashMap<List<Object>, Object>());
+  protected Map<List<Object>, Object> mParameterizedResourceInstanceMap = 
+      new ConcurrentHashMap<List<Object>, Object>();
 
   /**
    * UIMA extension ClassLoader. ClassLoader is created if an extension 
classpath is specified at
@@ -104,13 +115,19 @@ public class ResourceManager_impl implem
   private UIMAClassLoader uimaCL = null;
 
   /** CasManager - manages creation and pooling of CASes. */
-  // gets and sets of this are synchronized
-  protected CasManager mCasManager = null;
+  // volatile to support double-checked locking idiom
+  protected volatile CasManager mCasManager = null;
 
   /**
    * Cache of imported descriptors, so that parsed objects can be reused if the
    * same URL is imported more than once.
    * 
+   * All callers of this synchronize on the importCache object before doing a 
+   *    get
+   *    ...
+   *    put
+   * sequence
+   * 
    * Use Case where synchronization is needed:
    *   running multiple instances on multiple threads, sharing a common 
resource manager,
    *   the initialization that merges typePriorities happens lazily, when 
using Cas Multipliers,
@@ -118,6 +135,7 @@ public class ResourceManager_impl implem
    *   are synchronized among themselves, any other use of this map that might 
occur
    *   simultaneously is not.
    */
+  // leaving this as a synchronizedMap - for backwards compatibility
   private Map<String,XMLizable> importCache = Collections.synchronizedMap(new 
HashMap<String,XMLizable>());
   
   /**
@@ -127,6 +145,14 @@ public class ResourceManager_impl implem
     mRelativePathResolver = new RelativePathResolver_impl();
   }
 
+  /**
+   * Creates a new <code>ResourceManager_impl</code> with a custom ClassLoader 
to use for locating
+   * resources.
+   */
+  public ResourceManager_impl(ClassLoader aClassLoader) {
+    mRelativePathResolver = new RelativePathResolver_impl(aClassLoader);
+  }
+
  /**
   * Support reusing UIMA Class Loader instances to speed up
   * things including the Component Description Editor when
@@ -183,14 +209,6 @@ public class ResourceManager_impl implem
   }
 
   /**
-   * Creates a new <code>ResourceManager_impl</code> with a custom ClassLoader 
to use for locating
-   * resources.
-   */
-  public ResourceManager_impl(ClassLoader aClassLoader) {
-    mRelativePathResolver = new RelativePathResolver_impl(aClassLoader);
-  }
-
-  /**
    * @see org.apache.uima.resource.ResourceManager#getDataPath()
    */
   public String getDataPath() {
@@ -230,13 +248,17 @@ public class ResourceManager_impl implem
               new Object[] { aName });
     }
     return r;
-
   }
 
   /**
    * @see 
org.apache.uima.resource.ResourceManager#getResource(java.lang.String, 
java.lang.String[])
    */
   public Object getResource(String aName, String[] aParams) throws 
ResourceAccessException {
+    /* Multi-core design
+     *   This may be called by user code sharing the same Resource Manager, 
and / or the same 
+     *     uima context object.
+     *   Do double-checked idiom to avoid locking where resource is already 
available, loaded   
+     */
     Object r = mResourceMap.get(aName);
 
     // if no resource found, return null
@@ -259,35 +281,41 @@ public class ResourceManager_impl implem
     }
 
     // see if we've already encountered this DataResource under this resource 
name
-    ArrayList<Object> nameAndResource = new ArrayList<Object>();
+    List<Object> nameAndResource = new ArrayList<Object>(2);
     nameAndResource.add(aName);
     nameAndResource.add(dr);
     Object resourceInstance = 
mParameterizedResourceInstanceMap.get(nameAndResource);
     if (resourceInstance != null) {
       return resourceInstance;
     }
-
-    // We haven't encountered this before. See if we need to instantiate a
-    // SharedResourceObject
-    Class<?> sharedResourceObjectClass = 
mParameterizedResourceImplClassMap.get(aName);
-    if (sharedResourceObjectClass != null) {
-      try {
-        SharedResourceObject sro = (SharedResourceObject) 
sharedResourceObjectClass.newInstance();
-        sro.load(dr);
-        mParameterizedResourceInstanceMap.put(nameAndResource, sro);
-        return sro;
-      } catch (InstantiationException e) {
-        throw new ResourceAccessException(e);
-      } catch (IllegalAccessException e) {
-        throw new ResourceAccessException(e);
-      } catch (ResourceInitializationException e) {
-        throw new ResourceAccessException(e);
+    synchronized(mParameterizedResourceInstanceMap) {
+      // double-check idiom
+      resourceInstance = 
mParameterizedResourceInstanceMap.get(nameAndResource);
+      if (resourceInstance != null) {
+        return resourceInstance;
+      }
+      // We haven't encountered this before. See if we need to instantiate a
+      // SharedResourceObject
+      Class<?> sharedResourceObjectClass = 
mParameterizedResourceImplClassMap.get(aName);
+      if (sharedResourceObjectClass != EMPTY_RESOURCE_CLASS) {
+        try {
+          SharedResourceObject sro = (SharedResourceObject) 
sharedResourceObjectClass.newInstance();
+          sro.load(dr);
+          mParameterizedResourceInstanceMap.put(nameAndResource, sro);
+          return sro;
+        } catch (InstantiationException e) {
+          throw new ResourceAccessException(e);
+        } catch (IllegalAccessException e) {
+          throw new ResourceAccessException(e);
+        } catch (ResourceInitializationException e) {
+          throw new ResourceAccessException(e);
+        }
+      } else
+      // no impl. class - just return the DataResource
+      {
+        mParameterizedResourceInstanceMap.put(nameAndResource, dr);
+        return dr;
       }
-    } else
-    // no impl. class - just return the DataResource
-    {
-      mParameterizedResourceInstanceMap.put(nameAndResource, dr);
-      return dr;
     }
   }
 
@@ -305,7 +333,7 @@ public class ResourceManager_impl implem
     // if this is a ParameterizedDataResource, look up its class
     if (r instanceof ParameterizedDataResource) {
       Class<? extends Resource> customResourceClass = (Class<? extends 
Resource>) mParameterizedResourceImplClassMap.get(aName);
-      if (customResourceClass == null) {
+      if (customResourceClass == EMPTY_RESOURCE_CLASS) {
         // return the default class
         return DataResource_impl.class;
       }
@@ -324,37 +352,35 @@ public class ResourceManager_impl implem
    */
   public InputStream getResourceAsStream(String aKey, String[] aParams)
           throws ResourceAccessException {
-    try {
-      // see if this resource is registered in the ResourceManager
-      Object r = getResource(aKey, aParams);
-      // if so, and if it is a DataResource, use its InputStream
-      if (r != null && r instanceof DataResource) {
-        return ((DataResource) r).getInputStream();
-      } else {
-        return null;
-      }
-    } catch (IOException e) {
-      throw new ResourceAccessException(e);
-    }
+    return getResourceAsStreamCommon(getResource(aKey, aParams));
   }
-
+  
   /*
    * (non-Javadoc)
    * 
    * @see 
org.apache.uima.resource.ResourceManager#getResourceAsStream(java.lang.String)
    */
   public InputStream getResourceAsStream(String aKey) throws 
ResourceAccessException {
+    return getResourceAsStreamCommon(getResource(aKey));
+  }
+
+  private InputStream getResourceAsStreamCommon(Object resource) throws 
ResourceAccessException {
     try {
-      // see if this resource is registered in the ResourceManager
-      Object r = getResource(aKey);
-      // if so, and if it is a DataResource, use its InputStream
-      if (r != null && r instanceof DataResource) {
-        return ((DataResource) r).getInputStream();
+      if (resource != null && resource instanceof DataResource) {
+        return ((DataResource) resource).getInputStream();
       } else {
         return null;
       }
     } catch (IOException e) {
       throw new ResourceAccessException(e);
+    }    
+  }
+
+  private URL getResourceAsStreamCommonUrl(Object resource) {
+    if (resource != null && resource instanceof DataResource) {
+      return ((DataResource) resource).getUrl();
+    } else {
+      return null;
     }
   }
 
@@ -365,32 +391,7 @@ public class ResourceManager_impl implem
    *      java.lang.String[])
    */
   public URL getResourceURL(String aKey, String[] aParams) throws 
ResourceAccessException {
-    // try
-    // {
-    // see if this resource is registered in the ResourceManager
-    Object r = getResource(aKey, aParams);
-    // if so, and if it is a DataResource, use its URL
-    if (r != null && r instanceof DataResource) {
-      return ((DataResource) r).getUrl();
-    } else {
-      return null;
-      // //fall back on Relative Path Resolver (searches data path then 
ClassLoader)
-      // URL relativeUrl;
-      // try
-      // {
-      // relativeUrl = new URL(aKey);
-      // }
-      // catch(MalformedURLException e)
-      // {
-      // relativeUrl = new URL("file","",aKey);
-      // }
-      // return getRelativePathResolver().resolveRelativePath(relativeUrl);
-    }
-    // }
-    // catch(MalformedURLException e)
-    // {
-    // throw new ResourceAccessException(e);
-    // }
+    return getResourceAsStreamCommonUrl(getResource(aKey, aParams));
   }
 
   /*
@@ -399,34 +400,7 @@ public class ResourceManager_impl implem
    * @see 
org.apache.uima.resource.ResourceManager#getResourceURL(java.lang.String)
    */
   public URL getResourceURL(String aKey) throws ResourceAccessException {
-    // try
-    // {
-    // see if this resource is registered in the ResourceManager
-    Object r = getResource(aKey);
-    // if so, and if it is a DataResource, use its URL
-    if (r != null && r instanceof DataResource) {
-      return ((DataResource) r).getUrl();
-    } else {
-      return null;
-      // //fall back on Relative Path Resolver (searches data path then 
ClassLoader)
-      // // String keyNoContext = stripContext(aKey); Stripping to last / 
doesn't work - also strips
-      // part of path!!!
-      // URL relativeUrl;
-      // try
-      // {
-      // relativeUrl = new URL(aKey);//keyNoContext);
-      // }
-      // catch(MalformedURLException e)
-      // {
-      // relativeUrl = new URL("file","",aKey);//keyNoContext);
-      // }
-      // return getRelativePathResolver().resolveRelativePath(relativeUrl);
-    }
-    // }
-    // catch(MalformedURLException e)
-    // {
-    // throw new ResourceAccessException(e);
-    // }
+    return getResourceAsStreamCommonUrl(getResource(aKey));
   }
 
   /*
@@ -479,9 +453,9 @@ public class ResourceManager_impl implem
       }
       mResourceMap.put(aQualifiedContextName + bindings[i].getKey(), 
registration.resource);
       // record the link from key to resource class (for parameterized 
resources only)
+      Class<?> impl = 
mInternalParameterizedResourceImplClassMap.get(bindings[i].getResourceName()); 
       mParameterizedResourceImplClassMap.put(aQualifiedContextName + 
bindings[i].getKey(),
-              
mInternalParameterizedResourceImplClassMap.get(bindings[i].getResourceName()));
-
+                                             (impl == null) ? 
EMPTY_RESOURCE_CLASS : impl);
     }
   }
 
@@ -626,7 +600,7 @@ public class ResourceManager_impl implem
     else if (r instanceof ParameterizedDataResource) {
       // we can't load the SharedResourceObject now, but we need to remember
       // which class it is for later when we get a request with parameters
-      mInternalParameterizedResourceImplClassMap.put(aName, implClass);
+      mInternalParameterizedResourceImplClassMap.put(aName, (null == 
implClass) ? EMPTY_RESOURCE_CLASS : implClass);
     } else
     // it is some other type of Resource
     {
@@ -651,7 +625,7 @@ public class ResourceManager_impl implem
    * @see org.apache.uima.resource.ResourceManager#getCasManager()
    */
   public CasManager getCasManager() {
-    synchronized(this) {
+    synchronized(casManagerMonitor) {
       if (mCasManager == null) {
         mCasManager = new CasManager_impl(this);
       }
@@ -659,13 +633,11 @@ public class ResourceManager_impl implem
     }
   }
   
-  
-
   /* (non-Javadoc)
    * @see 
org.apache.uima.resource.ResourceManager#setCasManager(org.apache.uima.resource.CasManager)
    */
   public void setCasManager(CasManager aCasManager) {
-    synchronized(this) {
+    synchronized(casManagerMonitor) {
       if (mCasManager == null) {
         mCasManager = aCasManager;
       }
@@ -699,4 +671,5 @@ public class ResourceManager_impl implem
   public Map<String, XMLizable> getImportCache() {
     return importCache;
   }
+
 }


Reply via email to