[ 
https://issues.apache.org/struts/browse/SHALE-390?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Gary VanMatre resolved SHALE-390.
---------------------------------

       Resolution: Fixed
    Fix Version/s: 1.1.0-SNAPSHOT
                   1.0.5-SNAPSHOT
         Assignee: Gary VanMatre

Thanks for doing such detail analysis.  The test case you provided allowed me 
to easily recreate the problem.  I applied the changes you suggested which 
seemed to fix the problem.

This fix will be in the 20070225 nightly build.

> NPE in ComponentConfigBean$WatchDog.isDirty
> -------------------------------------------
>
>                 Key: SHALE-390
>                 URL: https://issues.apache.org/struts/browse/SHALE-390
>             Project: Shale
>          Issue Type: Bug
>          Components: Clay
>    Affects Versions: 1.1.0-SNAPSHOT
>         Environment: Debian 3.1 and Windows XP Prof.
> Tomcat 5.5.20
>            Reporter: Martin Bergljung
>         Assigned To: Gary VanMatre
>             Fix For: 1.0.5-SNAPSHOT, 1.1.0-SNAPSHOT
>
>
> 2007-01-10 01:34:03,996 ERROR 
> [org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/scn].[faces]]
>  Servlet.service() for servlet faces threw exception
> java.lang.NullPointerException
>         at 
> org.apache.shale.clay.config.beans.ComponentConfigBean$WatchDog.isDirty(ComponentConfigBean.java:1248)
>         at 
> org.apache.shale.clay.config.beans.ComponentConfigBean$WatchDog.refresh(ComponentConfigBean.java:1276)
>         at 
> org.apache.shale.clay.config.beans.TemplateConfigBean.getElement(TemplateConfigBean.java:79)
>         at org.apache.shale.clay.component.Clay.getRootElement(Clay.java:271)
>         at org.apache.shale.clay.component.Clay.encodeBegin(Clay.java:314)
>         at 
> org.apache.shale.clay.component.Clay.recursiveRenderChildren(Clay.java:412)
>         at 
> org.apache.shale.clay.component.Clay.recursiveRenderChildren(Clay.java:415)
>         at 
> org.apache.shale.clay.component.Clay.recursiveRenderChildren(Clay.java:415)
>         at org.apache.shale.clay.component.Clay.encodeChildren(Clay.java:444)
>         at 
> org.apache.shale.clay.component.Clay.recursiveRenderChildren(Clay.java:417)
>         at org.apache.shale.clay.component.Clay.encodeChildren(Clay.java:444)
>         at 
> org.apache.shale.clay.faces.ClayViewHandler.recursiveRender(ClayViewHandler.java:468)
>         at 
> org.apache.shale.clay.faces.ClayViewHandler.renderView(ClayViewHandler.java:394)
>         at 
> org.apache.shale.view.faces.ViewViewHandler.renderView(ViewViewHandler.java:151)
>         at 
> org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:384)
>         at javax.faces.webapp.FacesServlet.service(FacesServlet.java:138)
>         at 
> org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
>         at 
> org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
>         at 
> org.apache.shale.faces.ShaleApplicationFilter.doFilter(ShaleApplicationFilter.java:268)
>         at 
> org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
>         at 
> org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
>         at 
> org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:292)
>         at 
> org.acegisecurity.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:116)
>         at 
> org.acegisecurity.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:79)
>         at 
> org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:303)
>         at 
> org.acegisecurity.ui.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:143)
>         at 
> org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:303)
>         at 
> org.acegisecurity.providers.anonymous.AnonymousProcessingFilter.doFilter(AnonymousProcessingFilter.java:138)
>         at 
> org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:303)
>         at 
> org.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:220)
>         at 
> org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:303)
>         at 
> org.acegisecurity.securechannel.ChannelProcessingFilter.doFilter(ChannelProcessingFilter.java:168)
>         at 
> org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:303)
>         at 
> org.acegisecurity.util.FilterChainProxy.doFilter(FilterChainProxy.java:173)
>         at 
> org.acegisecurity.util.FilterToBeanProxy.doFilter(FilterToBeanProxy.java:120)
>         at 
> org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
>         at 
> org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
>         at 
> com.scn.web.common.filter.CharsetFilter.doFilter(CharsetFilter.java:45)
>         at 
> org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
>         at 
> org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
>         at 
> org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
>         at 
> org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
>         at 
> org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
>         at 
> org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
>         at 
> org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
>         at 
> org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
>         at 
> org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:199)
>         at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:282)
>         at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:744)
>         at 
> org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:674)
>         at 
> org.apache.jk.common.ChannelSocket$SocketConnection.runIt(ChannelSocket.java:866)
>         at 
> org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
>         at java.lang.Thread.run(Thread.java:595)
> ---------------------------------------------------------------------
> This NPE is probably caused by the WatchDog.refresh() method not being 
> synchronized. This method opens and closes connections to the Clay config 
> files, which means that one thread can open and another thread can close 
> connections before the first one is done, causing connections to be null in 
> the isDirty() method. I suppose that normally the 
> ComponentConfigBean.refresh() method should be called as it synchronizes 
> access to the WatchDog.refresh() method. However, the 
> TemplateConfigBean.getElement() method, that is called in above stack trace, 
> calls the WatchDog.refresh method directly without synchronizing access.
> Tried to turn off auto reloading of Clay config files with the 
> org.apache.shale.clay.AUTO_RELOAD_CONFIG_FILES context parameter but didn't 
> help as the WatchDog.refresh() method does not check this context parameter, 
> only the ComponentConfigBean.refresh() method does so. Also, setting the 
> AUTO_RELOAD_CONFIG_FILES to false in Shale 1.0.3, the version that we use, is 
> not picked up by the ComponentConfigBean.
> I did a test and implemented new synchronization (watchDogs = 
> Collections.synchronizedMap(new TreeMap());, displayElements = 
> Collections.synchronizedMap(new HashMap(size));,  public synchronized boolean 
> WatchDog.refresh(boolean forceReload), public synchronized void 
> ComponentConfigBean.assignParent(ComponentBean b) ) and removed all block 
> synchronization which seemed to solve most of my problems. Did this in Shale 
> 1.1.0 SNAPSHOT.
> However, the block synchronization is probably there for performance reasons 
> I guess...
> ---------------------------------------------------------------------
> I used the following JUnit test to stress our home page:
> import junit.framework.TestCase;
> import org.apache.commons.httpclient.methods.GetMethod;
> import org.apache.commons.httpclient.HttpClient;
> import org.apache.commons.httpclient.HttpStatus;
> import java.io.IOException;
> import java.util.List;
> import java.util.ArrayList;
> public class StressTest extends TestCase {
>     public void testStressWebSite() {
>         ConcurrentTestDriver testDriver = new ConcurrentTestDriver(
>                 10, new ConcurrentTask(100));
>         testDriver.start();
>     }
>     private class ConcurrentTestDriver {
>         List<Thread> threads = new ArrayList<Thread>();
>         int numberOfThreads;
>         ConcurrentTask concurrentTask;
>         ConcurrentTestDriver(int threads,
>                          ConcurrentTask task) {
>             numberOfThreads = threads;
>             concurrentTask = task;
>         }
>         public void start() {
>             // Create the threads
>             for (int i=0; i<numberOfThreads; i++) {
>                 Thread thread = new Thread(concurrentTask);
>                 threads.add(thread);
>             }
>             // Start the threads
>             for (Thread thread: threads) {
>                 thread.start();
>             }
>             // Wait for all threads to finish
>             for (Thread thread: threads) {
>                 try {
>                     thread.join();
>                 } catch (InterruptedException e) {
>                     e.printStackTrace();
>                     System.exit(12);
>                 }
>             }
>         }
>     }
>     private class ConcurrentTask implements Runnable {
>         int testCaseRepeats;
>         public ConcurrentTask(int repeats) {
>             testCaseRepeats = repeats;
>         }
>         public void run() {
>             GetMethod gm = new GetMethod("http://localhost:8080/scn";);
>             HttpClient hc = new HttpClient();
>             for (int rep=0; rep<testCaseRepeats; rep++) {
>                 System.out.println(Thread.currentThread().getName()+": Test # 
> "+(rep+1));
>                 try {
>                     int responseCode = hc.executeMethod(gm);
>                     if (responseCode != HttpStatus.SC_OK) {
>                         fail("response code: " + responseCode);
>                     }
>                     System.out.println(Thread.currentThread().getName()+": 
> Response code = "+responseCode);
>                 } catch(IOException ioe) {
>                     fail("IOException: " + ioe.getMessage());
>                 }
>                 try {
>                     long numMillisecondsToSleep = 10;
>                     Thread.sleep(numMillisecondsToSleep);
>                 } catch (InterruptedException e) {
>                     fail("InterruptedException: " + e.getMessage());
>                 }
>             }
>         }
>     }
> }

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to