From do-not-reply at jboss.org Tue May 4 13:28:48 2010 Content-Type: multipart/mixed; boundary="===============7859771698741546994==" 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> --===============7859771698741546994== 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 --===============7859771698741546994==--