From do-not-reply at jboss.org Tue May 4 13:28:48 2010
Content-Type: multipart/mixed; boundary="===============3747534853708321289=="
MIME-Version: 1.0
From: do-not-reply at jboss.org
To: exo-jcr-commits at lists.jboss.org
Subject: [exo-jcr-commits] exo-jcr SVN: r2348 - in
kernel/trunk/exo.kernel.container/src:
main/java/org/exoplatform/container/jmx and 2 other directories.
Date: Tue, 04 May 2010 13:28:48 -0400
Message-ID: <201005041728.o44HSm5f004986@svn01.web.mwc.hst.phx2.redhat.com>
--===============3747534853708321289==
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Author: nfilotto
Date: 2010-05-04 13:28:47 -0400 (Tue, 04 May 2010)
New Revision: 2348
Added:
kernel/trunk/exo.kernel.container/src/test/java/org/exoplatform/containe=
r/TestExoContainer.java
kernel/trunk/exo.kernel.container/src/test/resources/org/exoplatform/con=
tainer/test-exo-container.xml
Modified:
kernel/trunk/exo.kernel.container/src/main/java/org/exoplatform/containe=
r/CachingContainer.java
kernel/trunk/exo.kernel.container/src/main/java/org/exoplatform/containe=
r/jmx/MX4JComponentAdapter.java
Log:
EXOJCR-712: =
1. CachingContainer: Make all the write methods Thread Safe to prevent race=
conditions and thread safety issues
2. MX4JComponentAdapter: Ensure that only one instance is created per adapt=
er
Modified: kernel/trunk/exo.kernel.container/src/main/java/org/exoplatform/c=
ontainer/CachingContainer.java
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- kernel/trunk/exo.kernel.container/src/main/java/org/exoplatform/contain=
er/CachingContainer.java 2010-04-30 18:16:15 UTC (rev 2347)
+++ kernel/trunk/exo.kernel.container/src/main/java/org/exoplatform/contain=
er/CachingContainer.java 2010-05-04 17:28:47 UTC (rev 2348)
@@ -37,9 +37,15 @@
* @author Julien Viet
* @version $Revision$
*/
+(a)SuppressWarnings("unchecked")
public class CachingContainer extends MCIntegrationContainer
{
=
+ /**
+ * Serial Version UID
+ */
+ private static final long serialVersionUID =3D 316388590860241305L;
+
private final ConcurrentMap adapterByType =3D
new ConcurrentHashMap();
=
@@ -171,67 +177,67 @@
=
//
=
- public ComponentAdapter registerComponent(ComponentAdapter componentAda=
pter)
+ public synchronized ComponentAdapter registerComponent(ComponentAdapter=
componentAdapter)
throws DuplicateComponentKeyRegistrationException
{
invalidate();
return super.registerComponent(componentAdapter);
}
=
- public ComponentAdapter unregisterComponent(Object componentKey)
+ public synchronized ComponentAdapter unregisterComponent(Object compone=
ntKey)
{
invalidate();
return super.unregisterComponent(componentKey);
}
=
- public ComponentAdapter registerComponentInstance(Object component) thr=
ows PicoRegistrationException
+ public synchronized ComponentAdapter registerComponentInstance(Object c=
omponent) throws PicoRegistrationException
{
invalidate();
return super.registerComponentInstance(component);
}
=
- public ComponentAdapter registerComponentInstance(Object componentKey, =
Object componentInstance)
+ public synchronized ComponentAdapter registerComponentInstance(Object c=
omponentKey, Object componentInstance)
throws PicoRegistrationException
{
invalidate();
return super.registerComponentInstance(componentKey, componentInstan=
ce);
}
=
- public ComponentAdapter registerComponentImplementation(Class component=
Implementation)
+ public synchronized ComponentAdapter registerComponentImplementation(Cl=
ass componentImplementation)
throws PicoRegistrationException
{
invalidate();
return super.registerComponentImplementation(componentImplementation=
);
}
=
- public ComponentAdapter registerComponentImplementation(Object componen=
tKey, Class componentImplementation)
+ public synchronized ComponentAdapter registerComponentImplementation(Ob=
ject componentKey, Class componentImplementation)
throws PicoRegistrationException
{
invalidate();
return super.registerComponentImplementation(componentKey, component=
Implementation);
}
=
- public ComponentAdapter registerComponentImplementation(Object componen=
tKey, Class componentImplementation,
+ public synchronized ComponentAdapter registerComponentImplementation(Ob=
ject componentKey, Class componentImplementation,
Parameter[] parameters) throws PicoRegistrationException
{
invalidate();
return super.registerComponentImplementation(componentKey, component=
Implementation, parameters);
}
=
- public ComponentAdapter registerComponentImplementation(Object componen=
tKey, Class componentImplementation,
+ public synchronized ComponentAdapter registerComponentImplementation(Ob=
ject componentKey, Class componentImplementation,
List parameters) throws PicoRegistrationException
{
invalidate();
return super.registerComponentImplementation(componentKey, component=
Implementation, parameters);
}
=
- public boolean addChildContainer(PicoContainer child)
+ public synchronized boolean addChildContainer(PicoContainer child)
{
invalidate();
return super.addChildContainer(child);
}
=
- public boolean removeChildContainer(PicoContainer child)
+ public synchronized boolean removeChildContainer(PicoContainer child)
{
invalidate();
return super.removeChildContainer(child);
Modified: kernel/trunk/exo.kernel.container/src/main/java/org/exoplatform/c=
ontainer/jmx/MX4JComponentAdapter.java
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- kernel/trunk/exo.kernel.container/src/main/java/org/exoplatform/contain=
er/jmx/MX4JComponentAdapter.java 2010-04-30 18:16:15 UTC (rev 2347)
+++ kernel/trunk/exo.kernel.container/src/main/java/org/exoplatform/contain=
er/jmx/MX4JComponentAdapter.java 2010-05-04 17:28:47 UTC (rev 2348)
@@ -42,10 +42,16 @@
* @author Benjamin Mestrallet
* @version $Revision: 1.5 $
*/
+(a)SuppressWarnings("unchecked")
public class MX4JComponentAdapter extends AbstractComponentAdapter
{
- private Object instance_;
+ /**
+ * Serial Version ID
+ */
+ private static final long serialVersionUID =3D -9001193588034229411L;
=
+ private volatile Object instance_;
+
private Log log =3D ExoLogger.getLogger("exo.kernel.container.MX4JCompo=
nentAdapter");
=
public MX4JComponentAdapter(Object key, Class implementation)
@@ -58,31 +64,38 @@
if (instance_ !=3D null)
return instance_;
=
- // Get the component
+ //
ExoContainer exocontainer =3D (ExoContainer)container;
- Object key =3D getComponentKey();
+ Component component =3D null;
+ ConfigurationManager manager;
String componentKey;
- if (key instanceof String)
- componentKey =3D (String)key;
- else
- componentKey =3D ((Class)key).getName();
- ConfigurationManager manager =3D
- (ConfigurationManager)exocontainer.getComponentInstanceOfType(Con=
figurationManager.class);
- Component component =3D manager.getComponent(componentKey);
-
- //
try
{
InitParams params =3D null;
boolean debug =3D false;
- if (component !=3D null)
+ synchronized (this)
{
- params =3D component.getInitParams();
- debug =3D component.getShowDeployInfo();
+ // Avoid to create duplicate instances if it is called at the =
same time by several threads
+ if (instance_ !=3D null)
+ return instance_;
+ // Get the component
+ Object key =3D getComponentKey();
+ if (key instanceof String)
+ componentKey =3D (String)key;
+ else
+ componentKey =3D ((Class)key).getName();
+ manager =3D (ConfigurationManager)exocontainer.getComponentIns=
tanceOfType(ConfigurationManager.class);
+ component =3D manager.getComponent(componentKey);
+ if (component !=3D null)
+ {
+ params =3D component.getInitParams();
+ debug =3D component.getShowDeployInfo();
+ }
+ // Please note that we cannot fully initialize the Object "ins=
tance_" before releasing other
+ // threads because it could cause StackOverflowError due to re=
cursive calls
+ instance_ =3D exocontainer.createComponent(getComponentImpleme=
ntation(), params);
}
=
- instance_ =3D exocontainer.createComponent(getComponentImplementa=
tion(), params);
-
if (debug)
log.debug("=3D=3D> create component : " + instance_);
if (component !=3D null && component.getComponentPlugins() !=3D n=
ull)
@@ -112,6 +125,7 @@
}
throw new RuntimeException(msg, ex);
}
+
return instance_;
}
=
Added: kernel/trunk/exo.kernel.container/src/test/java/org/exoplatform/cont=
ainer/TestExoContainer.java
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- kernel/trunk/exo.kernel.container/src/test/java/org/exoplatform/contain=
er/TestExoContainer.java (rev 0)
+++ kernel/trunk/exo.kernel.container/src/test/java/org/exoplatform/contain=
er/TestExoContainer.java 2010-05-04 17:28:47 UTC (rev 2348)
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2003-2010 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see<http://www.gnu.org/licenses/>=
;.
+ */
+package org.exoplatform.container;
+
+import org.exoplatform.container.component.BaseComponentPlugin;
+import org.exoplatform.container.configuration.ConfigurationManager;
+import org.exoplatform.container.jmx.AbstractTestContainer;
+import org.picocontainer.ComponentAdapter;
+import org.picocontainer.PicoContainer;
+import org.picocontainer.PicoInitializationException;
+import org.picocontainer.PicoIntrospectionException;
+import org.picocontainer.PicoVisitor;
+import org.picocontainer.defaults.DuplicateComponentKeyRegistrationExcepti=
on;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto =
+ * nicolas.filotto(a)exoplatform.com
+ * 3 mai 2010 =
+ */
+public class TestExoContainer extends AbstractTestContainer
+{
+
+ public void testStackOverFlow()
+ {
+ final RootContainer container =3D createRootContainer("test-exo-cont=
ainer.xml");
+ MyClass value =3D (MyClass)container.getComponentInstanceOfType(MyCl=
ass.class);
+ assertNotNull(value);
+ MyClassPlugin plugin =3D value.plugin_;
+ assertNotNull(plugin);
+ assertNotNull(plugin.cmanager_);
+ assertEquals(value, plugin.myClass_);
+ }
+ =
+ public void testMultiThreading() throws Throwable
+ {
+ final RootContainer container =3D createRootContainer("test-exo-cont=
ainer.xml");
+ final AtomicReference currentMyClass =3D new AtomicRefere=
nce();
+ testMultiThreading(new Task()
+ {
+
+ public void execute()
+ {
+ MyMTClass value =3D (MyMTClass)container.getComponentInstance(=
MyMTClass.class);
+ synchronized (currentMyClass)
+ {
+ if (currentMyClass.get() =3D=3D null)
+ {
+ currentMyClass.set(value);
+ }
+ }
+ assertEquals(currentMyClass.get(), container.getComponentInsta=
nce(MyMTClass.class));
+ }
+ }); =
+ testMultiThreading(new Task()
+ {
+
+ public void execute()
+ {
+ MyMTClass value =3D (MyMTClass)container.getComponentInstanceO=
fType(MyMTClass.class);
+ synchronized (currentMyClass)
+ {
+ if (currentMyClass.get() =3D=3D null)
+ {
+ currentMyClass.set(value);
+ }
+ }
+ assertEquals(currentMyClass.get(), container.getComponentInsta=
nceOfType(MyMTClass.class));
+ }
+ });
+ final AtomicReference ar =3D new AtomicReference();
+ testMultiThreading(new Task()
+ {
+ public void execute()
+ {
+ try
+ {
+ ComponentAdapter ca =3D new ComponentAdapter()
+ {
+
+ public void accept(PicoVisitor paramPicoVisitor)
+ {
+ }
+
+ public Class getComponentImplementation()
+ {
+ return MyClass.class;
+ }
+
+ public Object getComponentInstance(PicoContainer paramPi=
coContainer)
+ throws PicoInitializationException, PicoIntrospection=
Exception
+ {
+ return new MyClass();
+ }
+
+ public Object getComponentKey()
+ {
+ return "a";
+ }
+
+ public void verify(PicoContainer paramPicoContainer) thr=
ows PicoIntrospectionException
+ {
+ }
+
+ };
+ ar.set(container.registerComponent(ca));
+ }
+ catch (DuplicateComponentKeyRegistrationException e)
+ {
+ // ignore expected behavior
+ }
+ }
+ });
+ testMultiThreading(new Task()
+ {
+
+ public void execute()
+ {
+ assertEquals(ar.get(), container.getComponentAdapter("a"));
+ }
+ });
+ testMultiThreading(new Task()
+ {
+
+ public void execute()
+ {
+ container.unregisterComponent("a");
+ }
+ });
+
+ }
+
+ private void testMultiThreading(final Task task) throws Throwable
+ {
+ int threads =3D 50;
+ final CountDownLatch startSignal =3D new CountDownLatch(1);
+ final CountDownLatch doneSignal =3D new CountDownLatch(threads);
+ final List errors =3D Collections.synchronizedList(new Ar=
rayList());
+ for (int i =3D 0; i < threads; i++)
+ {
+ Thread thread =3D new Thread()
+ {
+ public void run()
+ {
+ try
+ {
+ startSignal.await();
+ task.execute();
+ }
+ catch (Throwable e)
+ {
+ errors.add(e);
+ }
+ finally
+ {
+ doneSignal.countDown();
+ }
+ }
+ };
+ thread.start();
+ }
+ startSignal.countDown();
+ doneSignal.await();
+ if (!errors.isEmpty())
+ {
+ for (Throwable e : errors)
+ {
+ e.printStackTrace();
+ }
+ throw errors.get(0);
+ }
+ }
+
+ public interface Task
+ {
+ public void execute();
+ }
+ =
+ public static class MyMTClass
+ {
+ public MyMTClass() throws InterruptedException
+ {
+ // Make the thread wait to ensure that the thread safety issue is=
properly solved
+ Thread.sleep(10);
+ }
+ }
+
+ public static class MyClass
+ {
+ public MyClassPlugin plugin_;
+ public void add(MyClassPlugin plugin)
+ {
+ this.plugin_ =3D plugin;
+ }
+ }
+ =
+ public static class MyClassPlugin extends BaseComponentPlugin
+ {
+ public ConfigurationManager cmanager_;
+ public MyClass myClass_;
+ public MyClassPlugin(ConfigurationManager cmanager, MyClass myClass)
+ {
+ this.cmanager_ =3D cmanager;
+ this.myClass_ =3D myClass;
+ }
+ }
+}
\ No newline at end of file
Added: kernel/trunk/exo.kernel.container/src/test/resources/org/exoplatform=
/container/test-exo-container.xml
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- kernel/trunk/exo.kernel.container/src/test/resources/org/exoplatform/co=
ntainer/test-exo-container.xml (rev 0)
+++ kernel/trunk/exo.kernel.container/src/test/resources/org/exoplatform/co=
ntainer/test-exo-container.xml 2010-05-04 17:28:47 UTC (rev 2348)
@@ -0,0 +1,25 @@
+
+
+
+
+ org.exoplatform.container.TestExoContainer$MyMTClass
+
+
+ org.exoplatform.container.TestExoContainer$MyClass
+
+
+ stackoverflow-test-plugin
+ add
+ org.exoplatform.container.TestExoContainer$MyClassPlugin
+
+
+
+
\ No newline at end of file
--===============3747534853708321289==--