portals-pluto-scm mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From msnickl...@apache.org
Subject [10/13] portals-pluto git commit: Completed implementation of dynamic page resources for Pluto. You can now define page resources in the pluto-portal-driver-config.xml file, along with default resources to be added to each page. Each page can individuall
Date Fri, 13 May 2016 11:07:02 GMT
Completed implementation of dynamic page resources for Pluto. You can now
define page resources in the pluto-portal-driver-config.xml file, along with
default resources to be added to each page. Each page can individually
override or add resources.

The base style sheets and JavaScript files that were previously hard-coded
into the main rendering JSP are now handled as dynamic resources that can be
changed on a per-page basis.

The changes are backward compatible, so that older driver config files that
do not declare resources will continue to work.

The next step will be to add page resources specified as portlet
dependencies.


Project: http://git-wip-us.apache.org/repos/asf/portals-pluto/repo
Commit: http://git-wip-us.apache.org/repos/asf/portals-pluto/commit/0c9aec76
Tree: http://git-wip-us.apache.org/repos/asf/portals-pluto/tree/0c9aec76
Diff: http://git-wip-us.apache.org/repos/asf/portals-pluto/diff/0c9aec76

Branch: refs/heads/master
Commit: 0c9aec76f2bbe95661ee7c2e830c07136b764ca2
Parents: ad9d72c
Author: Scott Nicklous <msnicklous@apache.org>
Authored: Thu May 12 17:04:55 2016 +0200
Committer: Scott Nicklous <msnicklous@apache.org>
Committed: Fri May 13 06:53:36 2016 +0200

----------------------------------------------------------------------
 .../pluto/driver/PortalDriverServlet.java       |  17 +-
 .../driver/services/portal/PageResourceId.java  | 149 ++++++++++--
 .../driver/services/portal/PageResources.java   | 232 +++++++++++++++++--
 .../resources/pluto-portal-driver-config.xml    |  24 +-
 4 files changed, 373 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0c9aec76/pluto-portal-driver/src/main/java/org/apache/pluto/driver/PortalDriverServlet.java
----------------------------------------------------------------------
diff --git a/pluto-portal-driver/src/main/java/org/apache/pluto/driver/PortalDriverServlet.java
b/pluto-portal-driver/src/main/java/org/apache/pluto/driver/PortalDriverServlet.java
index 2de302a..b49c8e6 100644
--- a/pluto-portal-driver/src/main/java/org/apache/pluto/driver/PortalDriverServlet.java
+++ b/pluto-portal-driver/src/main/java/org/apache/pluto/driver/PortalDriverServlet.java
@@ -17,7 +17,6 @@
 package org.apache.pluto.driver;
 
 import java.io.IOException;
-import java.io.PrintWriter;
 import java.io.Writer;
 import java.util.ArrayList;
 import java.util.List;
@@ -25,7 +24,6 @@ import java.util.Map;
 
 import javax.portlet.PortletException;
 import javax.portlet.PortletRequest;
-import javax.servlet.AsyncContext;
 import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
@@ -37,7 +35,6 @@ import javax.servlet.http.HttpServletResponse;
 import org.apache.pluto.container.HeaderData;
 import org.apache.pluto.container.PortletContainer;
 import org.apache.pluto.container.PortletContainerException;
-import org.apache.pluto.container.PortletInvokerService;
 import org.apache.pluto.container.om.portlet.ContainerRuntimeOption;
 import org.apache.pluto.container.om.portlet.PortletDefinition;
 import org.apache.pluto.driver.config.DriverConfiguration;
@@ -317,15 +314,25 @@ public class PortalDriverServlet extends HttpServlet {
       }
 
       // Set the header section markup provided by the portlets as an attribute
+      // The main rendering JSP uses this when rendering the head section.
       req.setAttribute(AttributeKeys.HEAD_SECTION_MARKUP, markup.toString());
       
       // Now generate the markup for the configured page resources
       markup.setLength(0);
       PageResources pr = dc.getRenderConfigService().getPageResources();
-      List<PageResourceId> deps = dc.getRenderConfigService().getDefaultPageDependencies();
+      
+      // start with the default page resources
+      List<PageResourceId> deps = new ArrayList<PageResourceId>(
+            dc.getRenderConfigService().getDefaultPageDependencies());
+      
+      // add in the page-specific resources
+      List<PageResourceId> pagedeps = purl.getPageConfig(req.getServletContext()).getPageResources();
+      deps.addAll(pagedeps);
+      
+      // Set the markup resulting from the specified page resources as an attribute
+      // The main rendering JSP uses this when rendering the head section.
       markup.append(pr.getMarkup(deps, req.getContextPath()));
       req.setAttribute(AttributeKeys.DYNAMIC_PAGE_RESOURCES, markup.toString());
-      
 
       return;
    }

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0c9aec76/pluto-portal-driver/src/main/java/org/apache/pluto/driver/services/portal/PageResourceId.java
----------------------------------------------------------------------
diff --git a/pluto-portal-driver/src/main/java/org/apache/pluto/driver/services/portal/PageResourceId.java
b/pluto-portal-driver/src/main/java/org/apache/pluto/driver/services/portal/PageResourceId.java
index 42aec3f..2ed835e 100644
--- a/pluto-portal-driver/src/main/java/org/apache/pluto/driver/services/portal/PageResourceId.java
+++ b/pluto-portal-driver/src/main/java/org/apache/pluto/driver/services/portal/PageResourceId.java
@@ -16,69 +16,96 @@
  *  under the License.
  */
 
-
 package org.apache.pluto.driver.services.portal;
 
 /**
  * Contains identification data for a page resource.
  * 
  * @author Scott Nicklous
- *
+ * 
  */
-public class PageResourceId {
-   
+public class PageResourceId implements Comparable<PageResourceId> {
+
    private String name;
    private String scope;
    private String version;
-   
+
    public PageResourceId(String name, String scope, String version) {
       this.name = name;
       this.scope = scope;
       this.version = version;
    }
-   
+
    /**
     * @return the name
     */
    public String getName() {
       return name;
    }
-   
+
    /**
-    * @param name the name to set
+    * @param name
+    *           the name to set
     */
    public void setName(String name) {
       this.name = name;
    }
-   
+
    /**
     * @return the scope
     */
    public String getScope() {
       return scope;
    }
-   
+
    /**
-    * @param scope the scope to set
+    * @param scope
+    *           the scope to set
     */
    public void setScope(String library) {
       this.scope = library;
    }
-   
+
    /**
     * @return the version
     */
    public String getVersion() {
       return version;
    }
-   
+
    /**
-    * @param version the version to set
+    * @param version
+    *           the version to set
     */
    public void setVersion(String version) {
       this.version = version;
    }
-   
+
+   public boolean resourceMatches(PageResourceId other) {
+      if (this == other) {
+         return true;
+      }
+      if (other == null) {
+         return false;
+      }
+      if (scope == null) {
+         if (other.scope != null) {
+            return false;
+         }
+      } else if (!scope.equals(other.scope)) {
+         return false;
+      }
+      if (name == null) {
+         if (other.name != null) {
+            return false;
+         }
+      } else if (!name.equals(other.name)) {
+         return false;
+      }
+
+      return true;
+   }
+
    @Override
    public String toString() {
       StringBuilder txt = new StringBuilder(128);
@@ -87,8 +114,10 @@ public class PageResourceId {
       txt.append(", Version: ").append(version);
       return txt.toString();
    }
-   
-   /* (non-Javadoc)
+
+   /*
+    * (non-Javadoc)
+    * 
     * @see java.lang.Object#hashCode()
     */
    @Override
@@ -100,8 +129,10 @@ public class PageResourceId {
       result = prime * result + ((version == null) ? 0 : version.hashCode());
       return result;
    }
-   
-   /* (non-Javadoc)
+
+   /*
+    * (non-Javadoc)
+    * 
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
@@ -140,4 +171,84 @@ public class PageResourceId {
       return true;
    }
 
+   // for ordering IDs according to version
+   @Override
+   public int compareTo(PageResourceId id) {
+      if (!equals(id)) {
+         if (id == null) {
+            return 1;
+         }
+         if (scope == null) {
+            if (id.scope != null) {
+               return -1;
+            }
+         } else if (!scope.equals(id.scope)) {
+            return scope.compareTo(id.scope);
+         }
+         if (name == null) {
+            if (id.name != null) {
+               return -1;
+            }
+         } else if (!name.equals(id.name)) {
+            return name.compareTo(id.name);
+         }
+
+         // now they must differ only in version
+
+         String currVersion = null;
+         String newVersion = null;
+         String[] currDecimals = new String[0];
+         String[] newDecimals = new String[0];
+
+         // Extract the dotted decimal version numbers
+         String regex = "^[vV=]{0,1}(\\d+(?:\\.\\d+){0,2}).*$";
+         currVersion = version.replaceFirst(regex, "$1");
+         newVersion = id.version.replaceFirst(regex, "$1");
+
+         String dottedDecimalRegex = "^\\d+(?:\\.\\d+)*$";
+         if (currVersion.matches(dottedDecimalRegex)) {
+
+            // the current version is conforming dotted decimal.
+            // If the new version is also conforming, compare version numbers.
+            // otherwise new version is less then this one.
+
+            if (newVersion.matches(dottedDecimalRegex)) {
+               currDecimals = currVersion.split("\\.");
+               newDecimals = newVersion.split("\\.");
+               for (int ii = 0; (ii < currDecimals.length) && (ii < newDecimals.length);
ii++) {
+                  int currDigit = Integer.parseInt(currDecimals[ii]);
+                  int newDigit = Integer.parseInt(newDecimals[ii]);
+                  if (newDigit > currDigit) {
+                     return 1;
+                  } else if (newDigit < currDigit) {
+                     return -1;
+                  }
+               }
+               
+               // they're equal so far, so the one with the most digits is greater
+               
+               if (currDecimals.length > newDecimals.length) {
+                  return -1;
+               } else if (currDecimals.length < newDecimals.length) {
+                  return 1;
+               } 
+            }
+
+         } else {
+
+            // If new version conforms, use it, otherwise string compare
+
+            if (newVersion.matches(dottedDecimalRegex)) {
+               return 1;
+            } else {
+               // if neither conform, use string compare
+               return version.compareTo(id.version);
+            }
+
+         }
+
+      }
+      return 0;
+   }
+
 }

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0c9aec76/pluto-portal-driver/src/main/java/org/apache/pluto/driver/services/portal/PageResources.java
----------------------------------------------------------------------
diff --git a/pluto-portal-driver/src/main/java/org/apache/pluto/driver/services/portal/PageResources.java
b/pluto-portal-driver/src/main/java/org/apache/pluto/driver/services/portal/PageResources.java
index fd1c212..8c7f0f0 100644
--- a/pluto-portal-driver/src/main/java/org/apache/pluto/driver/services/portal/PageResources.java
+++ b/pluto-portal-driver/src/main/java/org/apache/pluto/driver/services/portal/PageResources.java
@@ -19,6 +19,9 @@
 
 package org.apache.pluto.driver.services.portal;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -39,8 +42,9 @@ public class PageResources {
    @SuppressWarnings("unused")
    private static final boolean isTrace = LOG.isTraceEnabled();
    
-   
-   
+   /**
+    * Holds data needed to generate markup for a page resource 
+    */
    private static class Source {
       String type;
       String source;
@@ -86,6 +90,63 @@ public class PageResources {
    }
    
    /**
+    * Implements a fuzzy matching to identify best available resource.
+    * 
+    * @param resid   The desired resource resource ID
+    * @return        The best match page resource ID
+    */
+   private Source getBestMatch(PageResourceId resid) {
+      if (resources.containsKey(resid)) {
+         return resources.get(resid);
+      }
+      
+      // has to at least match on name, and if the scope is provided, on scope
+      
+      List<PageResourceId> candidates = new ArrayList<PageResourceId>();
+      for (PageResourceId id : resources.keySet()) {
+         if (resid.resourceMatches(id)) {
+            candidates.add(id);
+         }
+      }
+      
+      PageResourceId effectiveId = null;
+      if (candidates.size() > 0) {
+         if (candidates.size() == 1) {
+            effectiveId = candidates.get(0);
+         } else {
+            
+            // There are more than one candidates that differ in version.
+            // Choose the first one greater than the requested or the highest available.
+            
+            Collections.sort(candidates);
+            for (PageResourceId id : candidates) {
+               if (resid.compareTo(id) <= 0) {
+                  effectiveId = id;
+                  break;
+               }
+            }
+            
+            if (effectiveId == null) {
+               effectiveId = candidates.get(candidates.size()-1);
+            }
+         }
+      }
+      
+      if (isDebug) {
+         StringBuilder txt = new StringBuilder();
+         txt.append("Effective page resource ID: ");
+         txt.append((effectiveId == null) ? "null" : effectiveId.toString());
+         LOG.debug(txt.toString());
+      }
+      
+      if (effectiveId != null) {
+         return resources.get(effectiveId);
+      }
+      
+      return null;
+   }
+   
+   /**
     * Returns the markup for a given page resource ID, properly fixed
     * up with the context path, if necessary.
     *  
@@ -94,10 +155,10 @@ public class PageResources {
     * @return              the markup for the page resource, or <code>null</code>
if ID not found
     */
    public String getMarkup(PageResourceId resid, String contextPath) {
-      String markup = null;
+      String markup = "";
       
-      if (resources.containsKey(resid)) {
-         Source src = resources.get(resid);
+      Source src = getBestMatch(resid);
+      if (src != null) {
          StringBuilder txt = new StringBuilder(128);
          switch (src.type) {
          case "CSS":
@@ -116,22 +177,167 @@ public class PageResources {
          default:
             LOG.warn("Unknown page resource type: " + src.type);
          }
-         if (txt.length() > 0) {
-            markup = txt.toString();
-         }
+         markup = txt.toString();
+      } else {
+         LOG.warn("Unknown page resource ID: " + resid.toString());
       }
       
       return markup;
    }
    
-   public String getMarkup(List<PageResourceId> resids, String contextPath) {
-      StringBuilder txt = new StringBuilder(128);
+   /**
+    * Takes a list of page resource IDs that can potentially contain duplicates
+    * and returns the appropriate head section markup.
+    * <p>
+    * Duplicate resource IDs are scrubbed. If resource IDs in the list differ only by
+    * version, the resource ID with the highest version number is used.
+    * <p>
+    * An attempt is made to maintain the inclusion order when generating the markup.
+    * 
+    * @param prids        List of page resource IDs
+    * @param contextPath   The context path 
+    * @return              Markup string that can be added to the document head section
+    */
+   public String getMarkup(List<PageResourceId> prids, String contextPath) {
+      List<PageResourceId> resultids = new ArrayList<PageResourceId>();
       
-      for (PageResourceId resid : resids) {
-         txt.append(getMarkup(resid, contextPath)).append("\n");
+      // build the resulting page resource ID list by examining each ID from the
+      // input list, comparing it to IDs already in the result list.
+
+      for (PageResourceId newid : prids) {
+         
+         // look for page resource id match (without version)
+         
+         int index = -1;
+         for (int ii = 0; ii < resultids.size(); ii++) {
+            if (resultids.get(ii).resourceMatches(newid)) {
+               index = ii;
+               break;
+            }
+         }
+         
+         if (index == -1) {
+            
+            // no match, so just add new element
+            resultids.add(newid);
+            
+         } else {
+            PageResourceId currid = resultids.get(index);
+            
+            // ignore exact match (throw away exact duplicates)
+            if (!currid.equals(newid)) {
+               
+               // The Id in the list differs from the new ID only in the version. 
+               // The version will be compared assuming a format similar to that 
+               // described by the semantic versioning spec (see http://semver.org/).
+               // Format: MAJOR.MINOR.PATCH with decimal numbers
+               // If, after truncating leading and trailing characters, the result does
+               // not match this format, a simple string compare is used.
+               // The latest version will be kept in the list at the original index.
+               
+               boolean replaceId = false;
+               
+               if (currid.getVersion() == null) {
+                  // a specified version replaces a null version
+                  replaceId = true;
+               }
+
+               // place vars here to allow debug data collection
+               String currVersion = null;
+               String newVersion  = null;
+               String[] currDecimals = new String[0];
+               String[] newDecimals  = new String[0];
+
+               if (!replaceId && newid.getVersion() != null) {
+                  
+                  // Extract the dotted decimal version numbers
+                  String regex = "^[vV=]{0,1}(\\d+(?:\\.\\d+){0,2}).*$";
+                  currVersion = currid.getVersion().replaceFirst(regex, "$1");
+                  newVersion  = newid.getVersion().replaceFirst(regex, "$1");
+                  
+                  String dottedDecimalRegex = "^\\d+(?:\\.\\d+)*$";
+                  if (currVersion.matches(dottedDecimalRegex)) {
+                     
+                     // the current version is conforming dotted decimal. 
+                     // If the new version is also conforming, compare version numbers.
+                     // otherwise ignore.
+                     
+                     if (newVersion.matches(dottedDecimalRegex)) {
+                        currDecimals = currVersion.split("\\.");
+                        newDecimals  = newVersion.split("\\.");
+                        for (int ii=0; (ii < currDecimals.length) && (ii <
newDecimals.length); ii++) {
+                           int currDigit = Integer.parseInt(currDecimals[ii]);
+                           int newDigit = Integer.parseInt(newDecimals[ii]);
+                           if (newDigit > currDigit) {
+                              replaceId = true;
+                              break;
+                           }
+                        }
+                        if (!replaceId) {
+                           // if the new id is identical, but with more digits, replace
+                           if (newDecimals.length > currDecimals.length) {
+                              replaceId = true;
+                           }
+                        }
+                     } 
+                     
+                  } else {
+                     
+                     // If new version conforms, use it, otherwise string compare
+                     
+                     if (newVersion.matches(dottedDecimalRegex)) {
+                        replaceId = true;
+                     } else {
+                        replaceId = currid.getVersion().compareTo(newid.getVersion()) >
0;
+                     }
+                     
+                  }
+               }
+               
+               if (replaceId) {
+                  
+                  if (isDebug) {
+                     StringBuilder txt = new StringBuilder();
+                     txt.append("Replacing page resource id.");
+                     txt.append(" old: ").append(currid.toString());
+                     txt.append(", new: ").append(newid.toString());
+                     txt.append(", index: ").append(index);
+                     txt.append(", total length: ").append(resultids.size());
+                     txt.append("\n   Current version string: ").append(currVersion);
+                     txt.append(", New version string: ").append(newVersion);
+                     txt.append(", Current digits: ").append(Arrays.asList(currDecimals));
+                     txt.append(", New digits: ").append(Arrays.asList(newDecimals));
+                     LOG.debug(txt.toString());
+                  }
+                  
+                  // replace the current item in the list with the new item, as it
+                  // has a later version.
+                  resultids.add(index, newid);
+                  resultids.remove(index+1);
+                  
+               }
+            }
+         }
+         
+      }
+      
+      // generate the markup
+      StringBuilder markup = new StringBuilder(128);
+      for (PageResourceId resid : resultids) {
+         markup.append(getMarkup(resid, contextPath)).append("\n");
+      }
+      
+      if (isDebug) {
+         StringBuilder txt = new StringBuilder();
+         txt.append("\nConsolidated page resource IDs:");
+         for (PageResourceId id : resultids) {
+            txt.append("\n").append(id.toString());
+         }
+         txt.append("\n\nResulting markup:\n").append(markup.toString());
+         LOG.debug(txt.toString());
       }
       
-      return (txt.length() == 0) ? null : txt.toString();
+      return (markup.length() == 0) ? null : markup.toString();
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0c9aec76/pluto-portal/src/main/resources/pluto-portal-driver-config.xml
----------------------------------------------------------------------
diff --git a/pluto-portal/src/main/resources/pluto-portal-driver-config.xml b/pluto-portal/src/main/resources/pluto-portal-driver-config.xml
index a6eadcc..14ff632 100644
--- a/pluto-portal/src/main/resources/pluto-portal-driver-config.xml
+++ b/pluto-portal/src/main/resources/pluto-portal-driver-config.xml
@@ -49,7 +49,7 @@ limitations under the License.
       <identifier>
         <name>portlet-spec-1.0.css</name>
         <scope>org.apache.portals</scope>
-        <version>1.0</version>
+        <version>1.0.0</version>
       </identifier>
       <source type="css">/css/portlet-spec-1.0.css</source>
     </page-resource>
@@ -57,7 +57,7 @@ limitations under the License.
       <identifier>
         <name>portlet-spec-2.0.css</name>
         <scope>org.apache.portals</scope>
-        <version>2.0</version>
+        <version>2.0.0</version>
       </identifier>
       <source type="css">/css/portlet-spec-2.0.css</source>
     </page-resource>
@@ -65,7 +65,7 @@ limitations under the License.
       <identifier>
         <name>pluto.css</name>
         <scope>org.apache.portals</scope>
-        <version>3.0</version>
+        <version>3.0.0</version>
       </identifier>
       <source type="css">/css/pluto.css</source>
     </page-resource>
@@ -81,7 +81,7 @@ limitations under the License.
       <identifier>
         <name>pluto.js</name>
         <scope>org.apache.portals</scope>
-        <version>3.0</version>
+        <version>3.0.0</version>
       </identifier>
       <source type="script">/javascript/pluto.js</source>
     </page-resource>
@@ -89,7 +89,7 @@ limitations under the License.
       <identifier>
         <name>portlet.js</name>
         <scope>org.apache.portals</scope>
-        <version>3.0</version>
+        <version>3.0.0</version>
       </identifier>
       <source type="script">/javascript/portlet.js</source>
     </page-resource>
@@ -97,7 +97,7 @@ limitations under the License.
       <identifier>
         <name>portletHubImpl.js</name>
         <scope>org.apache.portals</scope>
-        <version>3.0</version>
+        <version>3.0.0</version>
       </identifier>
       <source type="script">/javascript/portletHubImpl.js</source>
     </page-resource>
@@ -116,32 +116,32 @@ limitations under the License.
     <default-resource>
       <name>pluto.css</name>
       <scope>org.apache.portals</scope>
-      <version>3.0</version>
+      <version>3.0.0</version>
     </default-resource>
     <default-resource>
         <name>portlet-spec-1.0.css</name>
         <scope>org.apache.portals</scope>
-        <version>1.0</version>
+        <version>1.0.0</version>
     </default-resource>
     <default-resource>
         <name>portlet-spec-2.0.css</name>
         <scope>org.apache.portals</scope>
-        <version>2.0</version>
+        <version>2.0.0</version>
     </default-resource>
     <default-resource>
       <name>pluto.js</name>
       <scope>org.apache.portals</scope>
-      <version>3.0</version>
+      <version>3.0.0</version>
     </default-resource>
     <default-resource>
       <name>portlet.js</name>
       <scope>org.apache.portals</scope>
-      <version>3.0</version>
+      <version>3.0.0</version>
     </default-resource>
     <default-resource>
       <name>portletHubImpl.js</name>
       <scope>org.apache.portals</scope>
-      <version>3.0</version>
+      <version>3.0.0</version>
     </default-resource>
   </page-resources>
 


Mime
View raw message