portals-jetspeed-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From smi...@apache.org
Subject svn commit: r540314 - in /portals/jetspeed-2/trunk: components/portal/src/java/org/apache/jetspeed/container/ components/portal/src/java/org/apache/jetspeed/container/url/impl/ components/portal/src/java/org/apache/jetspeed/desktop/impl/ jetspeed-api/s...
Date Mon, 21 May 2007 21:51:54 GMT
Author: smilek
Date: Mon May 21 14:51:53 2007
New Revision: 540314

URL: http://svn.apache.org/viewvc?view=rev&rev=540314
Log:
(JS2-696 and JS2-694) For desktop only, changed values returned by createActionURL and createRenderURL
to be regular urls (instead of 'javascript:doRender()/doAction()' statement). Added desktop
/render pipeline, which is equivalent to /portlet pipeline except for the addition of the
DesktopEncoderRedirectValveImpl (used by the /render pipeline (desktop-render-pipeline) to
allow render requests that are not initiated via desktop javascript code to result in a page
level navigation to the /desktop pipeline with the correct portlet rendering indicated in
the original url).

Added:
    portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/desktop/impl/DesktopEncoderRedirectValveImpl.java
Modified:
    portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/container/DesktopPortletContainerImpl.java
    portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/container/url/impl/DesktopEncodingPortalURL.java
    portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/container/url/impl/PortalURLValveImpl.java
    portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/desktop/JetspeedDesktop.java

Modified: portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/container/DesktopPortletContainerImpl.java
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/container/DesktopPortletContainerImpl.java?view=diff&rev=540314&r1=540313&r2=540314
==============================================================================
--- portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/container/DesktopPortletContainerImpl.java
(original)
+++ portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/container/DesktopPortletContainerImpl.java
Mon May 21 14:51:53 2007
@@ -32,17 +32,50 @@
 import org.apache.pluto.services.information.InformationProviderAccess;
 import org.apache.pluto.services.information.PortletURLProvider;
 
+import org.apache.jetspeed.desktop.JetspeedDesktop;
+
 /**
- * Desktop Portlet Container implementation. This implementation does not
- * redirect, but instead returns back the 'redirect' URL in the response to the
- * Ajax client for client-side aggregation.
+ * Desktop Portlet Container implementation. This implementation 
+ * redirects only if the query paramater encoder=desktop is NOT specified.
+ * When the encoder=desktop parameter is specified, the 'redirect' URL 
+ * is returned in the response body for use by desktop javascript code.
  * 
  * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
  * @version $Id: $
  */
-public class DesktopPortletContainerImpl extends PortletContainerImpl implements
-        PortletContainer
+public class DesktopPortletContainerImpl extends PortletContainerImpl implements PortletContainer
 {
+    private String desktopPipelinePath = null;
+    private String desktopActionPipelinePath = null;
+    private String desktopRenderPipelinePath = null;
+    
+    public DesktopPortletContainerImpl( String desktopPipelinePath, String desktopActionPipelinePath,
String desktopRenderPipelinePath )
+    {
+        if ( desktopPipelinePath == null || desktopPipelinePath.length() == 0 )
+            desktopPipelinePath = JetspeedDesktop.DEFAULT_DESKTOP_PIPELINE_PATH;
+        if ( desktopPipelinePath.charAt( 0 ) != '/' )
+            desktopPipelinePath = "/" + desktopPipelinePath;
+        if ( desktopPipelinePath.charAt( desktopPipelinePath.length() -1 ) != '/' )
+            desktopPipelinePath = desktopPipelinePath + "/";
+        
+        if ( desktopActionPipelinePath == null || desktopActionPipelinePath.length() == 0
)
+            desktopActionPipelinePath = JetspeedDesktop.DEFAULT_DESKTOP_ACTION_PIPELINE_PATH;
+        if ( desktopActionPipelinePath.charAt( 0 ) != '/' )
+            desktopActionPipelinePath = "/" + desktopActionPipelinePath;
+        if ( desktopActionPipelinePath.charAt( desktopActionPipelinePath.length() -1 ) !=
'/' )
+            desktopActionPipelinePath = desktopActionPipelinePath + "/";
+
+        if ( desktopRenderPipelinePath == null || desktopRenderPipelinePath.length() == 0
)
+            desktopRenderPipelinePath = JetspeedDesktop.DEFAULT_DESKTOP_RENDER_PIPELINE_PATH;
+        if ( desktopRenderPipelinePath.charAt( 0 ) != '/' )
+            desktopRenderPipelinePath = "/" + desktopRenderPipelinePath;
+        if ( desktopRenderPipelinePath.charAt( desktopRenderPipelinePath.length() -1 ) !=
'/' )
+            desktopRenderPipelinePath = desktopRenderPipelinePath + "/";
+        
+        this.desktopPipelinePath = desktopPipelinePath;
+        this.desktopActionPipelinePath = desktopActionPipelinePath;
+        this.desktopRenderPipelinePath = desktopRenderPipelinePath;
+    }
 
     /**
      * This redirect does not redirect, instead returns the redirect URL in the response
@@ -111,10 +144,21 @@
             redirectResponse = (javax.servlet.http.HttpServletResponse) ((javax.servlet.http.HttpServletResponseWrapper)
redirectResponse)
                     .getResponse();
         }
-        //redirectResponse.sendRedirect(location);
-        location = location.replaceAll("/action/", "/portlet/");
+
+        String encoding = servletRequest.getParameter( JetspeedDesktop.DESKTOP_ENCODER_REQUEST_PARAMETER
);
+        if ( encoding != null && encoding.equals( JetspeedDesktop.DESKTOP_ENCODER_REQUEST_PARAMETER_VALUE
) )
+        {
+            location = location.replaceAll( this.desktopActionPipelinePath, this.desktopRenderPipelinePath
);
+            redirectResponse.getWriter().print( location );
+        }
+        else
+        {
+            location = location.replaceAll( this.desktopActionPipelinePath, this.desktopPipelinePath
);
+            location = location.replaceAll( this.desktopRenderPipelinePath, this.desktopPipelinePath);
+            redirectResponse.sendRedirect(location);
+        }
         // System.out.println("+++ >>>> location is " + location);
-        redirectResponse.getWriter().print(location);
+        
     }
 
 }

Modified: portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/container/url/impl/DesktopEncodingPortalURL.java
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/container/url/impl/DesktopEncodingPortalURL.java?view=diff&rev=540314&r1=540313&r2=540314
==============================================================================
--- portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/container/url/impl/DesktopEncodingPortalURL.java
(original)
+++ portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/container/url/impl/DesktopEncodingPortalURL.java
Mon May 21 14:51:53 2007
@@ -27,53 +27,85 @@
 import org.apache.jetspeed.PortalContext;
 import org.apache.jetspeed.container.state.NavigationalState;
 import org.apache.jetspeed.container.url.BasePortalURL;
+import org.apache.jetspeed.desktop.JetspeedDesktop;
+import org.apache.jetspeed.om.common.portlet.MutablePortletApplication;
 import org.apache.pluto.om.window.PortletWindow;
+import org.apache.pluto.om.entity.PortletEntity;
+import org.apache.pluto.om.portlet.PortletDefinition;
 
 /**
- * DesktopEncodingPortalURL encodes URLs as javascript calls 
- * The signature for the javascript call is based on teh constructor argument <code>javascriptDoRender</code>
- * The script method requires two parameters:
- *   1. URL the portlet pipeline URL
- *   2. the entity id of the portlet to render
- * Example URL for a javascript method doRender:  <code>doRender("http://localhost/jetspeed/portlet",
"33")</code>
- * *
+ * DesktopEncodingPortalURL encodes action URLs to target desktop specific /action pipeline,
+ * and render URLs to target desktop specific /render pipeline
+ * 
+ * The query parameters "entity" and "portlet" are added to each url. These parameters are
needed in a /render
+ * request and are used by the desktop javascript code for both /render and /action requests.
+ * 
  * @author <a href="mailto:ate@apache.org">Ate Douma</a>
  * @version $Id: PathInfoEncodingPortalURL.java 367856 2006-01-11 01:04:09Z taylor $
  */
 public class DesktopEncodingPortalURL extends AbstractPortalURL
 {
-    protected final String javascriptDoRender;
-    protected final String javascriptDoAction;    
-    protected String baseActionPath;;
+    private String baseActionPath = null;
+    private String baseRenderPath = null;
     
-    public DesktopEncodingPortalURL(NavigationalState navState, PortalContext portalContext,
String javascriptDoRender, String javascriptDoAction, BasePortalURL base)
+    private String desktopActionPipelinePath = null;
+    private String desktopRenderPipelinePath = null;
+    
+    
+    public DesktopEncodingPortalURL(NavigationalState navState, PortalContext portalContext,
String desktopRenderPipelinePath, String desktopActionPipelinePath)
     {
-        super(navState, portalContext, base);
-        this.javascriptDoRender = javascriptDoRender;
-        this.javascriptDoAction = javascriptDoAction;        
+        super(navState, portalContext);
+        initializePipelinePaths( desktopRenderPipelinePath, desktopActionPipelinePath );
     }
-
-    public DesktopEncodingPortalURL(NavigationalState navState, PortalContext portalContext,
String javascriptDoRender, String javascriptDoAction)
+    
+    public DesktopEncodingPortalURL(NavigationalState navState, PortalContext portalContext,
String desktopRenderPipelinePath, String desktopActionPipelinePath, BasePortalURL base)
     {
-        super(navState, portalContext);
-        this.javascriptDoRender = javascriptDoRender;                
-        this.javascriptDoAction = javascriptDoAction;
+        super(navState, portalContext, base);
+        initializePipelinePaths( desktopRenderPipelinePath, desktopActionPipelinePath );
     }
 
     public DesktopEncodingPortalURL(String characterEncoding, NavigationalState navState,
PortalContext portalContext)
     {
         super(characterEncoding, navState, portalContext);
-        this.javascriptDoRender = null;
-        this.javascriptDoAction = null;
+        initializePipelinePaths( null, null );
     }
 
     public DesktopEncodingPortalURL(HttpServletRequest request, String characterEncoding,
NavigationalState navState, PortalContext portalContext)
     {
         super(request, characterEncoding, navState, portalContext);
-        this.javascriptDoRender = null;
-        this.javascriptDoAction = null;
+        initializePipelinePaths( null, null );
+    }
+    
+    private void initializePipelinePaths( String desktopRenderPipelinePath, String desktopActionPipelinePath
)
+    {
+        if ( desktopActionPipelinePath == null || desktopActionPipelinePath.length() == 0
)
+            desktopActionPipelinePath = JetspeedDesktop.DEFAULT_DESKTOP_ACTION_PIPELINE_PATH;
+        if ( desktopActionPipelinePath.charAt( 0 ) != '/' )
+            desktopActionPipelinePath = "/" + desktopActionPipelinePath;
+        if ( desktopActionPipelinePath.length() > 1 && desktopActionPipelinePath.charAt(
desktopActionPipelinePath.length() -1 ) == '/' )
+            desktopActionPipelinePath = desktopActionPipelinePath.substring( 0, desktopActionPipelinePath.length()
-1 );
+
+        if ( desktopRenderPipelinePath == null || desktopRenderPipelinePath.length() == 0
)
+            desktopRenderPipelinePath = JetspeedDesktop.DEFAULT_DESKTOP_RENDER_PIPELINE_PATH;
+        if ( desktopRenderPipelinePath.charAt( 0 ) != '/' )
+            desktopRenderPipelinePath = "/" + desktopRenderPipelinePath;
+        if ( desktopRenderPipelinePath.length() > 1 && desktopRenderPipelinePath.charAt(
desktopRenderPipelinePath.length() -1 ) == '/' )
+            desktopRenderPipelinePath = desktopRenderPipelinePath.substring( 0, desktopRenderPipelinePath.length()
-1 );
+        
+        this.desktopRenderPipelinePath = desktopRenderPipelinePath;
+        this.desktopActionPipelinePath = desktopActionPipelinePath;        
     }
 
+    protected void decodeBasePath(HttpServletRequest request)
+    {
+        super.decodeBasePath(request);
+        if ( this.baseActionPath == null )
+        {
+            this.baseActionPath = contextPath + this.desktopActionPipelinePath;
+            this.baseRenderPath = contextPath + this.desktopRenderPipelinePath;
+        }
+    }
+    
     protected void decodePathAndNavigationalState(HttpServletRequest request)
     {
         String path = null;
@@ -125,20 +157,6 @@
     protected String createPortletURL(String encodedNavState, boolean secure, PortletWindow
window, boolean action)
     {   
         StringBuffer buffer = new StringBuffer("");
-        if (action)
-        {
-            if (this.javascriptDoAction != null)
-            {
-                buffer.append(this.javascriptDoAction + "(&quot;");
-            }            
-        }
-        else
-        {
-            if (this.javascriptDoRender != null)
-            {
-                buffer.append(this.javascriptDoRender + "(&quot;");
-            }            
-        }   
         buffer.append(getBaseURL(secure));
         if (action)
         {
@@ -146,7 +164,7 @@
         }
         else
         {
-            buffer.append(getBasePath());            
+            buffer.append(this.baseRenderPath);        
         }            
         if ( encodedNavState != null )
         {
@@ -159,33 +177,14 @@
         {
             buffer.append(getPath());
         }
-        if (action)
-        {
-            if (this.javascriptDoAction != null)            
-            {
-                if (window != null)
-                {
-                    buffer.append("&quot;,&quot;");
-                    buffer.append(window.getPortletEntity().getId());
-                    buffer.append("&quot;");                
-                }
-                buffer.append(")");
-            }
-        }
-        else
-        {
-            if (this.javascriptDoRender != null)            
-            {
-                if (window != null)
-                {
-                    buffer.append("&quot;,&quot;");
-                    buffer.append(window.getPortletEntity().getId());
-                    buffer.append("&quot;");                
-                }
-                buffer.append(")");
-            }            
-        }
-        //System.out.println("*** " + buffer.toString());
+        PortletEntity pe = window.getPortletEntity();
+        buffer.append( "?entity=" ).append( pe.getId() );
+        
+        PortletDefinition portlet = pe.getPortletDefinition();
+        MutablePortletApplication app = (MutablePortletApplication)portlet.getPortletApplicationDefinition();
+        String uniqueName = app.getName() + "::" + portlet.getName();
+        buffer.append( "&portlet=" ).append( uniqueName );
+
         return buffer.toString();
     }        
     
@@ -202,12 +201,5 @@
             // to keep the compiler happy
             return null;
         }
-    }
-    
-    protected void decodeBasePath(HttpServletRequest request)
-    {
-        super.decodeBasePath(request);
-        this.baseActionPath = contextPath + "/action";
-    }
-    
+    }    
 }

Modified: portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/container/url/impl/PortalURLValveImpl.java
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/container/url/impl/PortalURLValveImpl.java?view=diff&rev=540314&r1=540313&r2=540314
==============================================================================
--- portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/container/url/impl/PortalURLValveImpl.java
(original)
+++ portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/container/url/impl/PortalURLValveImpl.java
Mon May 21 14:51:53 2007
@@ -22,6 +22,7 @@
 import org.apache.jetspeed.pipeline.valve.AbstractValve;
 import org.apache.jetspeed.pipeline.valve.ValveContext;
 import org.apache.jetspeed.request.RequestContext;
+import org.apache.jetspeed.desktop.JetspeedDesktop;
 
 /**
  * Creates the PortalURL for the current Request
@@ -45,8 +46,8 @@
         {  
             if ( request.getPortalURL() == null )
             {
-                String encoding = request.getRequestParameter("encoder");
-                if (encoding != null && encoding.equals("desktop"))
+                String encoding = request.getRequestParameter(JetspeedDesktop.DESKTOP_ENCODER_REQUEST_PARAMETER);
+                if (encoding != null && encoding.equals(JetspeedDesktop.DESKTOP_ENCODER_REQUEST_PARAMETER_VALUE))
                 {
                     request.setPortalURL(navComponent.createDesktopURL(request.getRequest(),
request.getCharacterEncoding()));
                 }

Added: portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/desktop/impl/DesktopEncoderRedirectValveImpl.java
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/desktop/impl/DesktopEncoderRedirectValveImpl.java?view=auto&rev=540314
==============================================================================
--- portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/desktop/impl/DesktopEncoderRedirectValveImpl.java
(added)
+++ portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/desktop/impl/DesktopEncoderRedirectValveImpl.java
Mon May 21 14:51:53 2007
@@ -0,0 +1,112 @@
+/*
+ * 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.desktop.impl;
+
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jetspeed.desktop.JetspeedDesktop;
+import org.apache.jetspeed.pipeline.PipelineException;
+import org.apache.jetspeed.pipeline.valve.AbstractValve;
+import org.apache.jetspeed.pipeline.valve.ValveContext;
+import org.apache.jetspeed.request.RequestContext;
+
+/**
+ * DesktopEncoderRedirect Valve
+ * 
+ * if request parameter encoder=desktop is NOT defined,
+ *    redirect to same url with /desktop pipeline,
+ * otherwise,
+ *    just invoke next valve
+ * 
+ * Used by the /render pipeline (desktop-render-pipeline) to allow
+ * render requests that are not initiated via desktop javascript code to result
+ * in a page level navigation to the /desktop pipeline with the correct portlet rendering
+ * indicated in the original url. The encoder=desktop request parameter
+ * is used by desktop javascript code to indicate that the request is an "official"
+ * desktop ajax request. 
+ *
+ * @author <a href="mailto:smilek@apache.org">Steve Milek</a>
+ * @version $Id: $
+ */
+public class DesktopEncoderRedirectValveImpl extends AbstractValve
+{
+    protected Log log = LogFactory.getLog(DesktopEncoderRedirectValveImpl.class);
+    
+    private String desktopPipelinePath = null;
+    private String desktopRenderPipelinePath = null;
+    
+    public DesktopEncoderRedirectValveImpl( String desktopPipelinePath, String desktopRenderPipelinePath
)
+    {
+        if ( desktopPipelinePath == null || desktopPipelinePath.length() == 0 )
+            desktopPipelinePath = JetspeedDesktop.DEFAULT_DESKTOP_PIPELINE_PATH;
+        if ( desktopPipelinePath.charAt( 0 ) != '/' )
+            desktopPipelinePath = "/" + desktopPipelinePath;
+        if ( desktopPipelinePath.charAt( desktopPipelinePath.length() -1 ) != '/' )
+            desktopPipelinePath = desktopPipelinePath + "/";
+
+        if ( desktopRenderPipelinePath == null || desktopRenderPipelinePath.length() == 0
)
+            desktopRenderPipelinePath = JetspeedDesktop.DEFAULT_DESKTOP_RENDER_PIPELINE_PATH;
+        if ( desktopRenderPipelinePath.charAt( 0 ) != '/' )
+            desktopRenderPipelinePath = "/" + desktopRenderPipelinePath;
+        if ( desktopRenderPipelinePath.charAt( desktopRenderPipelinePath.length() -1 ) !=
'/' )
+            desktopRenderPipelinePath = desktopRenderPipelinePath + "/";
+        
+        this.desktopPipelinePath = desktopPipelinePath;
+        this.desktopRenderPipelinePath = desktopRenderPipelinePath;
+    }
+        
+    public void invoke( RequestContext request, ValveContext context )
+        throws PipelineException
+    {
+        try
+        {  
+            if ( request.getPortalURL() == null )
+            {
+                String encoding = request.getRequestParameter(JetspeedDesktop.DESKTOP_ENCODER_REQUEST_PARAMETER);
+                if (encoding == null || ! encoding.equals(JetspeedDesktop.DESKTOP_ENCODER_REQUEST_PARAMETER_VALUE))
+                {
+                    // redirect to page url with render encoding
+                    try 
+                    {
+                        String queryString = request.getRequest().getQueryString();
+                        String location = request.getRequest().getRequestURI();
+                        if ( queryString != null && queryString.length() > 0 )
+                            location += "?" + queryString;
+                        location = location.replaceAll( this.desktopRenderPipelinePath, this.desktopPipelinePath
);
+                        //log.info( "DesktopEncoderRedirectValveImpl redirecting request-uri="
+ request.getRequest().getRequestURI() + " location=" + location );
+                        request.getResponse().sendRedirect( location );
+                    }
+                    catch (IOException ioe){}
+                    return;
+                }                
+            }
+        }
+        catch (Exception e)
+        {
+            throw new PipelineException(e);
+        }
+        // Pass control to the next Valve in the Pipeline
+        context.invokeNext( request );
+    }
+
+    public String toString()
+    {
+        return "DesktopValve";
+    }
+}

Modified: portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/desktop/JetspeedDesktop.java
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/desktop/JetspeedDesktop.java?view=diff&rev=540314&r1=540313&r2=540314
==============================================================================
--- portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/desktop/JetspeedDesktop.java
(original)
+++ portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/desktop/JetspeedDesktop.java
Mon May 21 14:51:53 2007
@@ -28,6 +28,14 @@
 public interface JetspeedDesktop 
 {
     String DESKTOP_ENABLED_REQUEST_ATTRIBUTE = "desktop.enabled";
+    
+    String DESKTOP_ENCODER_REQUEST_PARAMETER = "encoder";
+    String DESKTOP_ENCODER_REQUEST_PARAMETER_VALUE = "desktop";
+    
+    String DEFAULT_DESKTOP_PIPELINE_PATH = "/desktop";
+    String DEFAULT_DESKTOP_ACTION_PIPELINE_PATH = "/action";
+    String DEFAULT_DESKTOP_RENDER_PIPELINE_PATH = "/render";
+    
 
     /**
      * Render a desktop theme.



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


Mime
View raw message