You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2008/09/08 04:25:12 UTC
svn commit: r692984 - in /tapestry/tapestry5/trunk: support/
tapestry-core/src/main/java/org/apache/tapestry5/internal/services/
tapestry-core/src/test/conf/
tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/
tapestry-ioc/src/main/java/org/a...
Author: hlship
Date: Sun Sep 7 19:25:11 2008
New Revision: 692984
URL: http://svn.apache.org/viewvc?rev=692984&view=rev
Log:
TAPESTRY-2561: Rapidly refreshing a page, even the same page, can cause a deadlock related to class loading
Added:
tapestry/tapestry5/trunk/support/heavy-load.jmx
Removed:
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/InternalConstants.java
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSourceImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/test/conf/testng.xml
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CtClassSourceImpl.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
Added: tapestry/tapestry5/trunk/support/heavy-load.jmx
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/support/heavy-load.jmx?rev=692984&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/support/heavy-load.jmx (added)
+++ tapestry/tapestry5/trunk/support/heavy-load.jmx Sun Sep 7 19:25:11 2008
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jmeterTestPlan version="1.2" properties="2.1">
+ <hashTree>
+ <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
+ <stringProp name="TestPlan.comments"></stringProp>
+ <boolProp name="TestPlan.functional_mode">false</boolProp>
+ <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
+ <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+ <collectionProp name="Arguments.arguments"/>
+ </elementProp>
+ <stringProp name="TestPlan.user_define_classpath"></stringProp>
+ </TestPlan>
+ <hashTree>
+ <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
+ <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
+ <boolProp name="LoopController.continue_forever">false</boolProp>
+ <stringProp name="LoopController.loops">5</stringProp>
+ </elementProp>
+ <stringProp name="ThreadGroup.num_threads">20</stringProp>
+ <stringProp name="ThreadGroup.ramp_time">0</stringProp>
+ <longProp name="ThreadGroup.start_time">1220812823000</longProp>
+ <longProp name="ThreadGroup.end_time">1220812823000</longProp>
+ <boolProp name="ThreadGroup.scheduler">false</boolProp>
+ <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
+ <stringProp name="ThreadGroup.duration"></stringProp>
+ <stringProp name="ThreadGroup.delay"></stringProp>
+ </ThreadGroup>
+ <hashTree>
+ <ConfigTestElement guiclass="HttpDefaultsGui" testclass="ConfigTestElement" testname="HTTP Request Defaults" enabled="true">
+ <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+ <collectionProp name="Arguments.arguments"/>
+ </elementProp>
+ <stringProp name="HTTPSampler.domain">localhost</stringProp>
+ <stringProp name="HTTPSampler.port">8080</stringProp>
+ <stringProp name="HTTPSampler.protocol">http</stringProp>
+ <stringProp name="HTTPSampler.contentEncoding"></stringProp>
+ <stringProp name="HTTPSampler.path">/</stringProp>
+ <boolProp name="HTTPSampler.image_parser">true</boolProp>
+ </ConfigTestElement>
+ <hashTree/>
+ <CookieManager guiclass="CookiePanel" testclass="CookieManager" testname="HTTP Cookie Manager" enabled="true">
+ <collectionProp name="CookieManager.cookies"/>
+ <boolProp name="CookieManager.clearEachIteration">true</boolProp>
+ <stringProp name="CookieManager.policy">rfc2109</stringProp>
+ </CookieManager>
+ <hashTree/>
+ <HTTPSampler guiclass="HttpTestSampleGui" testclass="HTTPSampler" testname="HTTP Request" enabled="true">
+ <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+ <collectionProp name="Arguments.arguments"/>
+ </elementProp>
+ <stringProp name="HTTPSampler.domain">localhost</stringProp>
+ <stringProp name="HTTPSampler.port">8080</stringProp>
+ <stringProp name="HTTPSampler.protocol">http</stringProp>
+ <stringProp name="HTTPSampler.contentEncoding"></stringProp>
+ <stringProp name="HTTPSampler.path">/</stringProp>
+ <stringProp name="HTTPSampler.method">GET</stringProp>
+ <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
+ <boolProp name="HTTPSampler.auto_redirects">true</boolProp>
+ <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+ <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
+ <stringProp name="HTTPSampler.FILE_NAME"></stringProp>
+ <stringProp name="HTTPSampler.FILE_FIELD"></stringProp>
+ <stringProp name="HTTPSampler.mimetype"></stringProp>
+ <boolProp name="HTTPSampler.image_parser">true</boolProp>
+ <stringProp name="HTTPSampler.monitor">false</stringProp>
+ <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
+ </HTTPSampler>
+ <hashTree/>
+ <HTTPSampler guiclass="HttpTestSampleGui" testclass="HTTPSampler" testname="HTTP Request" enabled="true">
+ <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+ <collectionProp name="Arguments.arguments"/>
+ </elementProp>
+ <stringProp name="HTTPSampler.domain"></stringProp>
+ <stringProp name="HTTPSampler.port"></stringProp>
+ <stringProp name="HTTPSampler.protocol"></stringProp>
+ <stringProp name="HTTPSampler.contentEncoding"></stringProp>
+ <stringProp name="HTTPSampler.path">/ValidBeanEditorDemo</stringProp>
+ <stringProp name="HTTPSampler.method">GET</stringProp>
+ <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
+ <boolProp name="HTTPSampler.auto_redirects">true</boolProp>
+ <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+ <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
+ <stringProp name="HTTPSampler.FILE_NAME"></stringProp>
+ <stringProp name="HTTPSampler.FILE_FIELD"></stringProp>
+ <stringProp name="HTTPSampler.mimetype"></stringProp>
+ <stringProp name="HTTPSampler.monitor">false</stringProp>
+ <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
+ </HTTPSampler>
+ <hashTree/>
+ <HTTPSampler guiclass="HttpTestSampleGui" testclass="HTTPSampler" testname="HTTP Request" enabled="true">
+ <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+ <collectionProp name="Arguments.arguments"/>
+ </elementProp>
+ <stringProp name="HTTPSampler.domain"></stringProp>
+ <stringProp name="HTTPSampler.port"></stringProp>
+ <stringProp name="HTTPSampler.protocol"></stringProp>
+ <stringProp name="HTTPSampler.contentEncoding"></stringProp>
+ <stringProp name="HTTPSampler.path">/griddemo</stringProp>
+ <stringProp name="HTTPSampler.method">GET</stringProp>
+ <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
+ <boolProp name="HTTPSampler.auto_redirects">true</boolProp>
+ <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+ <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
+ <stringProp name="HTTPSampler.FILE_NAME"></stringProp>
+ <stringProp name="HTTPSampler.FILE_FIELD"></stringProp>
+ <stringProp name="HTTPSampler.mimetype"></stringProp>
+ <stringProp name="HTTPSampler.monitor">false</stringProp>
+ <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
+ </HTTPSampler>
+ <hashTree/>
+ <ResultCollector guiclass="GraphVisualizer" testclass="ResultCollector" testname="Graph Results" enabled="true">
+ <boolProp name="ResultCollector.error_logging">false</boolProp>
+ <objProp>
+ <name>saveConfig</name>
+ <value class="SampleSaveConfiguration">
+ <time>true</time>
+ <latency>true</latency>
+ <timestamp>true</timestamp>
+ <success>true</success>
+ <label>true</label>
+ <code>true</code>
+ <message>true</message>
+ <threadName>true</threadName>
+ <dataType>true</dataType>
+ <encoding>false</encoding>
+ <assertions>true</assertions>
+ <subresults>true</subresults>
+ <responseData>false</responseData>
+ <samplerData>false</samplerData>
+ <xml>true</xml>
+ <fieldNames>false</fieldNames>
+ <responseHeaders>false</responseHeaders>
+ <requestHeaders>false</requestHeaders>
+ <responseDataOnError>false</responseDataOnError>
+ <saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
+ <assertionsResultsToSave>0</assertionsResultsToSave>
+ <bytes>true</bytes>
+ </value>
+ </objProp>
+ <stringProp name="filename"></stringProp>
+ </ResultCollector>
+ <hashTree/>
+ <ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="Aggregate Report" enabled="true">
+ <boolProp name="ResultCollector.error_logging">false</boolProp>
+ <objProp>
+ <name>saveConfig</name>
+ <value class="SampleSaveConfiguration">
+ <time>true</time>
+ <latency>true</latency>
+ <timestamp>true</timestamp>
+ <success>true</success>
+ <label>true</label>
+ <code>true</code>
+ <message>true</message>
+ <threadName>true</threadName>
+ <dataType>true</dataType>
+ <encoding>false</encoding>
+ <assertions>true</assertions>
+ <subresults>true</subresults>
+ <responseData>false</responseData>
+ <samplerData>false</samplerData>
+ <xml>true</xml>
+ <fieldNames>false</fieldNames>
+ <responseHeaders>false</responseHeaders>
+ <requestHeaders>false</requestHeaders>
+ <responseDataOnError>false</responseDataOnError>
+ <saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
+ <assertionsResultsToSave>0</assertionsResultsToSave>
+ <bytes>true</bytes>
+ </value>
+ </objProp>
+ <stringProp name="filename"></stringProp>
+ </ResultCollector>
+ <hashTree/>
+ </hashTree>
+ </hashTree>
+ </hashTree>
+</jmeterTestPlan>
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSourceImpl.java?rev=692984&r1=692983&r2=692984&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSourceImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSourceImpl.java Sun Sep 7 19:25:11 2008
@@ -18,7 +18,6 @@
import org.apache.tapestry5.internal.event.InvalidationEventHubImpl;
import org.apache.tapestry5.internal.events.UpdateListener;
import org.apache.tapestry5.internal.util.URLChangeTracker;
-import org.apache.tapestry5.ioc.internal.InternalConstants;
import org.apache.tapestry5.ioc.internal.services.ClassFactoryClassPool;
import org.apache.tapestry5.ioc.internal.services.ClassFactoryImpl;
import org.apache.tapestry5.ioc.internal.services.CtClassSource;
@@ -73,6 +72,21 @@
super(parent, classPool);
}
+
+ /**
+ * Synchronizes on the parent class loader before continuing, which is necessary to prevent thread deadlocks. Any classes
+ * loaded, or transformed, by this class loader will do so with the parent (context) class loader locked.
+ * The required order is always that the context class loader be locked, then the child class loader. Painful.
+ */
+ @Override
+ protected Class loadClass(String name, boolean resolve) throws ClassFormatError, ClassNotFoundException
+ {
+ synchronized (getParent())
+ {
+ return super.loadClass(name, resolve);
+ }
+ }
+
/**
* Determines if the class name represents a component class from a controlled package. If so,
* super.findClass() will load it and transform it. Returns null if not in a controlled package, allowing the
@@ -100,7 +114,6 @@
return null;
}
-
}
public ComponentInstantiatorSourceImpl(Logger logger, ClassLoader parent, ComponentClassTransformer transformer,
@@ -160,7 +173,9 @@
classFactory = new ClassFactoryImpl(loader, classPool, classSource, logger);
}
- // This is called from well within a synchronized block.
+ // This is called from well within a synchronized block. The component layer class loader,
+ // and the context class loader, should each be locked.
+
public void onLoad(ClassPool pool, String classname) throws NotFoundException, CannotCompileException
{
logger.debug("BEGIN onLoad " + classname);
@@ -179,20 +194,17 @@
try
{
- synchronized (InternalConstants.GLOBAL_CLASS_CREATION_MUTEX)
- {
- CtClass ctClass = pool.get(classname);
+ CtClass ctClass = pool.get(classname);
- // Force the creation of the super-class before the target class.
+ // Force the creation of the super-class before the target class.
- forceSuperclassTransform(ctClass);
+ forceSuperclassTransform(ctClass);
- // Do the transformations here
+ // Do the transformations here
- transformer.transformComponentClass(ctClass, loader);
+ transformer.transformComponentClass(ctClass, loader);
- writeClassToFileSystemForHardCoreDebuggingPurposesOnly(ctClass);
- }
+ writeClassToFileSystemForHardCoreDebuggingPurposesOnly(ctClass);
diag = "END";
}
@@ -218,7 +230,6 @@
ctClass.writeFile(JAVASSIST_WRITE_DIR);
ctClass.defrost();
ctClass.stopPruning(p);
-
}
catch (Exception ex)
{
Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/conf/testng.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/conf/testng.xml?rev=692984&r1=692983&r2=692984&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/conf/testng.xml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/conf/testng.xml Sun Sep 7 19:25:11 2008
@@ -15,7 +15,9 @@
limitations under the License.
-->
-<suite name="Tapestry Core" thread-count="10" annotations="1.5" verbose="2" parallel="tests">
+<!-- The suite may no longer be run in parallel, because of some tricky issues related to locking of class loaders. Running in parallel causes thread deadlocks, when unmanaged
+tests run at the same time as Selenium-based integration tests. See TAPESTRY-2561. -->
+<suite name="Tapestry Core" annotations="1.5" verbose="2">
<test name="Integration Tests">
<packages>
<package name="org.apache.tapestry5.integration"/>
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java?rev=692984&r1=692983&r2=692984&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java Sun Sep 7 19:25:11 2008
@@ -20,9 +20,7 @@
import org.apache.tapestry5.ioc.def.ModuleDef;
import org.apache.tapestry5.ioc.def.ServiceDef;
import org.apache.tapestry5.ioc.internal.services.JustInTimeObjectCreator;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.Defense;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.*;
import org.apache.tapestry5.ioc.services.*;
import org.slf4j.Logger;
@@ -46,12 +44,11 @@
private final Logger logger;
- // Guarded by InternalConstants.GLOBAL_CLASS_CREATION_MUTEX
private Object moduleBuilder;
// Set to true when invoking the module constructor. Used to
// detect endless loops caused by irresponsible dependencies in
- // the constructor. Guarded by InternalConstants.GLOBAL_CLASS_CREATION_MUTEX.
+ // the constructor.
private boolean insideConstructor;
/**
@@ -59,6 +56,8 @@
*/
private final Map<String, Object> services = CollectionFactory.newCaseInsensitiveMap();
+ private final ConcurrentBarrier barrier = new ConcurrentBarrier();
+
public ModuleImpl(InternalRegistry registry, ServiceActivityTracker tracker, ModuleDef moduleDef,
ClassFactory classFactory, Logger logger)
{
@@ -135,47 +134,58 @@
/**
* Locates the service proxy for a particular service (from the service definition).
- * <p/>
- * Access is synchronized via {@link InternalConstants#GLOBAL_CLASS_CREATION_MUTEX}.
*
* @param def defines the service
* @param eagerLoadProxies collection into which proxies for eager loaded services are added (or null)
* @return the service proxy
*/
- private Object findOrCreate(ServiceDef def, Collection<EagerLoadServiceProxy> eagerLoadProxies)
+ private synchronized Object findOrCreate(final ServiceDef def,
+ final Collection<EagerLoadServiceProxy> eagerLoadProxies)
{
- synchronized (InternalConstants.GLOBAL_CLASS_CREATION_MUTEX)
+ final String key = def.getServiceId();
+
+ final Invokable create = new Invokable()
{
- String key = def.getServiceId();
+ public Object invoke()
+ {
+ Object result = create(def, eagerLoadProxies);
- Object result = services.get(key);
+ services.put(key, result);
- if (result == null)
+ return result;
+ }
+ };
+
+ Invokable find = new Invokable()
+ {
+ public Object invoke()
{
- result = create(def, eagerLoadProxies);
- services.put(key, result);
+ Object result = services.get(key);
+
+ if (result == null)
+ {
+ result = barrier.withWrite(create);
+ }
+
+ return result;
}
+ };
- return result;
- }
+ return barrier.withRead(find);
}
public void collectEagerLoadServices(Collection<EagerLoadServiceProxy> proxies)
{
- synchronized (InternalConstants.GLOBAL_CLASS_CREATION_MUTEX)
+ for (String serviceId : moduleDef.getServiceIds())
{
- for (String serviceId : moduleDef.getServiceIds())
- {
- ServiceDef def = moduleDef.getServiceDef(serviceId);
+ ServiceDef def = moduleDef.getServiceDef(serviceId);
- if (def.isEagerLoad()) findOrCreate(def, proxies);
- }
+ if (def.isEagerLoad()) findOrCreate(def, proxies);
}
}
/**
- * Creates the service and updates the cache of created services. Access is synchronized via {@link
- * InternalConstants#GLOBAL_CLASS_CREATION_MUTEX}.
+ * Creates the service and updates the cache of created services.
*
* @param eagerLoadProxies a list into which any eager loaded proxies should be added
*/
@@ -239,20 +249,30 @@
}
}
- public Object getModuleBuilder()
+ private final Runnable instantiateModuleBuilder = new Runnable()
+ {
+ public void run()
+ {
+ moduleBuilder = constructModuleBuilder();
+ }
+ };
+
+ private final Invokable provideModuleBuilder = new Invokable<Object>()
{
- synchronized (InternalConstants.GLOBAL_CLASS_CREATION_MUTEX)
+ public Object invoke()
{
- if (moduleBuilder == null) moduleBuilder = instantiateModuleBuilder();
+ if (moduleBuilder == null) barrier.withWrite(instantiateModuleBuilder);
return moduleBuilder;
}
+ };
+
+ public Object getModuleBuilder()
+ {
+ return barrier.withRead(provideModuleBuilder);
}
- /**
- * Access synchronized by MUTEX.
- */
- private Object instantiateModuleBuilder()
+ private Object constructModuleBuilder()
{
Class builderClass = moduleDef.getBuilderClass();
@@ -338,7 +358,7 @@
classFab.addField("creator", Modifier.PRIVATE | Modifier.FINAL, ObjectCreator.class);
classFab.addField("token", Modifier.PRIVATE | Modifier.FINAL, ServiceProxyToken.class);
- classFab.addConstructor(new Class[]{ObjectCreator.class, ServiceProxyToken.class}, null,
+ classFab.addConstructor(new Class[] {ObjectCreator.class, ServiceProxyToken.class}, null,
"{ creator = $1; token = $2; }");
// Make proxies serializable by writing the token to the stream.
@@ -348,7 +368,7 @@
// This is the "magic" signature that allows an object to substitute some other
// object for itself.
MethodSignature writeReplaceSig = new MethodSignature(Object.class, "writeReplace", null,
- new Class[]{ObjectStreamException.class});
+ new Class[] {ObjectStreamException.class});
classFab.addMethod(Modifier.PRIVATE, writeReplaceSig, "return token;");
@@ -397,5 +417,4 @@
{
return moduleDef.getLoggerName();
}
-
}
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CtClassSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CtClassSourceImpl.java?rev=692984&r1=692983&r2=692984&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CtClassSourceImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CtClassSourceImpl.java Sun Sep 7 19:25:11 2008
@@ -16,7 +16,6 @@
import javassist.CtClass;
import javassist.NotFoundException;
-import org.apache.tapestry5.ioc.internal.InternalConstants;
import org.apache.tapestry5.ioc.services.ClassFabUtils;
import java.security.ProtectionDomain;
@@ -49,7 +48,7 @@
this.loader = loader;
}
- public CtClass toCtClass(Class searchClass)
+ public synchronized CtClass toCtClass(Class searchClass)
{
ClassLoader loader = searchClass.getClassLoader();
@@ -75,7 +74,7 @@
}
}
- public synchronized CtClass newClass(String name, Class superClass)
+ public CtClass newClass(String name, Class superClass)
{
CtClass ctSuperClass = toCtClass(superClass);
@@ -84,17 +83,20 @@
private static final String WRITE_DIR = System.getProperty("javassist-write-dir");
- public synchronized Class createClass(CtClass ctClass)
+ public Class createClass(CtClass ctClass)
{
if (WRITE_DIR != null) writeClass(ctClass);
- synchronized (InternalConstants.GLOBAL_CLASS_CREATION_MUTEX)
+ synchronized (loader)
{
try
{
Class result = pool.toClass(ctClass, loader, domain);
- createdClassCount++;
+ synchronized (this)
+ {
+ createdClassCount++;
+ }
return result;
}
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java?rev=692984&r1=692983&r2=692984&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java Sun Sep 7 19:25:11 2008
@@ -14,7 +14,6 @@
package org.apache.tapestry5.ioc.internal.services;
-import org.apache.tapestry5.ioc.internal.InternalConstants;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
import org.apache.tapestry5.ioc.services.PropertyAccess;
@@ -75,15 +74,13 @@
* serializes access to the Java Beans Introspector, which is not thread safe. In addition, handles the case where
* the class in question is an interface, accumulating properties inherited from super-classes.
*/
- private ClassPropertyAdapter buildAdapter(Class forClass)
+ private synchronized ClassPropertyAdapter buildAdapter(Class forClass)
{
// In some race conditions, we may hit this method for the same class multiple times.
// We just let it happen, replacing the old ClassPropertyAdapter with a new one.
try
{
- synchronized (InternalConstants.GLOBAL_CLASS_CREATION_MUTEX)
- {
BeanInfo info = Introspector.getBeanInfo(forClass);
List<PropertyDescriptor> descriptors = CollectionFactory.newList();
@@ -93,7 +90,6 @@
if (forClass.isInterface()) addPropertiesFromExtendedInterfaces(forClass, descriptors);
return new ClassPropertyAdapterImpl(forClass, descriptors);
- }
}
catch (Throwable ex)
{