You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2010/10/19 09:34:25 UTC

svn commit: r1024145 - /sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/ScriptEngineManagerFactory.java

Author: cziegeler
Date: Tue Oct 19 07:34:25 2010
New Revision: 1024145

URL: http://svn.apache.org/viewvc?rev=1024145&view=rev
Log:
SLING-1545 : ScripteEngineManagerFactory is not thread safe

Modified:
    sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/ScriptEngineManagerFactory.java

Modified: sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/ScriptEngineManagerFactory.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/ScriptEngineManagerFactory.java?rev=1024145&r1=1024144&r2=1024145&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/ScriptEngineManagerFactory.java (original)
+++ sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/ScriptEngineManagerFactory.java Tue Oct 19 07:34:25 2010
@@ -23,9 +23,10 @@ import java.io.InputStreamReader;
 import java.net.URL;
 import java.util.Collection;
 import java.util.Dictionary;
+import java.util.HashSet;
 import java.util.Hashtable;
-import java.util.LinkedList;
 import java.util.List;
+import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
@@ -68,15 +69,23 @@ public class ScriptEngineManagerFactory 
      */
     private ServiceTracker eventAdminTracker;
 
-    private ScriptEngineManager scriptEngineManager;
+    private volatile ScriptEngineManager scriptEngineManager;
 
-    private List<Bundle> engineSpiBundles = new LinkedList<Bundle>();
+    private final Set<Bundle> engineSpiBundles = new HashSet<Bundle>();
 
-    private List<ScriptEngineFactory> engineSpiServices = new LinkedList<ScriptEngineFactory>();
+    private final Set<ScriptEngineFactory> engineSpiServices = new HashSet<ScriptEngineFactory>();
 
     private ServiceRegistration scriptEngineManagerRegistration;
 
-    private void refreshScriptEngineManager() {
+    /**
+     * Refresh the script engine manager.
+     * This method is called from within a synchronized block,
+     * no other sync is required!
+     */
+    private ScriptEngineManager refreshScriptEngineManager() {
+        if ( this.scriptEngineManager != null ) {
+            return this.scriptEngineManager;
+        }
 
         if (scriptEngineManagerRegistration != null) {
             scriptEngineManagerRegistration.unregister();
@@ -84,17 +93,17 @@ public class ScriptEngineManagerFactory 
         }
 
         // create (empty) script engine manager
-        ClassLoader loader = getClass().getClassLoader();
-        SlingScriptEngineManager tmp = new SlingScriptEngineManager(loader);
+        final ClassLoader loader = getClass().getClassLoader();
+        final SlingScriptEngineManager tmp = new SlingScriptEngineManager(loader);
 
         // register script engines from bundles
         final SortedSet<Object> extensions = new TreeSet<Object>();
-        for (Bundle bundle : engineSpiBundles) {
+        for (final Bundle bundle : this.engineSpiBundles) {
             extensions.addAll(registerFactories(tmp, bundle));
         }
 
         // register script engines from registered services
-        for (ScriptEngineFactory factory : engineSpiServices) {
+        for (final ScriptEngineFactory factory : this.engineSpiServices) {
             extensions.addAll(registerFactory(tmp, factory));
         }
 
@@ -120,10 +129,11 @@ public class ScriptEngineManagerFactory 
                 }
             }
         }
+        return tmp;
     }
 
     @SuppressWarnings("unchecked")
-    private Collection<?> registerFactories(SlingScriptEngineManager mgr, Bundle bundle) {
+    private Collection<?> registerFactories(final SlingScriptEngineManager mgr, final Bundle bundle) {
         URL url = bundle.getEntry(ENGINE_FACTORY_SERVICE);
         InputStream ins = null;
         final SortedSet<String> extensions = new TreeSet<String>();
@@ -142,6 +152,7 @@ public class ScriptEngineManagerFactory 
                 }
             }
         } catch (IOException ioe) {
+            // ignore
         } finally {
             if (ins != null) {
                 try {
@@ -154,7 +165,7 @@ public class ScriptEngineManagerFactory 
         return extensions;
     }
 
-    private Collection<?> registerFactory(SlingScriptEngineManager mgr, ScriptEngineFactory factory) {
+    private Collection<?> registerFactory(final SlingScriptEngineManager mgr, final ScriptEngineFactory factory) {
         log.info("Adding ScriptEngine {}, {} for language {}, {}", new Object[] { factory.getEngineName(), factory.getEngineVersion(),
                 factory.getLanguageName(), factory.getLanguageVersion() });
 
@@ -168,13 +179,17 @@ public class ScriptEngineManagerFactory 
     public void bundleChanged(BundleEvent event) {
         if (event.getType() == BundleEvent.STARTED && event.getBundle().getEntry(ENGINE_FACTORY_SERVICE) != null) {
 
-            engineSpiBundles.add(event.getBundle());
-            refreshScriptEngineManager();
-
-        } else if (event.getType() == BundleEvent.STOPPED && engineSpiBundles.remove(event.getBundle())) {
-
-            refreshScriptEngineManager();
+            synchronized ( this ) {
+                this.engineSpiBundles.add(event.getBundle());
+                this.scriptEngineManager = null;
+            }
 
+        } else if (event.getType() == BundleEvent.STOPPED  ) {
+            synchronized ( this ) {
+                if ( this.engineSpiBundles.remove(event.getBundle()) ) {
+                    this.scriptEngineManager = null;
+                }
+            }
         }
     }
 
@@ -187,20 +202,23 @@ public class ScriptEngineManagerFactory 
         this.eventAdminTracker = new ServiceTracker(this.bundleContext, EventAdmin.class.getName(), null);
         this.eventAdminTracker.open();
 
-
-
         this.bundleContext.addBundleListener(this);
 
         Bundle[] bundles = this.bundleContext.getBundles();
         for (Bundle bundle : bundles) {
             if (bundle.getState() == Bundle.ACTIVE && bundle.getEntry(ENGINE_FACTORY_SERVICE) != null) {
-                engineSpiBundles.add(bundle);
+                synchronized ( this ) {
+                    this.engineSpiBundles.add(bundle);
+                    this.scriptEngineManager = null;
+                }
             }
         }
 
+        // create a script engine manager
+        synchronized ( this ) {
+            this.refreshScriptEngineManager();
+        }
         org.apache.sling.scripting.core.impl.ScriptEngineConsolePlugin.initPlugin(context.getBundleContext(), this);
-
-        refreshScriptEngineManager();
     }
 
     protected void deactivate(ComponentContext context) {
@@ -212,8 +230,10 @@ public class ScriptEngineManagerFactory 
             scriptEngineManagerRegistration.unregister();
             scriptEngineManagerRegistration = null;
         }
-        engineSpiBundles.clear();
-        engineSpiServices.clear();
+        synchronized ( this ) {
+            this.engineSpiBundles.clear();
+            this.engineSpiServices.clear();
+        }
         scriptEngineManager = null;
         if (this.eventAdminTracker != null) {
             this.eventAdminTracker.close();
@@ -225,15 +245,20 @@ public class ScriptEngineManagerFactory 
 
 
     protected void bindScriptEngineFactory(ScriptEngineFactory scriptEngineFactory) {
-        engineSpiServices.add(scriptEngineFactory);
-        refreshScriptEngineManager();
+        synchronized ( this ) {
+            this.engineSpiServices.add(scriptEngineFactory);
+            this.scriptEngineManager = null;
+        }
         // send event
         postEvent(SlingScriptConstants.TOPIC_SCRIPT_ENGINE_FACTORY_ADDED, scriptEngineFactory);
     }
 
     protected void unbindScriptEngineFactory(ScriptEngineFactory scriptEngineFactory) {
-        engineSpiServices.remove(scriptEngineFactory);
-        refreshScriptEngineManager();
+        synchronized ( this ) {
+            if ( this.engineSpiServices.remove(scriptEngineFactory) ) {
+                this.scriptEngineManager = null;
+            }
+        }
         // send event
         postEvent(SlingScriptConstants.TOPIC_SCRIPT_ENGINE_FACTORY_REMOVED, scriptEngineFactory);
     }
@@ -251,6 +276,9 @@ public class ScriptEngineManagerFactory 
         return list.toArray(new String[list.size()]);
     }
 
+    /**
+     * Post a notification with the EventAdmin
+     */
     private void postEvent(final String topic, final ScriptEngineFactory scriptEngineFactory) {
         final EventAdmin localEA = this.getEventAdmin();
         if (localEA != null) {
@@ -265,10 +293,17 @@ public class ScriptEngineManagerFactory 
         }
     }
 
-
+    /**
+     * Get the script engine manager.
+     * Refresh the manager if changes occured.
+     */
     ScriptEngineManager getScriptEngineManager() {
-        return scriptEngineManager;
+        ScriptEngineManager sem = this.scriptEngineManager;
+        if ( sem == null ) {
+            synchronized ( this ) {
+                sem = this.refreshScriptEngineManager();
+            }
+        }
+        return sem;
     }
-
-
 }