Author: rwatler
Date: Wed Dec 16 20:22:15 2009
New Revision: 891415

URL: http://svn.apache.org/viewvc?rev=891415&view=rev
Log:
Jetspeed DynamicPage Support - J2-admin Demo Portlet
-----------------------------------------------------------
- added DynamicWebContentPortlet as example DynamicPage 'aware' content portlet
- includes custom URL rewriter, DynamicWebContentRewriter, to support 1:1 
overlayed content and portal URL mappings


Added:
    
portals/jetspeed-2/applications/j2-admin/trunk/src/main/java/org/apache/jetspeed/portlets/content/
    
portals/jetspeed-2/applications/j2-admin/trunk/src/main/java/org/apache/jetspeed/portlets/content/DynamicWebContentPortlet.java
    
portals/jetspeed-2/applications/j2-admin/trunk/src/main/java/org/apache/jetspeed/portlets/content/DynamicWebContentRewriter.java
Modified:
    
portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/WEB-INF/portlet.xml

Added: 
portals/jetspeed-2/applications/j2-admin/trunk/src/main/java/org/apache/jetspeed/portlets/content/DynamicWebContentPortlet.java
URL: 
http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/java/org/apache/jetspeed/portlets/content/DynamicWebContentPortlet.java?rev=891415&view=auto
==============================================================================
--- 
portals/jetspeed-2/applications/j2-admin/trunk/src/main/java/org/apache/jetspeed/portlets/content/DynamicWebContentPortlet.java
 (added)
+++ 
portals/jetspeed-2/applications/j2-admin/trunk/src/main/java/org/apache/jetspeed/portlets/content/DynamicWebContentPortlet.java
 Wed Dec 16 20:22:15 2009
@@ -0,0 +1,172 @@
+/*
+ * 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.jetspeed.portlets.content;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.portlet.ActionRequest;
+import javax.portlet.ActionResponse;
+import javax.portlet.PortletException;
+import javax.portlet.PortletMode;
+import javax.portlet.RenderRequest;
+import javax.portlet.RenderResponse;
+
+import org.apache.jetspeed.request.RequestContext;
+import 
org.apache.portals.applications.webcontent.portlet.WebContentHistoryPage;
+import org.apache.portals.applications.webcontent.portlet.WebContentPortlet;
+import org.apache.portals.applications.webcontent.rewriter.WebContentRewriter;
+import org.apache.portals.messaging.PortletMessaging;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * WebContentPortlet that dynamically adjusts its content url based
+ * on portal request urls. This portlet is designed to work in conjunction
+ * with the DynamicPage PSML and PortalSite component in Jetspeed. 
+ * 
+ * @author <a href="mailto:rwat...@apache.org";>Randy Watler</a>
+ * @version $Id$
+ */
+public class DynamicWebContentPortlet extends WebContentPortlet
+{
+    private final static Logger log = 
LoggerFactory.getLogger(DynamicWebContentPortlet.class);
+
+    /* (non-Javadoc)
+     * @see 
org.apache.portals.applications.webcontent.portlet.WebContentPortlet#processAction(javax.portlet.ActionRequest,
 javax.portlet.ActionResponse)
+     */
+    public void processAction(ActionRequest actionRequest, ActionResponse 
actionResponse) throws PortletException, IOException
+    {
+        // process preferences
+        if (actionRequest.getPortletMode() == PortletMode.EDIT)
+        {
+            processPreferencesAction(actionRequest, actionResponse);
+            return;
+        }
+
+        // extract rewritten action and save in page
+        String webContentURL = 
actionRequest.getParameter(WebContentRewriter.ACTION_PARAMETER_URL);
+        String webContentMethod = 
actionRequest.getParameter(WebContentRewriter.ACTION_PARAMETER_METHOD);
+        Map webContentParams = new HashMap(actionRequest.getParameterMap()) ;
+        webContentParams.remove(WebContentRewriter.ACTION_PARAMETER_URL);
+        webContentParams.remove(WebContentRewriter.ACTION_PARAMETER_METHOD);
+        WebContentHistoryPage webContentPage = new 
WebContentHistoryPage(webContentURL, webContentParams, webContentMethod);
+        PortletMessaging.publish(actionRequest, getClass().getName(), 
webContentPage);        
+    }
+    
+    /* (non-Javadoc)
+     * @see 
org.apache.portals.applications.webcontent.portlet.WebContentPortlet#doView(javax.portlet.RenderRequest,
 javax.portlet.RenderResponse)
+     */
+    public void doView(RenderRequest request, RenderResponse response) throws 
PortletException, IOException
+    {
+        // portal request context
+        RequestContext rc = (RequestContext) 
request.getAttribute(RequestContext.REQUEST_PORTALENV);
+
+        // default page view rendering
+        String viewPage = (String)request.getAttribute(PARAM_VIEW_PAGE);
+        if (viewPage != null)
+        {
+            super.doView(request, response);
+            return;
+        }
+
+        // get source web content URL, parameters, and method to view
+        String sourceURL = null;
+        Map sourceParams = null;
+        boolean sourcePostMethod = false;
+        WebContentHistoryPage webContentPage = 
(WebContentHistoryPage)PortletMessaging.receive(request, getClass().getName());
+        if (webContentPage != null)
+        {
+            // view rewritten action URL page
+            sourceURL = webContentPage.getUrl();
+            sourceParams = webContentPage.getParams();
+            sourcePostMethod = webContentPage.isPost();            
+        }
+        else
+        {
+            // load and validate preferences, (base url and portal base path
+            // should both end in a "/" path separator to ensure that relative
+            // urls in the content resolve predictably)
+            String baseURL = request.getPreferences().getValue("SRC", null);
+            String portalBasePath = 
request.getPreferences().getValue("PORTALPATH", null);
+            if ((baseURL == null) || (portalBasePath == null))
+            {
+                throw new PortletException("Required SRC and PORTALPATH 
preferences not set");
+            }
+            if (!baseURL.endsWith("/"))
+            {
+                baseURL += "/";
+            }
+            if (!portalBasePath.startsWith("/"))
+            {
+                portalBasePath = "/"+portalBasePath;
+            }        
+            if (!portalBasePath.endsWith("/"))
+            {
+                portalBasePath += "/";
+            }        
+            // view content page based on portal request URL
+            String portalRequestPath = rc.getPath();
+            if (!portalRequestPath.startsWith(portalBasePath))
+            {
+                throw new PortletException("Unable to map portal request path: 
"+portalRequestPath+" onto portal base path: "+portalBasePath);
+            }
+            sourceURL = 
baseURL+portalRequestPath.substring(portalBasePath.length());            
+        }
+
+        // get web content
+        byte[] content = null;
+        try
+        {
+            // initialize and lock stateful rewriter
+            String basePortalPath = rc.getPortalURL().getPageBasePath();
+            initializeRewriter(DynamicWebContentRewriter.class);
+            
((DynamicWebContentRewriter)getRewriter()).setBasePortalPath(basePortalPath);
+        
+            // get and rewrite web content
+            if (log.isDebugEnabled())
+            {
+                log.debug("Portal request: "+rc.getPath()+", Web content: 
"+sourceURL);
+            }
+            try
+            {
+                content = doWebContent(sourceURL, sourceParams, 
sourcePostMethod, request, response);
+            }
+            catch (Throwable t)
+            {
+                throw new PortletException("Error retrieveing web content: 
"+t, t);
+            }
+        }
+        finally
+        {
+            // unlock stateful rewriter
+            freeRewriter();
+        }
+
+        // write web content to portlet writer
+        response.setContentType("text/html");
+        PrintWriter writer = response.getWriter();
+        ByteArrayInputStream bais = new ByteArrayInputStream(content);
+        drain(new InputStreamReader(bais, defaultEncoding), writer);
+        bais.close();
+    }
+}

Added: 
portals/jetspeed-2/applications/j2-admin/trunk/src/main/java/org/apache/jetspeed/portlets/content/DynamicWebContentRewriter.java
URL: 
http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/java/org/apache/jetspeed/portlets/content/DynamicWebContentRewriter.java?rev=891415&view=auto
==============================================================================
--- 
portals/jetspeed-2/applications/j2-admin/trunk/src/main/java/org/apache/jetspeed/portlets/content/DynamicWebContentRewriter.java
 (added)
+++ 
portals/jetspeed-2/applications/j2-admin/trunk/src/main/java/org/apache/jetspeed/portlets/content/DynamicWebContentRewriter.java
 Wed Dec 16 20:22:15 2009
@@ -0,0 +1,297 @@
+/*
+ * 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.jetspeed.portlets.content;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+import javax.portlet.PortletURL;
+
+import org.apache.portals.applications.webcontent.rewriter.MutableAttributes;
+import org.apache.portals.applications.webcontent.rewriter.WebContentRewriter;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * WebContentRewriter that overlays page navigation onto portal content paths.
+ * 
+ * @author <a href="mailto:rwat...@apache.org";>Randy Watler</a>
+ * @version $Id$
+ */
+public class DynamicWebContentRewriter extends WebContentRewriter
+{
+    private final static Logger log = 
LoggerFactory.getLogger(DynamicWebContentRewriter.class);
+
+    private final static Pattern ONCLICK_LOCATION_PATTERN = 
Pattern.compile("[.]location *= *'([^']*)'");
+    private final static Pattern STYLE_URL_PATTERN = Pattern.compile("url\\( 
*\"([^\"]*)\" *\\)");
+    
+    protected String basePortalPath;
+    
+    public String getBasePortalPath()
+    {
+        return basePortalPath;
+    }
+
+    public void setBasePortalPath(String basePortalPath)
+    {
+        this.basePortalPath = basePortalPath;
+        if (log.isDebugEnabled())
+        {
+            log.debug("basePortalPath: "+basePortalPath);
+        }
+    }
+        
+    /* (non-Javadoc)
+     * @see 
org.apache.portals.applications.webcontent.rewriter.AbstractRewriter#setBaseUrl(java.lang.String)
+     */
+    public void setBaseUrl(String base)
+    {
+        super.setBaseUrl(base);
+        if (log.isDebugEnabled())
+        {
+            log.debug("baseUrl: "+base);
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see 
org.apache.portals.applications.webcontent.rewriter.WebContentRewriter#setActionURL(javax.portlet.PortletURL)
+     */
+    public void setActionURL(PortletURL action)
+    {
+        super.setActionURL(action);
+        if (log.isDebugEnabled())
+        {
+            log.debug("actionURL: "+action);
+        }
+    }
+    
+    /* (non-Javadoc)
+     * @see 
org.apache.portals.applications.webcontent.rewriter.WebContentRewriter#rewriteUrl(java.lang.String,
 java.lang.String, java.lang.String, 
org.apache.portals.applications.webcontent.rewriter.MutableAttributes)
+     */
+    public String rewriteUrl(String url, String tag, String attribute, 
MutableAttributes otherAttributes)
+    {
+        String rewrittenUrl = url;
+        if (tag.equalsIgnoreCase("A") && attribute.equalsIgnoreCase("href"))
+        {
+            // redirect navigation through portal content urls
+            rewrittenUrl = portalURL(url);
+        }
+        else if (tag.equalsIgnoreCase("FORM") && 
attribute.equalsIgnoreCase("action"))                
+        {
+            // redirect forms through portal as action
+            getActionURL().setParameter(ACTION_PARAMETER_URL, 
webContentURL(url));
+            String httpMethod = otherAttributes.getValue("method");
+            if (httpMethod != null)
+            {
+                getActionURL().setParameter(ACTION_PARAMETER_METHOD, 
httpMethod);
+            }
+            rewrittenUrl = getActionURL().toString();
+        }
+        else if (attribute.equalsIgnoreCase("onclick"))                
+        {
+            // redirect javascript click navigation through portal content urls
+            String javascript = url;
+            StringBuilder rewrittenJavascript = new StringBuilder();
+            int rewrittenIndex = 0;
+            Matcher matcher = ONCLICK_LOCATION_PATTERN.matcher(javascript);
+            while (matcher.find())
+            {
+                
rewrittenJavascript.append(javascript.substring(rewrittenIndex,matcher.start(1)));
+                rewrittenJavascript.append(portalURL(matcher.group(1)));
+                rewrittenIndex = matcher.end(1);
+            }
+            if (rewrittenIndex > 0)
+            {
+                
rewrittenJavascript.append(javascript.substring(rewrittenIndex));
+                rewrittenUrl = rewrittenJavascript.toString();
+            }
+        }
+        else
+        {
+            // access assets directly externally from portal 
+            rewrittenUrl = webContentURL(url);            
+        }
+
+        if (log.isDebugEnabled())
+        {
+            log.debug("rewriteUrl: "+url+" -> "+rewrittenUrl);
+        }
+        return rewrittenUrl;
+    }
+    
+    /* (non-Javadoc)
+     * @see 
org.apache.portals.applications.webcontent.rewriter.BasicRewriter#rewriteText(java.lang.String,
 java.lang.String)
+     */
+    public String rewriteText(String tag, String text)
+    {
+        String rewrittenText = null;
+        if (tag.equalsIgnoreCase("STYLE"))
+        {
+            StringBuilder rewrittenStyle = new StringBuilder();
+            int rewrittenIndex = 0;
+            Matcher matcher = STYLE_URL_PATTERN.matcher(text);
+            while (matcher.find())
+            {
+                
rewrittenStyle.append(text.substring(rewrittenIndex,matcher.start(1)));
+                rewrittenStyle.append(webContentURL(matcher.group(1)));
+                rewrittenIndex = matcher.end(1);
+            }
+            if (rewrittenIndex > 0)
+            {
+                rewrittenStyle.append(text.substring(rewrittenIndex));
+                rewrittenText = rewrittenStyle.toString();
+            }
+        }
+        
+        if (rewrittenText != null)
+        {
+            if (log.isDebugEnabled())
+            {
+                String logText = text.replace('\n', ' ').replace('\r', ' ');
+                String logRewrittenText = rewrittenText.replace('\n', ' 
').replace('\r', ' ');
+                log.debug("rewriteText: "+logText+" -> "+logRewrittenText);
+            }
+        }
+        return rewrittenText;
+    }
+
+    protected String webContentURL(String url)
+    {
+        // form absolute web content URL
+        if (!url.startsWith("http://";) && !url.startsWith("https://";))
+        {
+            if (url.startsWith("/"))
+            {
+                // get site root base url
+                String baseRootUrl = baseRootURL(getBaseUrl());
+                // append site relative url to base url
+                url = baseRootUrl+url.substring(1);
+            }
+            else
+            {
+                // strip "./" prefix from url
+                while (url.startsWith("./"))
+                {
+                    url = url.substring(2);
+                }
+                // get base url 
+                String baseUrl = baseURL(getBaseUrl(), false);
+                // strip "../" prefix from url
+                while (url.startsWith("../"))
+                {
+                    url = url.substring(3);
+                    baseUrl = baseURL(baseUrl, true);
+                }
+                // append relative url to base url
+                url = baseUrl+url;
+            }
+        }
+        return url;
+    }
+
+    protected String portalURL(String url)
+    {
+        // derive content relative url if necessary
+        if (url.startsWith("http://";) || url.startsWith("https://";))
+        {
+            // get base url 
+            String baseUrl = baseURL(getBaseUrl(), false);
+            // strip base url to create relative url
+            if (url.startsWith(baseUrl))
+            {
+                return url.substring(baseUrl.length());
+            }
+            // compute relative url from base if possible
+            String baseRootUrl = baseRootURL(getBaseUrl());
+            if (url.startsWith(baseRootUrl))
+            {
+                url = url.substring(baseRootUrl.length());
+                String remainingBasePath = 
baseUrl.substring(baseRootUrl.length());
+                int remainingBasePathIndex = remainingBasePath.indexOf('/');
+                while (remainingBasePathIndex != -1)
+                {
+                    url = "../"+url;
+                    remainingBasePathIndex = remainingBasePath.indexOf('/', 
remainingBasePathIndex+1);
+                }
+            }
+        }
+        else if (url.startsWith("/"))
+        {
+            // get base url 
+            String baseUrl = baseURL(getBaseUrl(), false);
+            // compute relative url from root relative url
+            String baseRootUrl = baseRootURL(getBaseUrl());
+            url = url.substring(1);
+            String remainingBasePath = baseUrl.substring(baseRootUrl.length());
+            int remainingBasePathIndex = remainingBasePath.indexOf('/');
+            while (remainingBasePathIndex != -1)
+            {
+                url = "../"+url;
+                remainingBasePathIndex = remainingBasePath.indexOf('/', 
remainingBasePathIndex+1);
+            }
+        }
+        else
+        {
+            // strip "./" prefix from url
+            while (url.startsWith("./"))
+            {
+                url = url.substring(2);
+            }            
+        }
+        // make portal site relative url from content relative urls
+        if (!url.startsWith("http://";) && !url.startsWith("https://";))
+        {
+            String basePortalPath = getBasePortalPath();
+            if (!basePortalPath.endsWith("/"))
+            {
+                basePortalPath += "/";
+            }
+            url = basePortalPath+url;
+        }
+        return url;
+    }
+    
+    protected static String baseURL(String baseUrl, boolean force)
+    {
+        boolean folderUrl = baseUrl.endsWith("/");
+        if (!folderUrl || force)
+        {
+            int baseRootUrlIndex = baseUrl.indexOf('/');
+            baseRootUrlIndex = baseUrl.indexOf('/', baseRootUrlIndex+1);
+            baseRootUrlIndex = baseUrl.indexOf('/', baseRootUrlIndex+1);
+            int baseUrlIndex = (folderUrl ? baseUrl.lastIndexOf('/', 
baseUrl.length()-2) : baseUrl.lastIndexOf('/'));
+            if ((baseRootUrlIndex != -1) || (baseUrlIndex > baseUrlIndex))
+            {
+                baseUrl = baseUrl.substring(0, baseUrlIndex+1);
+            }
+            else if (!folderUrl)
+            {
+                baseUrl += "/";
+            }
+        }
+        return baseUrl;
+    }
+
+    protected static String baseRootURL(String baseUrl)
+    {
+        int baseRootUrlIndex = baseUrl.indexOf('/');
+        baseRootUrlIndex = baseUrl.indexOf('/', baseRootUrlIndex+1);
+        baseRootUrlIndex = baseUrl.indexOf('/', baseRootUrlIndex+1);
+        return ((baseRootUrlIndex != -1) ? baseUrl : baseUrl.substring(0, 
baseRootUrlIndex))+"/";
+    }
+}

Modified: 
portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/WEB-INF/portlet.xml
URL: 
http://svn.apache.org/viewvc/portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/WEB-INF/portlet.xml?rev=891415&r1=891414&r2=891415&view=diff
==============================================================================
--- 
portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/WEB-INF/portlet.xml
 (original)
+++ 
portals/jetspeed-2/applications/j2-admin/trunk/src/main/webapp/WEB-INF/portlet.xml
 Wed Dec 16 20:22:15 2009
@@ -2314,6 +2314,51 @@
     </portlet-info>
   </portlet>
       
+  <portlet>
+    <description>Portal DynamicPage enabled content portlet that displays 
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>DynamicWebContentPortlet</portlet-name>
+    <display-name>Portal DynamicPage WebContent Portlet</display-name>
+    
<portlet-class>org.apache.jetspeed.portlets.content.DynamicWebContentPortlet</portlet-class>
        
+    <init-param>
+      <name>EditPage</name>
+      <value>/WEB-INF/view/edit-prefs.vm</value>
+    </init-param>
+    <init-param>
+      <name>portlet-icon</name>
+      <value>preferences-system-network-proxy.png</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>Portal DynamicPage WebContent Portlet</title>
+      <short-title>DynamicWebContent</short-title>
+      <keywords>web,content,webnav,bridge,proxy,rewrite,dpsml</keywords>
+    </portlet-info>
+    <portlet-preferences>
+      <preference>
+        <name>SRC</name>
+        <value>http://portals.apache.org/</value>
+      </preference>
+      <preference>
+        <name>PORTALPATH</name>
+        <value>/content/</value>
+      </preference>
+      <preference>
+        <name>PROXYHOST</name>
+        <value></value>
+      </preference>
+      <preference>
+        <name>PROXYPORT</name>
+        <value></value>
+      </preference>
+    </portlet-preferences>        
+  </portlet>
+
   <custom-portlet-mode>
     <description>a Custom Config Mode</description>            
     <portlet-mode>config</portlet-mode>



---------------------------------------------------------------------
To unsubscribe, e-mail: jetspeed-dev-unsubscr...@portals.apache.org
For additional commands, e-mail: jetspeed-dev-h...@portals.apache.org

Reply via email to