You are viewing a plain text version of this content. The canonical link for it is here.
Posted to portalapps-dev@portals.apache.org by wo...@apache.org on 2014/08/18 01:53:10 UTC

svn commit: r1618528 - in /portals/applications/webcontent/trunk: portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentPortlet.java war/src/main/webapp/WEB-INF/conf/rewriter-rules-mapping.xml

Author: woonsan
Date: Sun Aug 17 23:53:10 2014
New Revision: 1618528

URL: http://svn.apache.org/r1618528
Log:
APA-64: fixing thread-safety issue - Rewriter instance must not be shared between requests because it has request specific member variables such as http method name.

Modified:
    portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentPortlet.java
    portals/applications/webcontent/trunk/war/src/main/webapp/WEB-INF/conf/rewriter-rules-mapping.xml

Modified: portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentPortlet.java
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentPortlet.java?rev=1618528&r1=1618527&r2=1618528&view=diff
==============================================================================
--- portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentPortlet.java (original)
+++ portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentPortlet.java Sun Aug 17 23:53:10 2014
@@ -19,7 +19,6 @@ package org.apache.portals.applications.
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
-import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -37,13 +36,10 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
 
 import javax.portlet.ActionRequest;
 import javax.portlet.ActionResponse;
 import javax.portlet.PortletConfig;
-import javax.portlet.PortletContext;
 import javax.portlet.PortletException;
 import javax.portlet.PortletMode;
 import javax.portlet.PortletURL;
@@ -115,19 +111,15 @@ public class WebContentPortlet extends G
     public static final String HISTORY = "webcontent.history";
     public static final String HTTP_STATE = "webcontent.http.state";
 
-    // Class Data    
     protected final static Logger log = LoggerFactory.getLogger(WebContentPortlet.class);
-    public final static String defaultEncoding = "UTF-8";
-
-    // Data Members
-    private Lock rewriterLock = new ReentrantLock();
-    private RulesetRewriter rewriter = null;
-    private RewriterController rewriteController = null;
 
     public static final String FORM_MULTIPART_METHOD = "multipart";
 
     public static final String NO_URL = "<p>URL source not specified. Go to edit mode and specify an URL.</p>";
 
+    private RewriterController rewriterController;
+    private Ruleset rewriterRuleSet;
+
     private String defaultProxyHost;
     private int defaultProxyPort = -1;
 
@@ -262,30 +254,18 @@ public class WebContentPortlet extends G
 
         byte[] content = null;
 
+        // get content from current page
+        response.setContentType("text/html");
+
         try
         {
-            // initialize the controller if it's not already done
-            // and lock stateful rewriter
-            initializeRewriter();
-
-            // get content from current page
-            response.setContentType("text/html");
-
-            try
-            {
-                content = doWebContent(currentPage.getMethod(), currentPage.getUrl(), currentPage.getParams(), request, response);
-            }
-            catch (Throwable t)
-            {
-                PrintWriter writer = response.getWriter();
-                writer.print("Error retrieveing web content:" + t.getMessage());
-                return;
-            }
+            content = doWebContent(currentPage.getMethod(), currentPage.getUrl(), currentPage.getParams(), request, response);
         }
-        finally
+        catch (Throwable t)
         {
-            // unlock stateful rewriter
-            freeRewriter();
+            PrintWriter writer = response.getWriter();
+            writer.print("Error retrieveing web content:" + t.getMessage());
+            return;
         }
 
         // write the meta-control navigation header
@@ -317,7 +297,7 @@ public class WebContentPortlet extends G
         try
         {
             bais = new ByteArrayInputStream(content);
-            IOUtils.copy(new InputStreamReader(bais, WebContentPortlet.defaultEncoding), writer);
+            IOUtils.copy(new InputStreamReader(bais, "UTF-8"), writer);
         }
         finally
         {
@@ -335,47 +315,40 @@ public class WebContentPortlet extends G
         doPreferencesEdit(request, response);
     }
 
-    /*
-     * Protected helpers for generating WebContent
-     */
-    protected void initializeRewriter() throws PortletException
-    {
-        initializeRewriter(WebContentRewriter.class);
-    }
-
-    protected void initializeRewriter(Class rewriterClass) throws PortletException
+    protected byte[] doWebContent(String method, String sourceAttr, Map sourceParams, RenderRequest request, RenderResponse response)
+        throws PortletException
     {
-        rewriterLock.lock();
+        CloseableHttpClient httpClient = null;
+        HttpRequestBase httpRequest = null ;
 
-        if (rewriteController == null)
+        try
         {
-            PortletContext portletApplication = getPortletContext(); 
-            String path = portletApplication.getRealPath("/WEB-INF");
-            String contextPath = path + "/";
-
-            try
+            if (rewriterController == null)
             {
-                // Create rewriter adaptor
-                rewriteController = getController(contextPath, rewriterClass);
+                String webinfDirPath = getPortletContext().getRealPath("/WEB-INF") + "/";
+                rewriterController = getRewriterController(webinfDirPath, WebContentRewriter.class);
             }
-            catch (Exception e)
+
+            if (rewriterRuleSet == null)
             {
-                throw new PortletException("WebContentPortlet failed to create rewriter controller: "+e, e);
+                InputStream is = null;
+
+                try
+                {
+                    is = getPortletContext().getResourceAsStream("/WEB-INF/conf/default-rewriter-rules.xml");
+                    rewriterRuleSet = rewriterController.loadRuleset(is);
+                }
+                finally
+                {
+                    IOUtils.closeQuietly(is);
+                }
             }
-        }
-    }
 
-    protected byte[] doWebContent(String method, String sourceAttr, Map sourceParams, RenderRequest request, RenderResponse response)
-        throws PortletException
-    {
-        CloseableHttpClient httpClient = null;
-        HttpRequestBase httpRequest = null ;
+            WebContentRewriter rewriter = (WebContentRewriter) createRewriter(rewriterController, rewriterRuleSet);
 
-        try
-        {
             // Set the action and base URLs in the rewriter
             PortletURL action = response.createActionURL();
-            ((WebContentRewriter) rewriter).setActionURL(action);
+            rewriter.setActionURL(action);
             URL baseURL = new URL(sourceAttr);
             rewriter.setBaseUrl(baseURL.toString());
 
@@ -384,7 +357,7 @@ public class WebContentPortlet extends G
             {
                 Reader reader = new InputStreamReader((InputStream)baseURL.getContent());
                 StringWriter writer = new StringWriter();
-                rewriter.rewrite(rewriteController.createParserAdaptor("text/html"), reader, writer);
+                rewriter.rewrite(rewriterController.createParserAdaptor("text/html"), reader, writer);
                 writer.flush();
                 return writer.toString().getBytes();
             }
@@ -394,7 +367,7 @@ public class WebContentPortlet extends G
             httpClient = getHttpClient(request, cookieStore) ;
             String methodName = StringUtils.defaultIfEmpty(method, HttpGet.METHOD_NAME);
 
-            if (FORM_MULTIPART_METHOD.equals(methodName))
+            if (StringUtils.equalsIgnoreCase(FORM_MULTIPART_METHOD, methodName))
             {
                 httpRequest = createHttpRequest(httpClient, methodName, sourceAttr, null, sourceParams, request);
             }
@@ -408,7 +381,7 @@ public class WebContentPortlet extends G
             // ...get, cache, and return the content
             if (result == null) 
             {
-                return doHttpWebContent(httpClient, cookieStore, httpRequest, 0, request, response);
+                return doHttpWebContent(httpClient, cookieStore, httpRequest, 0, request, response, rewriter);
             }
             else
             {
@@ -446,8 +419,8 @@ public class WebContentPortlet extends G
         }
     }
 
-    protected byte[] doHttpWebContent(CloseableHttpClient httpClient, CookieStore cookieStore, HttpRequestBase httpRequest, int retryCount, RenderRequest request, RenderResponse response)
-            throws PortletException
+    protected byte[] doHttpWebContent(CloseableHttpClient httpClient, CookieStore cookieStore, HttpRequestBase httpRequest, int retryCount,
+                                      RenderRequest request, RenderResponse response, WebContentRewriter rewriter) throws PortletException
     {
         CloseableHttpResponse httpResponse = null;
         HttpEntity httpEntity = null;
@@ -500,7 +473,7 @@ public class WebContentPortlet extends G
                     if (retryCount++ < 1 && doRequestedAuthentication( httpClient, httpRequest, request, response))
                     {
                         // try again, now that we are authorizied
-                        return doHttpWebContent(httpClient, cookieStore, httpRequest, retryCount, request, response);
+                        return doHttpWebContent(httpClient, cookieStore, httpRequest, retryCount, request, response, rewriter);
                     }
                     else
                     {
@@ -512,7 +485,7 @@ public class WebContentPortlet extends G
                 {
                     log.info("WebContentPortlet.doHttpWebContent() - retrying: " + httpRequest.getURI() + ", response code: " + responseCode);
                     // retry
-                    return doHttpWebContent(httpClient, cookieStore, httpRequest, retryCount, request, response);
+                    return doHttpWebContent(httpClient, cookieStore, httpRequest, retryCount, request, response, rewriter);
                 }
                 else
                 {
@@ -531,17 +504,11 @@ public class WebContentPortlet extends G
             String encoding = StringUtils.defaultIfEmpty((charset != null ? charset.name() : null), "UTF-8");
             reader = new InputStreamReader(bis, encoding);
 
-            // get the output buffer
-            if (encoding == null)
-            {
-                encoding = WebContentPortlet.defaultEncoding;
-            }
-
             ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
             Writer htmlWriter = new OutputStreamWriter(byteOutputStream, encoding);
 
             // rewrite and flush output
-            rewriter.rewrite(rewriteController.createParserAdaptor("text/html"), reader, htmlWriter);
+            rewriter.rewrite(rewriterController.createParserAdaptor("text/html"), reader, htmlWriter);
             htmlWriter.flush();
 
             // Page has been rewritten
@@ -551,15 +518,15 @@ public class WebContentPortlet extends G
         }
         catch (UnsupportedEncodingException ueex)
         {
-            throw new PortletException("Encoding " + defaultEncoding + " not supported. Error: " + ueex.getMessage());
+            throw new PortletException("Encoding not supported. Error: " + ueex);
         }
         catch (RewriterException rwe)
         {
-            throw new PortletException("Failed to rewrite HTML page. Error: " + rwe.getMessage());
+            throw new PortletException("Failed to rewrite HTML page. Error: " + rwe);
         }
         catch (Exception e)
         {
-            throw new PortletException("Exception while rewritting HTML page. Error: " + e.getMessage());
+            throw new PortletException("Exception while rewritting HTML page. Error: " + e);
         }
         finally
         {
@@ -606,31 +573,23 @@ public class WebContentPortlet extends G
     /*
      * Generate a rewrite controller using the basic rules file
      */
-    protected RewriterController getController(String contextPath, Class rewriterClass) throws Exception
+    protected RewriterController getRewriterController(String contextPath, Class rewriterClass) throws Exception
     {
-        Class[] rewriterClasses = new Class[] { rewriterClass, rewriterClass};
-        Class[] adaptorClasses = new Class[] { NekoParserAdaptor.class, SaxParserAdaptor.class};
-        RewriterController rwc = 
+        Class[] rewriterClasses = new Class[] { rewriterClass, rewriterClass };
+        Class[] adaptorClasses = new Class[] { NekoParserAdaptor.class, SaxParserAdaptor.class };
+        RewriterController rewriterController = 
                         new MappingRewriterController(contextPath + "conf/rewriter-rules-mapping.xml", 
                                                       Arrays.asList(rewriterClasses),
                                                       Arrays.asList(adaptorClasses));
-        FileReader reader = new FileReader(contextPath + "conf/default-rewriter-rules.xml");
-        Ruleset ruleset = rwc.loadRuleset(reader);
-        reader.close();
-        rewriter = rwc.createRewriter(ruleset);
-        return rwc;
+        return rewriterController;
     }
 
-    protected RulesetRewriter getRewriter()
+    protected RulesetRewriter createRewriter(RewriterController rewriterController, Ruleset ruleset) throws RewriterException
     {
+        RulesetRewriter rewriter = rewriterController.createRewriter(ruleset);
         return rewriter;
     }
 
-    protected void freeRewriter()
-    {
-        rewriterLock.unlock();
-    }
-
     protected CloseableHttpClient getHttpClient(RenderRequest request, CookieStore cookieStore) throws IOException
     {
         // derived class hook (e.g. to set up Basic Authentication)
@@ -700,7 +659,7 @@ public class WebContentPortlet extends G
             }
         }
 
-        if (HttpPost.METHOD_NAME.equals(method))
+        if (StringUtils.equalsIgnoreCase(HttpPost.METHOD_NAME, method))
         {
             httpRequest = new HttpPost(uriBuilder.build());
 
@@ -732,7 +691,7 @@ public class WebContentPortlet extends G
                 }
             }
         }
-        else if (HttpGet.METHOD_NAME.equals(method))
+        else if (StringUtils.equalsIgnoreCase(HttpGet.METHOD_NAME, method) || StringUtils.isBlank(method))
         {
             httpRequest = new HttpGet(uriBuilder.build());
         }

Modified: portals/applications/webcontent/trunk/war/src/main/webapp/WEB-INF/conf/rewriter-rules-mapping.xml
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/war/src/main/webapp/WEB-INF/conf/rewriter-rules-mapping.xml?rev=1618528&r1=1618527&r2=1618528&view=diff
==============================================================================
--- portals/applications/webcontent/trunk/war/src/main/webapp/WEB-INF/conf/rewriter-rules-mapping.xml (original)
+++ portals/applications/webcontent/trunk/war/src/main/webapp/WEB-INF/conf/rewriter-rules-mapping.xml Sun Aug 17 23:53:10 2014
@@ -16,7 +16,7 @@ See the License for the specific languag
 limitations under the License.
 -->
 <mapping>
-  <class name="org.apache.portals.applications.webcontent2.rewriter.rules.impl.RulesetImpl">
+  <class name="org.apache.portals.applications.webcontent2.portlet.rewriter.rules.impl.RulesetImpl">
     <map-to xml="ruleset"/>
 
     <field name="id" type="java.lang.String">
@@ -28,20 +28,20 @@ limitations under the License.
     </field>
                                    
     <field name="tags"
-           type="org.apache.portals.applications.webcontent2.rewriter.rules.impl.TagImpl"
+           type="org.apache.portals.applications.webcontent2.portlet.rewriter.rules.impl.TagImpl"
            collection="collection">
       <bind-xml name="tag"/>
     </field>
 
     <field name="rules"
-           type="org.apache.portals.applications.webcontent2.rewriter.rules.impl.RuleImpl"
+           type="org.apache.portals.applications.webcontent2.portlet.rewriter.rules.impl.RuleImpl"
            collection="collection">
       <bind-xml name="rule"/>
     </field>
 
   </class>
 
-  <class name="org.apache.portals.applications.webcontent2.rewriter.rules.impl.TagImpl">
+  <class name="org.apache.portals.applications.webcontent2.portlet.rewriter.rules.impl.TagImpl">
     <map-to xml="tag"/>
                                    
     <field name="id" type="java.lang.String">
@@ -57,14 +57,14 @@ limitations under the License.
     </field>
 
     <field name="attributes"
-           type="org.apache.portals.applications.webcontent2.rewriter.rules.impl.AttributeImpl"
+           type="org.apache.portals.applications.webcontent2.portlet.rewriter.rules.impl.AttributeImpl"
            collection="collection">
       <bind-xml name="attribute"/>
     </field>
 
   </class>
 
-  <class name="org.apache.portals.applications.webcontent2.rewriter.rules.impl.RuleImpl">
+  <class name="org.apache.portals.applications.webcontent2.portlet.rewriter.rules.impl.RuleImpl">
     <map-to xml="rule"/>
                                    
     <field name="id" type="java.lang.String">
@@ -89,7 +89,7 @@ limitations under the License.
 
   </class>
 
-  <class name="org.apache.portals.applications.webcontent2.rewriter.rules.impl.AttributeImpl">
+  <class name="org.apache.portals.applications.webcontent2.portlet.rewriter.rules.impl.AttributeImpl">
     <map-to xml="attribute"/>
                                    
     <field name="id" type="java.lang.String">