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/29 05:16:09 UTC

svn commit: r1621242 - in /portals/applications/webcontent/trunk: content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/ content-rewriter/src/test/java/org/apache/portals/applications/webcontent2/rewriter/ port...

Author: woonsan
Date: Fri Aug 29 03:16:08 2014
New Revision: 1621242

URL: http://svn.apache.org/r1621242
Log:
APA-66: Adding simpleReverseProxyPortlet with html cleaner based content rewriting

Added:
    portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/AbstractProxyTagNodeVisitor.java
    portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/AndTagNodeCondition.java
    portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/ContentSelectorUtils.java
    portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/history/
    portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/history/WebContentPage.java
      - copied, changed from r1621008, portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentHistoryPage.java
    portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/history/WebContentPageHistory.java
      - copied, changed from r1621008, portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentHistoryList.java
    portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/DefaultPortletProxyTagNodeVisitor.java
    portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/PortletAnyProxyMapping.java
Removed:
    portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentHistoryList.java
    portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentHistoryPage.java
    portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentResource.java
Modified:
    portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/HtmlCleanerContentRewriter.java
    portals/applications/webcontent/trunk/content-rewriter/src/test/java/org/apache/portals/applications/webcontent2/rewriter/HtmlCleanerContentRewriterTest.java
    portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentPortlet.java
    portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/GenericReverseProxyPortlet.java
    portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/PortletRequestContext.java
    portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/SimpleReverseProxyPortlet.java
    portals/applications/webcontent/trunk/reverse-proxy/src/main/java/org/apache/portals/applications/webcontent2/proxy/impl/ProxyContext.java
    portals/applications/webcontent/trunk/reverse-proxy/src/main/java/org/apache/portals/applications/webcontent2/proxy/impl/ServletRequestContext.java
    portals/applications/webcontent/trunk/war/src/main/webapp/WEB-INF/portlet.xml
    portals/applications/webcontent/trunk/war/src/main/webapp/WEB-INF/psml/test-webcontent2.psml

Added: portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/AbstractProxyTagNodeVisitor.java
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/AbstractProxyTagNodeVisitor.java?rev=1621242&view=auto
==============================================================================
--- portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/AbstractProxyTagNodeVisitor.java (added)
+++ portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/AbstractProxyTagNodeVisitor.java Fri Aug 29 03:16:08 2014
@@ -0,0 +1,89 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.portals.applications.webcontent2.rewriter.htmlcleaner;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.htmlcleaner.CommentNode;
+import org.htmlcleaner.HtmlNode;
+import org.htmlcleaner.TagNode;
+import org.htmlcleaner.TagNodeVisitor;
+
+public abstract class AbstractProxyTagNodeVisitor implements TagNodeVisitor
+{
+
+    private Map<String, String> tagNameAndLinkAttrs;
+
+    public AbstractProxyTagNodeVisitor(Map<String, String> tagNameAndLinkAttrs)
+    {
+        this.tagNameAndLinkAttrs = new HashMap<String, String>();
+
+        if (tagNameAndLinkAttrs != null)
+        {
+            this.tagNameAndLinkAttrs.putAll(tagNameAndLinkAttrs);
+        }
+    }
+
+    public boolean visit(TagNode parentNode, HtmlNode htmlNode)
+    {
+        if (htmlNode instanceof TagNode)
+        {
+            return visitTagNode(parentNode, (TagNode) htmlNode);
+        }
+        else if (htmlNode instanceof CommentNode)
+        {
+            return visitCommentNode(parentNode, (CommentNode) htmlNode);
+        }
+
+        return true;
+    }
+
+    protected boolean visitTagNode(TagNode parentNode, TagNode tag)
+    {
+        String tagName = tag.getName();
+        String linkAttrName = tagNameAndLinkAttrs.get(tagName);
+
+        if (StringUtils.isEmpty(linkAttrName))
+        {
+            return true;
+        }
+
+        String link = tag.getAttributeByName(linkAttrName);
+
+        if (StringUtils.isNotEmpty(link))
+        {
+            String rewritten = rewriteURI(tagName, linkAttrName, link);
+
+            if (!StringUtils.equals(link, rewritten))
+            {
+                tag.addAttribute(linkAttrName, rewritten);
+            }
+        }
+
+        return true;
+    }
+
+    protected boolean visitCommentNode(TagNode parentNode, CommentNode comment)
+    {
+        return true;
+    }
+
+    protected abstract String rewriteURI(String tagName, String attrName, String uri);
+
+}

Added: portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/AndTagNodeCondition.java
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/AndTagNodeCondition.java?rev=1621242&view=auto
==============================================================================
--- portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/AndTagNodeCondition.java (added)
+++ portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/AndTagNodeCondition.java Fri Aug 29 03:16:08 2014
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.portals.applications.webcontent2.rewriter.htmlcleaner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.htmlcleaner.TagNode;
+import org.htmlcleaner.conditional.ITagNodeCondition;
+
+public class AndTagNodeCondition implements ITagNodeCondition
+{
+
+    private List<ITagNodeCondition> conditionsList;
+
+    public AndTagNodeCondition()
+    {
+    }
+
+    public void addTagNodeCondition(ITagNodeCondition condition)
+    {
+        if (conditionsList == null)
+        {
+            conditionsList = new ArrayList<ITagNodeCondition>();
+        }
+
+        conditionsList.add(condition);
+    }
+
+    public boolean satisfy(TagNode tagNode)
+    {
+        if (conditionsList == null || conditionsList.isEmpty())
+        {
+            return false;
+        }
+
+        for (ITagNodeCondition condition : conditionsList)
+        {
+            if (!condition.satisfy(tagNode))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}

Added: portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/ContentSelectorUtils.java
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/ContentSelectorUtils.java?rev=1621242&view=auto
==============================================================================
--- portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/ContentSelectorUtils.java (added)
+++ portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/ContentSelectorUtils.java Fri Aug 29 03:16:08 2014
@@ -0,0 +1,79 @@
+package org.apache.portals.applications.webcontent2.rewriter.htmlcleaner;
+
+import org.apache.commons.lang.StringUtils;
+import org.htmlcleaner.conditional.ITagNodeCondition;
+import org.htmlcleaner.conditional.TagNodeAttExistsCondition;
+import org.htmlcleaner.conditional.TagNodeAttValueCondition;
+import org.htmlcleaner.conditional.TagNodeNameCondition;
+
+class ContentSelectorUtils
+{
+
+    private ContentSelectorUtils()
+    {
+    }
+
+    /**
+     * Support transforming very simple selector string to <code>ITagNodeCondition</code>.
+     * <P>
+     * <EM>Note: This supports only 'elem[attr=value]' pattern only.
+     * </P>
+     * @param selector
+     * @return
+     */
+    public static ITagNodeCondition createTagNodeConditionBySelector(String selector)
+    {
+        AndTagNodeCondition condition = new AndTagNodeCondition();
+
+        if (StringUtils.isBlank(selector))
+        {
+            return condition;
+        }
+
+        String elementName = null;
+        String attributeName = null;
+        String attributeValue = null;
+
+        int offset = StringUtils.indexOf(selector, "[");
+
+        if (offset == -1)
+        {
+            elementName = StringUtils.trim(selector);
+        }
+        else
+        {
+            elementName = StringUtils.trim(StringUtils.substring(selector, 0, offset));
+            selector = StringUtils.trim(StringUtils.substringBefore(StringUtils.substring(selector, offset + 1), "]"));
+            offset = StringUtils.indexOf(selector, "=");
+
+            if (offset == -1)
+            {
+                attributeName = selector;
+            }
+            else
+            {
+                attributeName = StringUtils.trim(StringUtils.substring(selector, 0, offset));
+                attributeValue = StringUtils.trim(StringUtils.substring(selector, offset + 1));
+            }
+        }
+
+        if (StringUtils.isNotEmpty(elementName))
+        {
+            condition.addTagNodeCondition(new TagNodeNameCondition(elementName));
+        }
+
+        if (StringUtils.isNotEmpty(attributeName))
+        {
+            if (attributeValue == null)
+            {
+                condition.addTagNodeCondition(new TagNodeAttExistsCondition(attributeName));
+            }
+            else
+            {
+                condition.addTagNodeCondition(new TagNodeAttValueCondition(attributeName, attributeValue, true));
+            }
+        }
+
+        return condition;
+    }
+}

Modified: portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/HtmlCleanerContentRewriter.java
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/HtmlCleanerContentRewriter.java?rev=1621242&r1=1621241&r2=1621242&view=diff
==============================================================================
--- portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/HtmlCleanerContentRewriter.java (original)
+++ portals/applications/webcontent/trunk/content-rewriter/src/main/java/org/apache/portals/applications/webcontent2/rewriter/htmlcleaner/HtmlCleanerContentRewriter.java Fri Aug 29 03:16:08 2014
@@ -39,19 +39,16 @@ import org.htmlcleaner.HtmlCleaner;
 import org.htmlcleaner.Serializer;
 import org.htmlcleaner.TagNode;
 import org.htmlcleaner.TagNodeVisitor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.htmlcleaner.conditional.ITagNodeCondition;
 
 public class HtmlCleanerContentRewriter implements ContentRewriter
 {
 
-    private static Logger log = LoggerFactory.getLogger(HtmlCleanerContentRewriter.class);
-
     private HtmlCleaner cleaner;
     private SerializerFactory serializerFactory;
     private String sinkEncoding = "UTF-8";
-    private String rootTagName;
-    private boolean innerRootTagOnly;
+    private String contentSelector;
+    private boolean innerHtmlOnly;
     private String [] transformationInfos;
     private List<TagNodeVisitor> tagNodeVisitors;
 
@@ -79,24 +76,24 @@ public class HtmlCleanerContentRewriter 
         this.sinkEncoding = sinkEncoding;
     }
 
-    public String getRootTagName()
+    public String getContentSelector()
     {
-        return rootTagName;
+        return contentSelector;
     }
 
-    public void setRootTagName(String rootTagName)
+    public void setContentSelector(String contentSelector)
     {
-        this.rootTagName = rootTagName;
+        this.contentSelector = contentSelector;
     }
 
-    public boolean isInnerRootTagOnly()
+    public boolean isInnerHtmlOnly()
     {
-        return innerRootTagOnly;
+        return innerHtmlOnly;
     }
 
-    public void setInnerRootTagOnly(boolean innerRootTagOnly)
+    public void setInnerHtmlOnly(boolean innerHtmlOnly)
     {
-        this.innerRootTagOnly = innerRootTagOnly;
+        this.innerHtmlOnly = innerHtmlOnly;
     }
 
     public CleanerTransformations getCleanerTransformations()
@@ -218,27 +215,53 @@ public class HtmlCleanerContentRewriter 
             bw = new BufferedWriter(writer);
 
             TagNode rootTagNode = getHtmlCleaner().clean(br);
+            List<? extends TagNode> contentTagNodes = null;
 
-            if (getRootTagName() != null)
+            if (getContentSelector() != null)
             {
-                TagNode [] tagNodes = rootTagNode.getElementsByName(getRootTagName(), true);
-
-                if (tagNodes.length > 0 ) {
-                    rootTagNode = tagNodes[0];
-                }
+                ITagNodeCondition selectCondition = ContentSelectorUtils.createTagNodeConditionBySelector(getContentSelector());
+                contentTagNodes = rootTagNode.getElementList(selectCondition, true);
             }
 
-            for (TagNodeVisitor tagNodeVisitor : getTagNodeVisitors())
+            if (contentTagNodes != null && !contentTagNodes.isEmpty())
             {
-                rootTagNode.traverse(tagNodeVisitor);
-            }
+                for (TagNode contentTagNode : contentTagNodes)
+                {
+                    for (TagNodeVisitor tagNodeVisitor : getTagNodeVisitors())
+                    {
+                        contentTagNode.traverse(tagNodeVisitor);
+                    }
+                }
 
-            if (isInnerRootTagOnly())
-            {
-                writer.write(getHtmlCleaner().getInnerHtml(rootTagNode));
+                if (isInnerHtmlOnly())
+                {
+                    String innerHtml = null;
+
+                    for (TagNode contentTagNode : contentTagNodes)
+                    {
+                        innerHtml = getHtmlCleaner().getInnerHtml(contentTagNode);
+    
+                        if (innerHtml != null)
+                        {
+                            writer.write(innerHtml);
+                        }
+                    }
+                }
+                else
+                {
+                    for (TagNode contentTagNode : contentTagNodes)
+                    {
+                        serializer.write(contentTagNode, writer, getSinkEncoding());
+                    }
+                }
             }
             else
             {
+                for (TagNodeVisitor tagNodeVisitor : getTagNodeVisitors())
+                {
+                    rootTagNode.traverse(tagNodeVisitor);
+                }
+
                 serializer.write(rootTagNode, writer, getSinkEncoding());
             }
         } 

Modified: portals/applications/webcontent/trunk/content-rewriter/src/test/java/org/apache/portals/applications/webcontent2/rewriter/HtmlCleanerContentRewriterTest.java
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/content-rewriter/src/test/java/org/apache/portals/applications/webcontent2/rewriter/HtmlCleanerContentRewriterTest.java?rev=1621242&r1=1621241&r2=1621242&view=diff
==============================================================================
--- portals/applications/webcontent/trunk/content-rewriter/src/test/java/org/apache/portals/applications/webcontent2/rewriter/HtmlCleanerContentRewriterTest.java (original)
+++ portals/applications/webcontent/trunk/content-rewriter/src/test/java/org/apache/portals/applications/webcontent2/rewriter/HtmlCleanerContentRewriterTest.java Fri Aug 29 03:16:08 2014
@@ -95,8 +95,8 @@ public class HtmlCleanerContentRewriterT
 
         contentRewriter = new HtmlCleanerContentRewriter();
         contentRewriter.setSerializerFactory(serializerFactory);
-        contentRewriter.setRootTagName("body");
-        contentRewriter.setInnerRootTagOnly(true);
+        contentRewriter.setContentSelector("body");
+        contentRewriter.setInnerHtmlOnly(true);
         contentRewriter.setCleanerTransformationStringArray(HTMLCLEANER_TRNSFORM_INFO);
 
         final String siteUrl = "http://www.example.com/";

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=1621242&r1=1621241&r2=1621242&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 Fri Aug 29 03:16:08 2014
@@ -70,6 +70,8 @@ import org.apache.http.impl.client.HttpC
 import org.apache.http.impl.client.LaxRedirectStrategy;
 import org.apache.http.message.BasicNameValuePair;
 import org.apache.http.util.EntityUtils;
+import org.apache.portals.applications.webcontent2.portlet.history.WebContentPageHistory;
+import org.apache.portals.applications.webcontent2.portlet.history.WebContentPage;
 import org.apache.portals.applications.webcontent2.portlet.rewriter.MappingRewriterController;
 import org.apache.portals.applications.webcontent2.portlet.rewriter.RewriterController;
 import org.apache.portals.applications.webcontent2.portlet.rewriter.RewriterException;
@@ -159,7 +161,7 @@ public class WebContentPortlet extends G
             if (!browserAction.equalsIgnoreCase(BROWSER_ACTION_REFRESH_PAGE))
             {
                 // for Refresh, there is nothing special to do - current history page will be re-displayed
-                WebContentHistoryList history = (WebContentHistoryList)PortletMessaging.receive(actionRequest, HISTORY);
+                WebContentPageHistory history = (WebContentPageHistory)PortletMessaging.receive(actionRequest, HISTORY);
 
                 if (browserAction.equalsIgnoreCase(BROWSER_ACTION_PREVIOUS_PAGE))
                 {
@@ -203,14 +205,14 @@ public class WebContentPortlet extends G
         if (webContentURL != null && webContentURL.length() > 0)
         {
             // new page visit - make it the current page in the history
-            WebContentHistoryList history = (WebContentHistoryList)PortletMessaging.receive(actionRequest, HISTORY);
+            WebContentPageHistory history = (WebContentPageHistory)PortletMessaging.receive(actionRequest, HISTORY);
 
             if (history == null)
             {
-                history = new WebContentHistoryList();
+                history = new WebContentPageHistory();
             }
 
-            history.visitPage(new WebContentHistoryPage(webContentURL,webContentParams,webContentMethod));
+            history.visitPage(new WebContentPage(webContentURL, webContentMethod, webContentParams));
             PortletMessaging.publish(actionRequest, HISTORY, history);
         }
     }
@@ -230,14 +232,14 @@ public class WebContentPortlet extends G
         }
 
         // view the current page in the history
-        WebContentHistoryList history = (WebContentHistoryList)PortletMessaging.receive(request, HISTORY);
+        WebContentPageHistory history = (WebContentPageHistory)PortletMessaging.receive(request, HISTORY);
 
         if (history == null)
         {
-            history = new WebContentHistoryList();
+            history = new WebContentPageHistory();
         }
 
-        WebContentHistoryPage currentPage = history.getCurrentPage();
+        WebContentPage currentPage = history.getCurrentPage();
 
         if (currentPage == null)
         {
@@ -249,7 +251,7 @@ public class WebContentPortlet extends G
                 return;
             }
 
-            currentPage = new WebContentHistoryPage(sourceURL);
+            currentPage = new WebContentPage(sourceURL);
         }
 
         byte[] content = null;

Copied: portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/history/WebContentPage.java (from r1621008, portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentHistoryPage.java)
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/history/WebContentPage.java?p2=portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/history/WebContentPage.java&p1=portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentHistoryPage.java&r1=1621008&r2=1621242&rev=1621242&view=diff
==============================================================================
--- portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentHistoryPage.java (original)
+++ portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/history/WebContentPage.java Fri Aug 29 03:16:08 2014
@@ -14,47 +14,51 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.portals.applications.webcontent2.portlet;
+package org.apache.portals.applications.webcontent2.portlet.history;
 
 import java.io.Serializable;
-import java.util.HashMap;
+import java.util.Collections;
+import java.util.LinkedHashMap;
 import java.util.Map;
 
 import org.apache.commons.lang.StringUtils;
 
-
 /**
- * Information required to re-visit a page in the WebContentPortlet
- *
- * @author <a href="mailto:dyoung@phase2systems.com">David L Young</a>
- * @version $Id$ 
+ * Web content page
  */
-
-public class WebContentHistoryPage implements Serializable
+public class WebContentPage implements Serializable
 {
-
     private static final long serialVersionUID = 1L;
 
     private String method;
     private String url;
     private Map<String, String[]> params;
 
-    public WebContentHistoryPage(String url)
+    public WebContentPage(String url)
+    {
+        this(url, null);
+    }
+
+    public WebContentPage(String url, String method)
     {
-        this(url, null, null);
+        this(url, method, null);
     }
 
-    public WebContentHistoryPage(String url, Map<String, String[]> params, String method)
+    public WebContentPage(String url, String method, Map<String, String[]> params)
     {
-        // guarantee non-null, so that equals() is well-behaved
         if (url == null)
         {
-            throw new IllegalArgumentException("WebContentHistoryPage() - url required");
+            throw new IllegalArgumentException("url must not be null.");
         }
 
         this.url = url;
-        this.params = (params != null ? params : new HashMap<String, String[]>());
         this.method = method;
+        this.params = new LinkedHashMap<String, String[]>();
+
+        if (params != null)
+        {
+            this.params.putAll(params);
+        }
     }
 
     public String getMethod()
@@ -62,50 +66,33 @@ public class WebContentHistoryPage imple
         return method;
     }
 
-    public void setMethod(String method)
-    {
-        this.method = method;
-    }
-
     public String getUrl()
     {
         return url;
     }
 
-    public void setUrl(String url)
-    {
-        this.url = url;
-    }
-
     public Map<String, String[]> getParams()
     {
-        return params;
-    }
-
-    public void setParams(Map<String, String[]> params)
-    {
-        this.params = params;
+        return Collections.unmodifiableMap(params);
     }
 
     @Override
     public boolean equals(Object o)
     {
-        if (o == null || !(o instanceof WebContentHistoryPage))
+        if (o == null || !(o instanceof WebContentPage))
         {
             return false;
         }
 
-        WebContentHistoryPage page = (WebContentHistoryPage) o;
-
-        return (StringUtils.equals(page.url, this.url) && page.params.equals(this.params) && StringUtils.equals(page.method, this.method));
+        WebContentPage other = (WebContentPage) o;
+        return (StringUtils.equals(other.url, this.url) && StringUtils.equals(other.method, this.method) && other.params.equals(this.params));
     }
 
     @Override
     public String toString()
     {
-        StringBuilder sb = new StringBuilder();
-        sb.append( "[" ).append(method).append(": ").append(url).append(", params: ").append(params).append("]");
+        StringBuilder sb = new StringBuilder(super.toString()).append(' ');
+        sb.append("[").append(method).append(": ").append(url).append(", params: ").append(params).append("]");
         return sb.toString();
     }
-
 }

Copied: portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/history/WebContentPageHistory.java (from r1621008, portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentHistoryList.java)
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/history/WebContentPageHistory.java?p2=portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/history/WebContentPageHistory.java&p1=portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentHistoryList.java&r1=1621008&r2=1621242&rev=1621242&view=diff
==============================================================================
--- portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/WebContentHistoryList.java (original)
+++ portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/history/WebContentPageHistory.java Fri Aug 29 03:16:08 2014
@@ -14,110 +14,111 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.portals.applications.webcontent2.portlet;
+package org.apache.portals.applications.webcontent2.portlet.history;
 
 import java.io.Serializable;
-import java.util.ArrayList;
+import java.util.LinkedList;
 import java.util.List;
 
-
 /**
- * A history of content navigations in the WebContentPortlet
- *
- * @author <a href="mailto:dyoung@phase2systems.com">David L Young</a>
- * @version $Id$ 
+ * History of web content page navigations
  */
-
-public class WebContentHistoryList extends Object
-    implements Serializable
+public class WebContentPageHistory implements Serializable
 {
-    int maxLength;
-    List history;
-    int currentIndex;
-    
-    // Constructors
-
-    public WebContentHistoryList()
-    {
-        this( -1 );
-    }
-    public WebContentHistoryList( int maxLength )
-    {
-        super();
-        
-        this.maxLength = maxLength;
-        this.history = new ArrayList();
-        this.currentIndex = -1;
-    }
-    
-    // Methods
-    
+    private static final long serialVersionUID = 1L;
+
+    private List<WebContentPage> pageList;
+    private int curIndex = -1;
+
+    public WebContentPageHistory()
+    {
+        pageList = new LinkedList<WebContentPage>();
+    }
+
     public boolean isEmpty()
     {
-        return this.history.isEmpty();
+        return (pageList == null || pageList.isEmpty());
     }
+
     public boolean hasCurrentPage()
     {
-        return this.currentIndex >= 0;
+        return curIndex >= 0;
     }
+
     public boolean hasPreviousPage()
     {
-        return !isEmpty() && this.currentIndex-1 >= 0;
+        return !isEmpty() && (curIndex > 0);
     }
+
     public boolean hasNextPage()
     {
-        return !isEmpty() && this.currentIndex+1 < this.history.size();
+        return !isEmpty() && (curIndex < pageList.size() - 1);
     }
-    
-    public WebContentHistoryPage getCurrentPage()
+
+    public WebContentPage getCurrentPage()
     {
         if (!hasCurrentPage())
-            return null ;
-        return (WebContentHistoryPage)this.history.get(this.currentIndex);
+        {
+            return null;
+        }
+
+        return (WebContentPage) pageList.get(curIndex);
     }
-    public WebContentHistoryPage getPreviousPage()
+
+    public WebContentPage getPreviousPage()
     {
         if (!hasPreviousPage())
+        {
             return null;
-        this.currentIndex = this.currentIndex-1;
+        }
+
+        curIndex -= 1;
+
         return getCurrentPage();
     }
-    public WebContentHistoryPage getNextPage()
+
+    public WebContentPage getNextPage()
     {
         if (!hasNextPage())
+        {
             return null;
-        this.currentIndex = this.currentIndex+1;
+        }
+
+        curIndex += 1;
+
         return getCurrentPage();
     }
-    
-    public void visitPage(WebContentHistoryPage page)
+
+    public void visitPage(WebContentPage page)
     {
-        if (page==null)
-            throw new IllegalArgumentException("WebContentHistoryList.addPage() - non-null page required.");
-        
-        int i = this.history.indexOf(page);
-        if (i >= 0 && i == this.currentIndex) 
+        if (page == null)
+        {
+            throw new IllegalArgumentException("page must be not null.");
+        }
+
+        int index = pageList.indexOf(page);
+
+        if (index != -1 && index == curIndex)
         {
-            // just visiting the current page
+            // just you're visiting the current page
             return;
         }
-        
-        // otherwise - new page...
+
+        // otherwise new page...
         while (hasNextPage())
         {
             // ...visiting a page discards any pages we have visited by going "back"
-            this.history.remove(this.currentIndex+1);
+            pageList.remove(curIndex + 1);
         }
-        if (i >= 0 && i < history.size())
+
+        if (index != -1 && index < pageList.size())
         {
             // ...actually, new visit to an old page, only keep one reference to it
-            this.history.remove(i);
+            pageList.remove(index);
         }
-        
+
         // add in the new page, at the end
-        this.history.add(page);
-        this.currentIndex = this.history.size()-1;
-        
-        // System.out.println("WebContentHistoryList.visitPage() - current index is: "+this.currentIndex+"\nhistory list..."+ArrayUtils.toString(this.history));
+        pageList.add(page);
+        curIndex = pageList.size() - 1;
     }
 }

Added: portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/DefaultPortletProxyTagNodeVisitor.java
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/DefaultPortletProxyTagNodeVisitor.java?rev=1621242&view=auto
==============================================================================
--- portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/DefaultPortletProxyTagNodeVisitor.java (added)
+++ portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/DefaultPortletProxyTagNodeVisitor.java Fri Aug 29 03:16:08 2014
@@ -0,0 +1,119 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.portals.applications.webcontent2.portlet.proxy;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.portlet.MimeResponse;
+import javax.portlet.PortletResponse;
+import javax.portlet.PortletURL;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.http.client.utils.URIUtils;
+import org.apache.portals.applications.webcontent2.proxy.impl.ProxyContext;
+import org.apache.portals.applications.webcontent2.rewriter.htmlcleaner.AbstractProxyTagNodeVisitor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DefaultPortletProxyTagNodeVisitor extends AbstractProxyTagNodeVisitor
+{
+
+    private static Logger log = LoggerFactory.getLogger(DefaultPortletProxyTagNodeVisitor.class);
+
+    private static final Map<String, String> DEFAULT_TAG_NAME_AND_LINK_ATTRS = new HashMap<String, String>();
+
+    static
+    {
+        DEFAULT_TAG_NAME_AND_LINK_ATTRS.put("a", "href");
+        DEFAULT_TAG_NAME_AND_LINK_ATTRS.put("img", "src");
+        DEFAULT_TAG_NAME_AND_LINK_ATTRS.put("form", "action");
+    }
+
+    public DefaultPortletProxyTagNodeVisitor()
+    {
+        this(DEFAULT_TAG_NAME_AND_LINK_ATTRS);
+    }
+
+    public DefaultPortletProxyTagNodeVisitor(Map<String, String> tagNameAndLinkAttrs)
+    {
+        super(tagNameAndLinkAttrs);
+    }
+
+    @Override
+    protected String rewriteURI(String tagName, String attrName, String uri)
+    {
+        if (!isRewritableURI(uri))
+        {
+            return uri;
+        }
+
+        ProxyContext proxyContext = ProxyContext.getCurrentProxyContext();
+        PortletRequestContext prc = (PortletRequestContext) proxyContext.getRequestContext();
+        PortletResponse response = prc.getPortletResponse();
+
+        if (!(response instanceof MimeResponse))
+        {
+            log.error("Cannot rewrite url because response is not a MimeResponse.");
+            return uri;
+        }
+
+        URI remoteURI = proxyContext.getRemoteURI();
+
+        URI uriObj = null;
+
+        try
+        {
+            uriObj = URI.create(uri);
+        }
+        catch (Exception e)
+        {
+            log.warn("Invalid uri: '{}'.", uri);
+            return uri;
+        }
+
+        URI rewrittenURI = URIUtils.resolve(remoteURI, uriObj);
+
+        if ("src".equals(attrName))
+        {
+            return rewrittenURI.toString();
+        }
+        else
+        {
+            PortletURL actionUrl = ((MimeResponse) response).createActionURL();
+            actionUrl.setParameter(GenericReverseProxyPortlet.REMOTE_URI_PARAM_NAME, rewrittenURI.toString());
+            return actionUrl.toString();
+        }
+    }
+
+    protected boolean isRewritableURI(String uri)
+    {
+        // mailto: URIs often contain invalid characters in web pages to avoid spams
+        // and #, javascript: and data: URIs do not need to be parsed at all.
+        // These should be avoided in URI rewriting.
+        if (StringUtils.startsWith(uri, "#") 
+                        || StringUtils.startsWith(uri, "javascript:")
+                        || StringUtils.startsWith(uri, "mailto:")
+                        || StringUtils.startsWith(uri, "data:"))
+        {
+            return false;
+        }
+
+        return true;
+    }
+}

Modified: portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/GenericReverseProxyPortlet.java
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/GenericReverseProxyPortlet.java?rev=1621242&r1=1621241&r2=1621242&view=diff
==============================================================================
--- portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/GenericReverseProxyPortlet.java (original)
+++ portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/GenericReverseProxyPortlet.java Fri Aug 29 03:16:08 2014
@@ -18,18 +18,30 @@ package org.apache.portals.applications.
 
 import java.io.IOException;
 
+import javax.portlet.ActionRequest;
+import javax.portlet.ActionResponse;
 import javax.portlet.PortletException;
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletResponse;
 import javax.portlet.RenderRequest;
 import javax.portlet.RenderResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.portals.applications.webcontent2.proxy.ReverseProxyException;
 import org.apache.portals.applications.webcontent2.proxy.ReverseProxyService;
 import org.apache.portals.applications.webcontent2.proxy.impl.ProxyContext;
 import org.apache.portals.bridges.velocity.GenericVelocityPortlet;
 
+/**
+ * Generic reverse proxy portlet invoking {@link ReverseProxyService} injected.
+ */
 public class GenericReverseProxyPortlet extends GenericVelocityPortlet
 {
 
+    public static final String REMOTE_URI_PARAM_NAME = "remote.uri";
+
     private ReverseProxyService proxyService;
 
     public GenericReverseProxyPortlet()
@@ -51,11 +63,33 @@ public class GenericReverseProxyPortlet 
     public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException
     {
         response.setContentType("text/html");
+        invokeProxyService(request, response);
+    }
+
+    @Override
+    public void serveResource(ResourceRequest request, ResourceResponse response) throws PortletException, IOException
+    {
+        invokeProxyService(request, response);
+    }
+
+    @Override
+    public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException
+    {
+        String param = StringUtils.trim(request.getParameter(REMOTE_URI_PARAM_NAME));
+
+        if (StringUtils.isNotEmpty(param))
+        {
+            response.setRenderParameter(REMOTE_URI_PARAM_NAME, param);
+        }
+    }
 
+    protected void invokeProxyService(PortletRequest request, PortletResponse response) throws PortletException, IOException
+    {
         try
         {
             PortletRequestContext requestContext = new PortletRequestContext(request, response);
             ProxyContext proxyContext = new ProxyContext(requestContext);
+            ProxyContext.setCurrentProxyContext(proxyContext);
             getProxyService().invoke(proxyContext);
         }
         catch (ReverseProxyException e)
@@ -77,5 +111,9 @@ public class GenericReverseProxyPortlet 
         {
             throw new PortletException(e);
         }
+        finally
+        {
+            ProxyContext.removeCurrentProxyContext();
+        }
     }
 }

Added: portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/PortletAnyProxyMapping.java
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/PortletAnyProxyMapping.java?rev=1621242&view=auto
==============================================================================
--- portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/PortletAnyProxyMapping.java (added)
+++ portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/PortletAnyProxyMapping.java Fri Aug 29 03:16:08 2014
@@ -0,0 +1,82 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.portals.applications.webcontent2.portlet.proxy;
+
+import java.net.URI;
+
+import javax.portlet.PortletConfig;
+import javax.portlet.PortletRequest;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.portals.applications.webcontent2.proxy.impl.AbstractProxyMapping;
+import org.apache.portals.applications.webcontent2.proxy.impl.ProxyContext;
+
+public class PortletAnyProxyMapping extends AbstractProxyMapping
+{
+
+    private PortletConfig portletConfig;
+
+    public PortletAnyProxyMapping(PortletConfig portletConfig)
+    {
+        this.portletConfig = portletConfig;
+    }
+
+    public boolean matchesLocal(String localPath)
+    {
+        return true;
+    }
+
+    public String resolveRemoteFromLocal(String localPath)
+    {
+        return getCurrentRemoteURI();
+    }
+
+    public boolean matchesRemote(URI remoteURI)
+    {
+        return true;
+    }
+
+    public String resolveLocalFromRemote(URI remoteURI)
+    {
+        return "/";
+    }
+
+    protected PortletConfig getPortletConfig()
+    {
+        return portletConfig;
+    }
+
+    protected String getCurrentRemoteURI()
+    {
+        ProxyContext proxyContext = ProxyContext.getCurrentProxyContext();
+        PortletRequestContext prc = (PortletRequestContext) proxyContext.getRequestContext();
+        PortletRequest request = prc.getPortletRequest();
+        String remoteURI = request.getParameter(GenericReverseProxyPortlet.REMOTE_URI_PARAM_NAME);
+
+        if (StringUtils.isBlank(remoteURI))
+        {
+            remoteURI = request.getPreferences().getValue(GenericReverseProxyPortlet.REMOTE_URI_PARAM_NAME, null);
+        }
+
+        if (StringUtils.isBlank(remoteURI))
+        {
+            remoteURI = getPortletConfig().getInitParameter(GenericReverseProxyPortlet.REMOTE_URI_PARAM_NAME);
+        }
+
+        return remoteURI;
+    }
+}

Modified: portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/PortletRequestContext.java
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/PortletRequestContext.java?rev=1621242&r1=1621241&r2=1621242&view=diff
==============================================================================
--- portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/PortletRequestContext.java (original)
+++ portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/PortletRequestContext.java Fri Aug 29 03:16:08 2014
@@ -48,6 +48,16 @@ public class PortletRequestContext imple
         this.response = response;
     }
 
+    public PortletRequest getPortletRequest()
+    {
+        return request;
+    }
+
+    public PortletResponse getPortletResponse()
+    {
+        return response;
+    }
+
     public boolean isSecure()
     {
         return request.isSecure();
@@ -75,12 +85,12 @@ public class PortletRequestContext imple
 
     public String getRequestBasePath()
     {
-        return null;
+        return "";
     }
 
     public String getPathInfo()
     {
-        return null;
+        return "/";
     }
 
     public Object getAttribute(String name)
@@ -170,7 +180,7 @@ public class PortletRequestContext imple
     {
         if (sink == null)
         {
-            if (!(response instanceof MimeResponseSink))
+            if (!(response instanceof MimeResponse))
             {
                 throw new IllegalStateException("MimeResponse is required to create a sink.");
             }

Modified: portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/SimpleReverseProxyPortlet.java
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/SimpleReverseProxyPortlet.java?rev=1621242&r1=1621241&r2=1621242&view=diff
==============================================================================
--- portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/SimpleReverseProxyPortlet.java (original)
+++ portals/applications/webcontent/trunk/portlets/src/main/java/org/apache/portals/applications/webcontent2/portlet/proxy/SimpleReverseProxyPortlet.java Fri Aug 29 03:16:08 2014
@@ -16,23 +16,36 @@
  */
 package org.apache.portals.applications.webcontent2.portlet.proxy;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 import javax.portlet.PortletConfig;
 import javax.portlet.PortletException;
 
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.StringUtils;
 import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.impl.client.HttpClients;
+import org.apache.portals.applications.webcontent2.proxy.ProxyMapping;
 import org.apache.portals.applications.webcontent2.proxy.ProxyMappingRegistry;
 import org.apache.portals.applications.webcontent2.proxy.builder.ProxyServices;
 import org.apache.portals.applications.webcontent2.proxy.impl.DefaultProxyMappingRegistry;
 import org.apache.portals.applications.webcontent2.proxy.impl.DefaultReverseProxyService;
 import org.apache.portals.applications.webcontent2.proxy.impl.ProxyProcessingChain;
 import org.apache.portals.applications.webcontent2.proxy.util.ProxyCommandUtils;
-import org.apache.portals.applications.webcontent2.proxy.util.YamlConfigUtils;
+import org.apache.portals.applications.webcontent2.rewriter.ContentRewriter;
+import org.apache.portals.applications.webcontent2.rewriter.htmlcleaner.DefaultSerializerFactory;
+import org.apache.portals.applications.webcontent2.rewriter.htmlcleaner.HtmlCleanerContentRewriter;
+import org.htmlcleaner.SimpleHtmlSerializer;
+import org.htmlcleaner.TagNodeVisitor;
 
 public class SimpleReverseProxyPortlet extends GenericReverseProxyPortlet
 {
 
-    public static final String MAPPINGS_PARAM_NAME = "mappings";
+    private static final String CONTENT_SELECTOR_PARAM_NAME = "content.selector";
+    private static final String HTML_CLEANER_TRANSFORMATION_PARAM_NAME = "html.cleaner.transformation";
 
     private ProxyMappingRegistry proxyMappingRegistry;
     private HttpClientBuilder httpClientBuilder;
@@ -60,8 +73,7 @@ public class SimpleReverseProxyPortlet e
         if (proxyMappingRegistry == null)
         {
             proxyMappingRegistry = new DefaultProxyMappingRegistry();
-            final String param = getPortletConfig().getInitParameter(MAPPINGS_PARAM_NAME);
-            proxyMappingRegistry.addAllProxyMappings(YamlConfigUtils.loadProxyMappings(param, getPortletContext()));
+            proxyMappingRegistry.addProxyMapping(getProxyMapping());
         }
 
         return proxyMappingRegistry;
@@ -93,4 +105,83 @@ public class SimpleReverseProxyPortlet e
         ProxyCommandUtils.destroyAllCommands(proxyServiceCommand);
         super.destroy();
     }
+
+    protected ProxyMapping getProxyMapping()
+    {
+        PortletAnyProxyMapping portletAnyProxyMapping = new PortletAnyProxyMapping(getPortletConfig());
+        portletAnyProxyMapping.setContentRewriters(getContentRewriters());
+        return portletAnyProxyMapping;
+    }
+
+    protected Map<String, ContentRewriter> getContentRewriters()
+    {
+        Map<String, ContentRewriter> contentRewriters = new HashMap<String, ContentRewriter>();
+
+        DefaultSerializerFactory serializerFactory = new DefaultSerializerFactory();
+        serializerFactory.setSerializerClass(SimpleHtmlSerializer.class);
+
+        HtmlCleanerContentRewriter contentRewriter = new HtmlCleanerContentRewriter();
+        contentRewriter.setSerializerFactory(serializerFactory);
+        contentRewriter.setContentSelector(getContentSelector());
+        contentRewriter.setInnerHtmlOnly(true);
+
+        String [] cleanerTransformations = getCleanerTransformationStringArray();
+
+        if (!ArrayUtils.isEmpty(cleanerTransformations))
+        {
+            contentRewriter.setCleanerTransformationStringArray(cleanerTransformations);
+        }
+
+        List<TagNodeVisitor> tagNodeVisitors = getTagNodeVisitors();
+
+        if (!tagNodeVisitors.isEmpty())
+        {
+            for (TagNodeVisitor visitor : tagNodeVisitors)
+            {
+                contentRewriter.addTagNodeVisitor(visitor);
+            }
+        }
+
+        contentRewriters.put("text/html",contentRewriter);
+
+        return contentRewriters;
+    }
+
+    protected String getContentSelector()
+    {
+        String selector = getPortletConfig().getInitParameter(CONTENT_SELECTOR_PARAM_NAME);
+
+        if (selector == null || StringUtils.isBlank(selector))
+        {
+            return "body";
+        }
+
+        return selector;
+    }
+
+    protected String [] getCleanerTransformationStringArray()
+    {
+        String param = getPortletConfig().getInitParameter(HTML_CLEANER_TRANSFORMATION_PARAM_NAME);
+
+        if (param == null || StringUtils.isBlank(param))
+        {
+            return ArrayUtils.EMPTY_STRING_ARRAY;
+        }
+
+        String [] tokens = StringUtils.split(param, "|");
+
+        for (int i = 0; i < tokens.length; i++)
+        {
+            tokens[i] = StringUtils.trim(tokens[i]);
+        }
+
+        return tokens;
+    }
+
+    protected List<TagNodeVisitor> getTagNodeVisitors()
+    {
+        List<TagNodeVisitor> visitors = new ArrayList<TagNodeVisitor>();
+        visitors.add(new DefaultPortletProxyTagNodeVisitor());
+        return visitors;
+    }
 }

Modified: portals/applications/webcontent/trunk/reverse-proxy/src/main/java/org/apache/portals/applications/webcontent2/proxy/impl/ProxyContext.java
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/reverse-proxy/src/main/java/org/apache/portals/applications/webcontent2/proxy/impl/ProxyContext.java?rev=1621242&r1=1621241&r2=1621242&view=diff
==============================================================================
--- portals/applications/webcontent/trunk/reverse-proxy/src/main/java/org/apache/portals/applications/webcontent2/proxy/impl/ProxyContext.java (original)
+++ portals/applications/webcontent/trunk/reverse-proxy/src/main/java/org/apache/portals/applications/webcontent2/proxy/impl/ProxyContext.java Fri Aug 29 03:16:08 2014
@@ -36,6 +36,23 @@ public class ProxyContext extends Contex
 
     private static final long serialVersionUID = 1L;
 
+    private static ThreadLocal<ProxyContext> tlProxyContext = new ThreadLocal<ProxyContext>();
+
+    public static ProxyContext getCurrentProxyContext()
+    {
+        return tlProxyContext.get();
+    }
+
+    public static void setCurrentProxyContext(ProxyContext proxyContext)
+    {
+        tlProxyContext.set(proxyContext);
+    }
+
+    public static void removeCurrentProxyContext()
+    {
+        tlProxyContext.remove();
+    }
+
     private final RequestContext requestContext;
     private ProxyMappingRegistry proxyMappingRegistry;
     private ProxyMapping resolvedMapping;

Modified: portals/applications/webcontent/trunk/reverse-proxy/src/main/java/org/apache/portals/applications/webcontent2/proxy/impl/ServletRequestContext.java
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/reverse-proxy/src/main/java/org/apache/portals/applications/webcontent2/proxy/impl/ServletRequestContext.java?rev=1621242&r1=1621241&r2=1621242&view=diff
==============================================================================
--- portals/applications/webcontent/trunk/reverse-proxy/src/main/java/org/apache/portals/applications/webcontent2/proxy/impl/ServletRequestContext.java (original)
+++ portals/applications/webcontent/trunk/reverse-proxy/src/main/java/org/apache/portals/applications/webcontent2/proxy/impl/ServletRequestContext.java Fri Aug 29 03:16:08 2014
@@ -42,6 +42,16 @@ public class ServletRequestContext imple
         this.response = response;
     }
 
+    public HttpServletRequest getServletRequest()
+    {
+        return request;
+    }
+
+    public HttpServletResponse getServletResponse()
+    {
+        return response;
+    }
+
     public boolean isSecure()
     {
         return request.isSecure();

Modified: portals/applications/webcontent/trunk/war/src/main/webapp/WEB-INF/portlet.xml
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/war/src/main/webapp/WEB-INF/portlet.xml?rev=1621242&r1=1621241&r2=1621242&view=diff
==============================================================================
--- portals/applications/webcontent/trunk/war/src/main/webapp/WEB-INF/portlet.xml (original)
+++ portals/applications/webcontent/trunk/war/src/main/webapp/WEB-INF/portlet.xml Fri Aug 29 03:16:08 2014
@@ -18,11 +18,13 @@
   xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
   version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">
-  
+
   <portlet>
-    <description>Places an HTML IFrame inside a portlet for easily
+    <description>
+      Places an HTML IFrame inside a portlet for easily
       hosting other web application within a portlet. Sizes of both
-      normal and maximized modes are configurable in edit mode.</description>
+      normal and maximized modes are configurable in edit mode.
+    </description>
     <portlet-name>IFramePortlet2</portlet-name>
     <display-name>IFrame Portlet 2</display-name>
     <portlet-class>
@@ -102,11 +104,13 @@
       </preference>
     </portlet-preferences>
   </portlet>
-  
+
   <portlet>
-    <description>Places an HTML IFrame with reverse proxied url inside a portlet for easily
+    <description>
+      Places an HTML IFrame with reverse proxied url inside a portlet for easily
       hosting other web application within a portlet. Sizes of both
-      normal and maximized modes are configurable in edit mode.</description>
+      normal and maximized modes are configurable in edit mode.
+    </description>
     <portlet-name>ReverseProxyIFramePortlet2</portlet-name>
     <display-name>ReverseProxy IFrame Portlet2</display-name>
     <portlet-class>
@@ -195,12 +199,15 @@
       </preference>
     </portlet-preferences>
   </portlet>
-  
+
   <portlet>
-    <description>Includes the content of another website inside the portal without using frames. All links are rewritten back to the portal to attempt to proxy all content through the portal.</description>        
+    <description>
+      Includes the content of another website inside the portal without using frames.
+      All links are rewritten back to the portal to attempt to proxy all content through the portal.
+    </description>
     <portlet-name>WebContentPortlet2</portlet-name>
     <display-name>WebContent Portlet2</display-name>
-    <portlet-class>org.apache.portals.applications.webcontent2.portlet.WebContentPortlet</portlet-class>        
+    <portlet-class>org.apache.portals.applications.webcontent2.portlet.WebContentPortlet</portlet-class>
     <init-param>
       <name>EditPage</name>
       <value>/WEB-INF/view/edit-wcprefs.vm</value>
@@ -215,7 +222,7 @@
       <portlet-mode>EDIT</portlet-mode>
       <portlet-mode>VIEW</portlet-mode>
     </supports>
-    <supported-locale>en</supported-locale>        
+    <supported-locale>en</supported-locale>
     <portlet-info>
       <title>WebContent Prototype 2</title>
       <short-title>WebContent2</short-title>
@@ -234,9 +241,45 @@
         <name>PROXYPORT</name>
         <value></value>
       </preference>
-    </portlet-preferences>        
+    </portlet-preferences>
   </portlet>
-  
+
+  <portlet>
+    <description>
+      Includes the content of another website inside the portal without using frames.
+      All links are rewritten back to the portal to attempt to proxy all content through the portal.
+    </description>
+    <portlet-name>SimpleReverseProxyPortlet</portlet-name>
+    <display-name>Simple Reverse Proxy Portlet</display-name>
+    <portlet-class>org.apache.portals.applications.webcontent2.portlet.proxy.SimpleReverseProxyPortlet</portlet-class>
+    <init-param>
+      <name>portlet-icon</name>
+      <value>preferences-system-network-proxy.png</value>
+    </init-param>
+    <init-param>
+      <name>content.selector</name>
+      <value>div[id=bodyColumn]</value>
+    </init-param>
+    <expiration-cache>0</expiration-cache>
+    <supports>
+      <mime-type>text/html</mime-type>
+      <portlet-mode>EDIT</portlet-mode>
+      <portlet-mode>VIEW</portlet-mode>
+    </supports>
+    <supported-locale>en</supported-locale>
+    <portlet-info>
+      <title>Simple Reverse Proxy Portlet</title>
+      <short-title>Simple Reverse Proxy Portlet</short-title>
+      <keywords>web,content,webnav,bridge,proxy,rewrite</keywords>
+    </portlet-info>
+    <portlet-preferences>
+      <preference>
+        <name>remote.uri</name>
+        <value>http://portals.apache.org/news.html</value>
+      </preference>
+    </portlet-preferences>
+  </portlet>
+
   <custom-portlet-mode>
     <description>Custom About Mode</description>
     <portlet-mode>about</portlet-mode>
@@ -257,6 +300,6 @@
     <description>Custom Print Mode</description>
     <portlet-mode>print</portlet-mode>
   </custom-portlet-mode>
-  
+
 </portlet-app>
 

Modified: portals/applications/webcontent/trunk/war/src/main/webapp/WEB-INF/psml/test-webcontent2.psml
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/war/src/main/webapp/WEB-INF/psml/test-webcontent2.psml?rev=1621242&r1=1621241&r2=1621242&view=diff
==============================================================================
--- portals/applications/webcontent/trunk/war/src/main/webapp/WEB-INF/psml/test-webcontent2.psml (original)
+++ portals/applications/webcontent/trunk/war/src/main/webapp/WEB-INF/psml/test-webcontent2.psml Fri Aug 29 03:16:08 2014
@@ -29,13 +29,17 @@
             <property name="row" value="1"></property>
             <property name="column" value="0"></property>
         </fragment>
-        <fragment id="tw2-22" type="portlet" name="webcontent2::IFramePortlet2">
+        <fragment id="tw2-31" type="portlet" name="webcontent2::IFramePortlet2">
             <property name="row" value="2"></property>
             <property name="column" value="0"></property>
             <preference name="SRC" readOnly="false">
                 <value>http://www.apache.org/</value>
             </preference>
         </fragment>
+        <fragment id="tw2-41" type="portlet" name="webcontent2::SimpleReverseProxyPortlet">
+            <property name="row" value="3"></property>
+            <property name="column" value="0"></property>
+        </fragment>
     </fragment>
     <defaults></defaults>
 </page>