You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@roller.apache.org by sn...@apache.org on 2010/03/20 19:37:54 UTC

svn commit: r925653 [2/5] - in /roller/trunk: planet-business/src/test/resources/ planet-web/ planet-web/src/ planet-web/src/main/ planet-web/src/main/java/ planet-web/src/main/java/org/ planet-web/src/main/java/org/apache/ planet-web/src/main/java/org...

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/core/struts2/PlanetActionSupport.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/core/struts2/PlanetActionSupport.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/core/struts2/PlanetActionSupport.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/core/struts2/PlanetActionSupport.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.core.struts2;
+
+import com.opensymphony.xwork2.ActionSupport;
+import java.util.List;
+
+
+/**
+ * Extends the Struts2 ActionSupport class to add in support for handling an
+ * error and status success.  Other actions extending this one only need to
+ * calle setError() and setSuccess() accordingly.
+ * 
+ * NOTE: as a small convenience, all errors and messages are assumed to be keys
+ * which point to a success in a resource bundle, so we automatically call
+ * getText(key) on the param passed into setError() and setSuccess().
+ */
+public abstract class PlanetActionSupport extends ActionSupport {
+    
+    // status params
+    private String error = null;
+    private String warning = null;
+    private String success = null;
+    
+    
+    public String getError() {
+        return error;
+    }
+
+    public void setError(String error) {
+        this.error = getText(error);
+    }
+    
+    public void setError(String error, String param) {
+        this.error = getText(error, error, param);
+    }
+    
+    public String getWarning() {
+        return warning;
+    }
+
+    public void setWarning(String warning) {
+        this.warning = getText(warning);
+    }
+    
+    public void setWarning(String warning, String param) {
+        this.warning = getText(warning, warning, param);
+    }
+    
+    public String getSuccess() {
+        return success;
+    }
+
+    public void setSuccess(String message) {
+        this.success = getText(message);
+    }
+    
+    public void setSuccess(String message, String param) {
+        this.success = getText(message, message, param);
+    }
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/core/struts2/package.properties
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/core/struts2/package.properties?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/core/struts2/package.properties (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/core/struts2/package.properties Sat Mar 20 18:37:51 2010
@@ -0,0 +1,17 @@
+
+# Login
+
+Login.pageTitle=Login
+Login.tryAgain=Login failed.  Please try again.
+Login.username=UserName
+Login.password=Password
+Login.button=Login
+
+
+# MainMenu
+
+Menu.pageTitle=Welcome to Roller Planet
+Menu.heading=Welcome to Roller Planet
+Menu.mainPlanetLink=Main page of Roller Planet site
+Menu.mainRegistrationLink=Blog registration page
+Menu.mainConsoleLink=Roller Planet Admin Console

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/MultiPlanetRequestMapper.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/MultiPlanetRequestMapper.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/MultiPlanetRequestMapper.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/MultiPlanetRequestMapper.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,286 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.planet.business.PlanetFactory;
+import org.apache.roller.planet.business.PlanetManager;
+import org.apache.roller.planet.config.PlanetConfig;
+import org.apache.roller.planet.pojos.Planet;
+import org.apache.roller.planet.pojos.PlanetGroup;
+
+
+/**
+ * Multi-planet request mapper.
+ *
+ * This request mapper is used to map all planet specific urls of the form
+ * /<planet handle>/* to the appropriate servlet for handling the actual
+ * request.
+ */
+public class MultiPlanetRequestMapper implements RequestMapper {
+    
+    private static Log log = LogFactory.getLog(MultiPlanetRequestMapper.class);
+    
+    private static final String PAGE_SERVLET = "/planet-ui/rendering/page";
+    private static final String FEED_SERVLET = "/planet-ui/rendering/feed";
+    private static final String OPML_SERVLET = "/planet-ui/rendering/opml";
+    
+    // url patterns that are not allowed to be considered planet handles
+    Set restricted = null;
+    
+    
+    public MultiPlanetRequestMapper() {
+        
+        this.restricted = new HashSet();
+        
+        // build roller restricted list
+        String restrictList = 
+                PlanetConfig.getProperty("rendering.multiPlanetMapper.rollerProtectedUrls");
+        if(restrictList != null && restrictList.trim().length() > 0) {
+            String[] restrict = restrictList.split(",");
+            for(int i=0; i < restrict.length; i++) {
+                this.restricted.add(restrict[i]);
+            }
+        }
+        
+        // add user restricted list
+        restrictList = 
+                PlanetConfig.getProperty("rendering.multiPlanetMapper.userProtectedUrls");
+        if(restrictList != null && restrictList.trim().length() > 0) {
+            String[] restrict = restrictList.split(",");
+            for(int i=0; i < restrict.length; i++) {
+                this.restricted.add(restrict[i]);
+            }
+        }
+    }
+    
+    
+    public boolean handleRequest(HttpServletRequest request, HttpServletResponse response)
+            throws ServletException, IOException {
+        
+        // kinda silly, but we need to keep track of whether or not the url had
+        // a trailing slash so that we can act accordingly
+        boolean trailingSlash = false;
+        
+        String planetHandle = null;
+        String planetContext = null;
+        String groupHandle = null;
+        String groupContext = null;
+        String extraRequestData = null;
+        
+        log.debug("evaluating ["+request.getRequestURI()+"]");
+        
+        // figure out potential planet handle
+        String uri = request.getRequestURI();
+        String pathInfo = null;
+                
+        if(uri != null && uri.trim().length() > 1) {
+            
+            if(request.getContextPath() != null)
+                uri = uri.substring(request.getContextPath().length());
+            
+            // strip off the leading slash
+            uri = uri.substring(1);
+            
+            // strip off trailing slash if needed
+            if(uri.endsWith("/")) {
+                uri = uri.substring(0, uri.length() - 1);
+                trailingSlash = true;
+            }
+            
+            if(uri.indexOf("/") != -1) {
+                planetHandle = uri.substring(0, uri.indexOf("/"));
+                pathInfo = uri.substring(uri.indexOf("/")+1);
+            } else {
+                planetHandle = uri;
+            }
+        }
+        
+        log.debug("potential planet handle = "+planetHandle);
+        
+        // check if it's a valid planet handle
+        if(restricted.contains(planetHandle) || !this.isPlanet(planetHandle)) {
+            log.debug("SKIPPED "+planetHandle);
+            return false;
+        }
+        
+        log.debug("PLANET_URL "+request.getServletPath());
+        
+        // parse the rest of the url
+        if(pathInfo != null) {
+            
+            // parse the next portion of the url
+            // we expect <context>/<groupHandle>/<groupContext>/<extra>/<info>
+            String[] urlPath = pathInfo.split("/", 4);
+            planetContext = urlPath[0];
+            
+            if(urlPath.length == 2) {
+                groupHandle = urlPath[1];
+            } else if(urlPath.length == 3) {
+                groupHandle = urlPath[1];
+                groupContext = urlPath[2];
+            } else if(urlPath.length == 4) {
+                groupHandle = urlPath[1];
+                groupContext = urlPath[2];
+                extraRequestData = urlPath[3];
+            }
+        }
+        
+        // special handling for trailing slash issue
+        // we need this because by http standards the urls /foo and /foo/ are
+        // supposed to be considered different, so we must enforce that
+        if( (planetContext == null && !trailingSlash) ||
+            (groupHandle != null && groupContext == null && !trailingSlash) ) {
+            
+            // this means someone referred to a planet or group index page 
+            // with the shortest form of url /<planet> or /<planet>/group/<group>
+            // and we need to add a slash to the url and redirect
+            String redirectUrl = request.getRequestURI() + "/";
+            if(request.getQueryString() != null) {
+                redirectUrl += "?"+request.getQueryString();
+            }
+            
+            response.sendRedirect(redirectUrl);
+            return true;
+            
+        } else if(groupContext != null && trailingSlash) {
+            // this means that someone has accessed a url and included a 
+            // trailing slash, like /<planet>/group/<group>/feed/atom/ which is
+            // not supported, so we need to offer up a 404 Not Found
+            response.sendError(HttpServletResponse.SC_NOT_FOUND);
+            return true;
+        }
+        
+        // calculate forward url
+        String forwardUrl = calculateForwardUrl(request, planetHandle, 
+                planetContext, groupHandle, groupContext, extraRequestData);
+        
+        // if we don't have a forward url then the request was invalid somehow
+        if(forwardUrl == null) {
+            return false;
+        }
+        
+        // dispatch to forward url
+        log.debug("forwarding to "+forwardUrl);
+        RequestDispatcher dispatch = request.getRequestDispatcher(forwardUrl);
+        dispatch.forward(request, response);
+        
+        // we dealt with this request ourselves, so return "true"
+        return true;
+    }
+
+    
+    /**
+     * Convenience method for caculating the servlet forward url given a set
+     * of information to make the decision with.
+     *
+     * handle is always assumed valid, all other params may be null.
+     */
+    private String calculateForwardUrl(HttpServletRequest request,
+                                       String planetHandle, 
+                                       String planetContext, 
+                                       String groupHandle, 
+                                       String groupContext, 
+                                       String data) {
+        
+        log.debug(planetHandle+","+planetContext+","+groupHandle+","+groupContext+","+data);
+        
+        StringBuffer forwardUrl = new StringBuffer();
+        
+        // no context means planet homepage
+        if(planetContext == null) {
+            forwardUrl.append(PAGE_SERVLET);
+            forwardUrl.append("/").append(planetHandle);
+            
+        // requests for a specific planet group
+        } else if(planetContext.equals("group") && groupHandle != null) {
+            
+            // no group context means group homepage
+            if(groupContext == null) {
+                forwardUrl.append(PAGE_SERVLET);
+                forwardUrl.append("/").append(planetHandle);
+                forwardUrl.append("/").append(groupHandle);
+
+            // request for planet group feed
+            } else if("feed".equals(groupContext)) {
+                forwardUrl.append(FEED_SERVLET);
+                forwardUrl.append("/").append(planetHandle);
+                forwardUrl.append("/").append(groupHandle);
+                if(data != null) {
+                    forwardUrl.append("/").append(data);
+                }
+                
+            // request for planet group opml descriptor
+            } else if("opml".equals(groupContext)) {
+                forwardUrl.append(OPML_SERVLET);
+                forwardUrl.append("/").append(planetHandle);
+                forwardUrl.append("/").append(groupHandle);
+                if(data != null) {
+                    forwardUrl.append("/").append(data);
+                }
+                
+            // unsupported planet group url
+            } else {
+                return null;
+            }
+            
+        // unsupported planet url
+        } else {
+            return null;
+        }
+        
+        log.debug("FORWARD_URL "+forwardUrl.toString());
+        
+        return forwardUrl.toString();
+    }
+    
+    
+    /**
+     * convenience method which determines if the given string is a valid
+     * planet handle.
+     */
+    private boolean isPlanet(String planetHandle) {
+        
+        log.debug("checking planet handle "+planetHandle);
+        
+        boolean isPlanet = false;
+        
+        try {
+            PlanetManager mgr = PlanetFactory.getPlanet().getPlanetManager();
+            Planet planet = mgr.getPlanet(planetHandle);
+            
+            if(planet != null) {
+                isPlanet = true;
+            }
+        } catch(Exception ex) {
+            // doesn't really matter to us why it's not a valid planet
+        }
+        
+        return isPlanet;
+    }
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/Renderer.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/Renderer.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/Renderer.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/Renderer.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering;
+
+import java.io.Writer;
+import java.util.Map;
+
+
+/**
+ * Interface representing a content renderer in Roller.
+ */
+public interface Renderer {
+    
+    
+    /**
+     * Render the content for this Renderer to the given Writer using
+     * the given set of model objects.
+     *
+     * Throws an exception if there is a problem during rendering.
+     */
+    public void render(Map model, Writer writer) throws RenderingException;
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/RendererFactory.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/RendererFactory.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/RendererFactory.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/RendererFactory.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering;
+
+import org.apache.roller.planet.pojos.Template;
+
+
+/**
+ * A factory for Renderer objects.
+ *
+ * Implementations of this interface are used to handle the actual lookup of
+ * what Renderer object should be used to render a given resource.
+ */
+public interface RendererFactory {
+    
+    
+    /**
+     * Get a Renderer that will handle the given Template.
+     * If a RendererFactory does not have a Renderer which can handle the
+     * content then it may return null.
+     *
+     * This method purposely does not throw exceptions because the rendering
+     * system as a whole does not care if a given factory generates an exception
+     * while trying to find a renderer.  It is up to the factory itself to
+     * report any relevant exceptions itself.
+     */
+    public Renderer getRenderer(Template template);
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/RendererManager.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/RendererManager.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/RendererManager.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/RendererManager.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.planet.config.PlanetConfig;
+import org.apache.roller.planet.pojos.Template;
+import org.apache.roller.planet.ui.rendering.Renderer;
+import org.apache.roller.planet.ui.rendering.RendererFactory;
+import org.apache.roller.planet.ui.rendering.RenderingException;
+
+
+/**
+ * A governing class for Rollers rendering system.
+ * 
+ * The purpose of the RendererManager is to provide a level of abstraction 
+ * between classes that are rendering content and the implementations of the
+ * rendering technology.  This allows us to provide easily pluggable rendering
+ * implementations.
+ */
+public class RendererManager {
+    
+    private static Log log = LogFactory.getLog(RendererManager.class);
+    
+    // a set of all renderer factories we are consulting
+    private static Set rendererFactories = new HashSet();
+    
+    
+    static {
+        // lookup set of renderer factories we are going to use
+        String rollerFactories = PlanetConfig.getProperty("rendering.rollerRendererFactories");
+        String userFactories = PlanetConfig.getProperty("rendering.userRendererFactories");
+        
+        // instantiate user defined renderer factory classes
+        if(userFactories != null && userFactories.trim().length() > 0) {
+            
+            RendererFactory rendererFactory = null;
+            String[] uFactories = userFactories.split(",");
+            for(int i=0; i < uFactories.length; i++) {
+                try {
+                    Class factoryClass = Class.forName(uFactories[i]);
+                    rendererFactory = (RendererFactory) factoryClass.newInstance();
+                    rendererFactories.add(rendererFactory);
+                } catch(ClassCastException cce) {
+                    log.error("It appears that your factory does not implement "+
+                            "the RendererFactory interface", cce);
+                } catch(Exception e) {
+                    log.error("Unable to instantiate renderer factory ["+uFactories[i]+"]", e);
+                }
+            }
+        }
+        
+        // instantiate roller standard renderer factory classes
+        if(rollerFactories != null && rollerFactories.trim().length() > 0) {
+            
+            RendererFactory rendererFactory = null;
+            String[] rFactories = rollerFactories.split(",");
+            for(int i=0; i < rFactories.length; i++) {
+                try {
+                    Class factoryClass = Class.forName(rFactories[i]);
+                    rendererFactory = (RendererFactory) factoryClass.newInstance();
+                    rendererFactories.add(rendererFactory);
+                } catch(ClassCastException cce) {
+                    log.error("It appears that your factory does not implement "+
+                            "the RendererFactory interface", cce);
+                } catch(Exception e) {
+                    log.error("Unable to instantiate renderer factory ["+rFactories[i]+"]", e);
+                }
+            }
+        }
+        
+        if(rendererFactories.size() < 1) {
+            // hmm ... failed to load any renderer factories?
+            log.warn("Failed to load any renderer factories.  "+
+                    "Rendering probably won't function as you expect.");
+        }
+        
+        log.info("Renderer Manager Initialized.");
+    }
+    
+    
+    // this class is non-instantiable
+    private RendererManager() {}
+    
+    
+    /**
+     * Find the appropriate Renderer for the given content.
+     *
+     * This method checks all renderer factories configured for the Roller
+     * instance and tries to find a Renderer for the content.  If no Renderer
+     * can be found then we throw an exception.
+     */
+    public static Renderer getRenderer(Template template) 
+            throws RenderingException {
+        
+        Renderer renderer = null;
+        
+        // iterate over our renderer factories and see if one of them
+        // wants to handle this content
+        Iterator factories = rendererFactories.iterator();
+        while(factories.hasNext()) {
+            renderer = ((RendererFactory)factories.next()).getRenderer(template);
+            
+            if(renderer != null) {
+                return renderer;
+            }
+        }
+        
+        throw new RenderingException("No renderer found for template "+
+                template.getId()+"!");
+    }
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/RenderingException.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/RenderingException.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/RenderingException.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/RenderingException.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering;
+
+import org.apache.roller.planet.PlanetException;
+
+
+/**
+ * A generic Roller rendering exception.
+ */
+public class RenderingException extends PlanetException {
+    
+    public RenderingException(String s) {
+        super(s);
+    }
+    
+    public RenderingException(String s, Throwable t) {
+        super(s, t);
+    }
+    
+    public RenderingException(Throwable t) {
+        super(t);
+    }
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/RequestMapper.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/RequestMapper.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/RequestMapper.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/RequestMapper.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,26 @@
+
+package org.apache.roller.planet.ui.rendering;
+
+import java.io.IOException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * Interface representing an object that maps requests.
+ */
+public interface RequestMapper {
+    
+    /**
+     * Handle an incoming request.
+     *
+     * RequestMappers are not required to handle all requests and are instead
+     * encouraged to inspect the request and only take action when it
+     * wants to.  If action is taken then the RequestMapper should return a 
+     * boolean "true" value indicating that no further action is required.
+     */
+    public boolean handleRequest(HttpServletRequest req, HttpServletResponse res)
+        throws ServletException, IOException;
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/filters/RequestMappingFilter.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/filters/RequestMappingFilter.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/filters/RequestMappingFilter.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/filters/RequestMappingFilter.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering.filters;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.planet.config.PlanetConfig;
+import org.apache.roller.planet.ui.rendering.RequestMapper;
+
+
+/**
+ * Provides generalized request mapping capablilites.
+ *
+ * Incoming requests can be inspected by a series of RequestMappers and can
+ * potentially be re-routed to different places within the application.
+ */
+public class RequestMappingFilter implements Filter {
+    
+    private static Log log = LogFactory.getLog(RequestMappingFilter.class);
+    
+    // list of RequestMappers that want to inspect the request
+    private final List requestMappers = new ArrayList();
+    
+    
+    public void init(FilterConfig filterConfig) {
+        
+        // lookup set of request mappers we are going to use
+        String rollerMappers = PlanetConfig.getProperty("rendering.rollerRequestMappers");
+        String userMappers = PlanetConfig.getProperty("rendering.userRequestMappers");
+        
+        // instantiate user defined request mapper classes
+        if(userMappers != null && userMappers.trim().length() > 0) {
+            
+            RequestMapper requestMapper = null;
+            String[] uMappers = userMappers.split(",");
+            for(int i=0; i < uMappers.length; i++) {
+                try {
+                    Class mapperClass = Class.forName(uMappers[i]);
+                    requestMapper = (RequestMapper) mapperClass.newInstance();
+                    requestMappers.add(requestMapper);
+                } catch(ClassCastException cce) {
+                    log.error("It appears that your mapper does not implement "+
+                            "the RequestMapper interface", cce);
+                } catch(Exception e) {
+                    log.error("Unable to instantiate request mapper ["+uMappers[i]+"]", e);
+                }
+            }
+        }
+        
+        // instantiate roller standard request mapper classes
+        if(rollerMappers != null && rollerMappers.trim().length() > 0) {
+            
+            RequestMapper requestMapper = null;
+            String[] rMappers = rollerMappers.split(",");
+            for(int i=0; i < rMappers.length; i++) {
+                try {
+                    Class mapperClass = Class.forName(rMappers[i]);
+                    requestMapper = (RequestMapper) mapperClass.newInstance();
+                    requestMappers.add(requestMapper);
+                } catch(ClassCastException cce) {
+                    log.error("It appears that your mapper does not implement "+
+                            "the RequestMapper interface", cce);
+                } catch(Exception e) {
+                    log.error("Unable to instantiate request mapper ["+rMappers[i]+"]", e);
+                }
+            }
+        }
+        
+        if(requestMappers.size() < 1) {
+            // hmm ... failed to load any request mappers?
+            log.warn("Failed to load any request mappers.  "+
+                    "Weblog urls probably won't function as you expect.");
+        }
+        
+        log.info("Request mapping filter initialized, "+requestMappers.size()+
+                " mappers configured.");
+    }
+    
+    
+    /**
+     * Inspect incoming urls and see if they should be routed.
+     */
+    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
+            throws IOException, ServletException {
+        
+        HttpServletRequest request = (HttpServletRequest) req;
+        HttpServletResponse response = (HttpServletResponse) res;
+        
+        log.debug("entering");
+        
+        // give each mapper a chance to handle the request
+        RequestMapper mapper = null;
+        Iterator mappersIT = this.requestMappers.iterator();
+        while(mappersIT.hasNext()) {
+            mapper = (RequestMapper) mappersIT.next();
+            
+            log.debug("trying mapper "+mapper.getClass().getName());
+            
+            boolean wasHandled = mapper.handleRequest(request, response);
+            if(wasHandled) {
+                // if mapper has handled the request then we are done
+                log.debug("request handled by "+mapper.getClass().getName());
+                log.debug("exiting");
+                return;
+            }
+        }
+        
+        log.debug("request not mapped");
+        
+        // nobody handled the request, so let it continue as usual
+        chain.doFilter(request, response);
+        
+        log.debug("exiting");
+    }
+    
+    
+    public void destroy() {}
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/FeedModel.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/FeedModel.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/FeedModel.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/FeedModel.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering.model; 
+
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.planet.PlanetException;
+import org.apache.roller.planet.pojos.Planet;
+import org.apache.roller.planet.pojos.PlanetGroup;
+import org.apache.roller.planet.ui.rendering.pagers.Pager;
+import org.apache.roller.planet.ui.rendering.pagers.PlanetEntriesPager;
+import org.apache.roller.planet.ui.rendering.util.PlanetGroupFeedRequest;
+import org.apache.roller.planet.ui.rendering.util.PlanetRequest;
+import org.apache.roller.planet.util.URLUtilities;
+
+
+/**
+ * Model which provides information needed to render a planet feed.
+ */
+public class FeedModel extends PlanetGroupModel {
+    
+    private static Log log = LogFactory.getLog(FeedModel.class);
+    
+    private PlanetGroupFeedRequest feedRequest = null;
+    
+    
+    /** 
+     * Creates an un-initialized new instance, Roller calls init() to complete
+     * construction. 
+     */
+    public FeedModel() {
+        super();
+    }
+    
+    
+    /** 
+     * Template context name to be used for model.
+     */
+    public String getModelName() {
+        return "model";
+    }
+    
+    
+    /** 
+     * Init page model based on request. 
+     */
+    public void init(Map initData) throws PlanetException {
+        
+        // parent gets to go first
+        super.init(initData);
+        
+        // we expect the init data to contain a weblogRequest object
+        PlanetRequest planetRequest = (PlanetRequest) initData.get("planetRequest");
+        if(planetRequest == null) {
+            throw new PlanetException("expected planetRequest from init data");
+        }
+        
+        // PageModel only works on page requests, so cast planetRequest
+        // into a PlanetRequest and if it fails then throw exception
+        if(planetRequest instanceof PlanetGroupFeedRequest) {
+            this.feedRequest = (PlanetGroupFeedRequest) planetRequest;
+        } else {
+            throw new PlanetException("weblogRequest is not a WeblogPageRequest."+
+                    "  PageModel only supports page requests.");
+        }
+    }
+    
+    
+    public Pager getPager() {
+        
+        String pagerUrl = URLUtilities.getPlanetGroupURL(getPlanet().getHandle(), feedRequest.getGroupHandle());
+        
+        return new PlanetEntriesPager(
+                null,
+                feedRequest.getGroup(),
+                pagerUrl,
+                0,
+                0,
+                30);
+    }
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/Model.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/Model.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/Model.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/Model.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering.model;
+
+import java.util.Map;
+import org.apache.roller.planet.PlanetException;
+
+
+/**
+ * Represents a set of functionality to be used at rendering.
+ */
+public interface Model {
+    
+    /**
+     * Name to be used when referring to this model.
+     */
+    public String getModelName();
+    
+    
+    /**
+     * Initialize.
+     */
+    public void init(Map params) throws PlanetException;
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/ModelLoader.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/ModelLoader.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/ModelLoader.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/ModelLoader.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering.model;
+
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.planet.PlanetException;
+import org.apache.roller.planet.util.Utilities;
+
+
+/**
+ * Helps with model loading process.
+ */
+public class ModelLoader {
+    
+    private static Log log = LogFactory.getLog(ModelLoader.class);
+    
+    
+    /**
+     * Convenience method to load a comma-separated list of page models.
+     *
+     * Optionally fails if any exceptions are thrown when initializing
+     * the Model instances.
+     */
+    public static void loadModels(String modelsString, Map model, 
+                                   Map initData, boolean fail) 
+            throws PlanetException {
+        
+        String[] models = Utilities.stringToStringArray(modelsString, ",");
+        for(int i=0; i < models.length; i++) {
+            try {
+                Class modelClass = Class.forName(models[i]);
+                Model pageModel = (Model) modelClass.newInstance();
+                pageModel.init(initData);
+                model.put(pageModel.getModelName(), pageModel);
+            } catch (PlanetException re) {
+                if(fail) {
+                    throw re;
+                } else {
+                    log.warn("Error initializing model: " + models[i]);
+                }
+            } catch (ClassNotFoundException cnfe) {
+                if(fail) {
+                    throw new PlanetException("Error finding model: " + models[i], cnfe);
+                } else {
+                    log.warn("Error finding model: " + models[i]);
+                }
+            } catch (InstantiationException ie) {
+                if(fail) {
+                    throw new PlanetException("Error insantiating model: " + models[i], ie);
+                } else {
+                    log.warn("Error insantiating model: " + models[i]);
+                }
+            } catch (IllegalAccessException iae) {
+                if(fail) {
+                    throw new PlanetException("Error accessing model: " + models[i], iae);
+                } else {
+                    log.warn("Error accessing model: " + models[i]);
+                }
+            }
+        }
+    }
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/PageModel.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/PageModel.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/PageModel.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/PageModel.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering.model; 
+
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.planet.PlanetException;
+import org.apache.roller.planet.pojos.Planet;
+import org.apache.roller.planet.pojos.PlanetGroup;
+import org.apache.roller.planet.ui.rendering.pagers.Pager;
+import org.apache.roller.planet.ui.rendering.pagers.PlanetEntriesPager;
+import org.apache.roller.planet.ui.rendering.util.PlanetGroupPageRequest;
+import org.apache.roller.planet.ui.rendering.util.PlanetRequest;
+import org.apache.roller.planet.util.URLUtilities;
+
+
+/**
+ * Model which provides information needed to render a planet page.
+ */
+public class PageModel extends PlanetGroupModel {
+    
+    private static Log log = LogFactory.getLog(PageModel.class);
+    
+    private PlanetGroupPageRequest pageRequest = null;
+    
+    
+    /** 
+     * Creates an un-initialized new instance.
+     */
+    public PageModel() {
+        super();
+    }
+    
+    
+    /** 
+     * Template context name to be used for model.
+     */
+    public String getModelName() {
+        return "model";
+    }
+    
+    
+    /** 
+     * Init page model based on request. 
+     */
+    public void init(Map initData) throws PlanetException {
+        
+        // parent gets to go first
+        super.init(initData);
+        
+        // we expect the init data to contain a weblogRequest object
+        PlanetRequest planetRequest = (PlanetRequest) initData.get("planetRequest");
+        if(planetRequest == null) {
+            throw new PlanetException("expected planetRequest from init data");
+        }
+        
+        // PageModel only works on page requests, so cast planetRequest
+        // into a PlanetRequest and if it fails then throw exception
+        if(planetRequest instanceof PlanetGroupPageRequest) {
+            this.pageRequest = (PlanetGroupPageRequest) planetRequest;
+        } else {
+            throw new PlanetException("weblogRequest is not a WeblogPageRequest."+
+                    "  PageModel only supports page requests.");
+        }
+    }
+    
+    
+    public Pager getPager() {
+        
+        String pagerUrl = URLUtilities.getPlanetGroupURL(getPlanet().getHandle(), pageRequest.getGroupHandle());
+        
+        return new PlanetEntriesPager(
+                null,
+                pageRequest.getGroup(),
+                pagerUrl,
+                0,
+                pageRequest.getPageNum(),
+                getGroup().getMaxPageEntries());
+    }
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/PlanetGroupModel.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/PlanetGroupModel.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/PlanetGroupModel.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/PlanetGroupModel.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering.model; 
+
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.planet.PlanetException;
+import org.apache.roller.planet.pojos.Planet;
+import org.apache.roller.planet.pojos.PlanetGroup;
+import org.apache.roller.planet.ui.rendering.util.PlanetGroupRequest;
+import org.apache.roller.planet.ui.rendering.util.PlanetRequest;
+
+
+/**
+ * Model which provides information common to a planet group request
+ */
+public class PlanetGroupModel implements Model {
+    
+    private static Log log = LogFactory.getLog(PlanetGroupModel.class);
+    
+    private PlanetGroupRequest planetGroupRequest = null;
+    private Planet planet = null;
+    private PlanetGroup group = null;
+    
+    
+    /** 
+     * Creates an un-initialized new instance, Roller calls init() to complete
+     * construction. 
+     */
+    public PlanetGroupModel() {}
+    
+    
+    /** 
+     * Template context name to be used for model.
+     */
+    public String getModelName() {
+        return "model";
+    }
+    
+    
+    /** 
+     * Init page model based on request. 
+     */
+    public void init(Map initData) throws PlanetException {
+        
+        // we expect the init data to contain a planetRequest object
+        PlanetRequest planetRequest = (PlanetRequest) initData.get("planetRequest");
+        if(planetRequest == null) {
+            throw new PlanetException("expected planetRequest from init data");
+        }
+        
+        // only works on planet group requests, so cast planetRequest
+        // into a PlanetGroupRequest and if it fails then throw exception
+        if(planetRequest instanceof PlanetGroupRequest) {
+            this.planetGroupRequest = (PlanetGroupRequest) planetRequest;
+        } else {
+            throw new PlanetException("planetRequest is not a PlanetGroupRequest."+
+                    "  PlanetGroupModel only supports planet group requests.");
+        }
+        
+        // extract planet object
+        planet = planetGroupRequest.getPlanet();
+        
+        // extract group object
+        group = planetGroupRequest.getGroup();
+    }
+    
+    
+    /**
+     * Get planet being displayed.
+     */
+    public Planet getPlanet() {
+        return planet;
+    }
+    
+    
+    /**
+     * Get group being displayed.
+     */
+    public PlanetGroup getGroup() {
+        return group;
+    }
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/PlanetURLModel.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/PlanetURLModel.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/PlanetURLModel.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/PlanetURLModel.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering.model;
+
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.planet.PlanetException;
+import org.apache.roller.planet.business.PlanetFactory;
+import org.apache.roller.planet.business.URLStrategy;
+import org.apache.roller.planet.config.PlanetRuntimeConfig;
+import org.apache.roller.planet.pojos.Planet;
+import org.apache.roller.planet.ui.rendering.util.PlanetRequest;
+
+
+/**
+ * Provides access to URL building functionality.
+ *
+ * NOTE: we purposely go against the standard getter/setter bean standard
+ * for methods that take arguments so that users get a consistent way to
+ * access those methods in their templates. i.e.
+ *
+ * $url.category("foo")
+ *
+ * instead of
+ *
+ * $url.getCategory("foo")
+ */
+public class PlanetURLModel implements Model {
+    
+    private static Log log = LogFactory.getLog(PlanetURLModel.class);
+    
+    private URLStrategy urlStrategy = null;
+    private Planet planet = null;
+    
+    
+    public PlanetURLModel() {}
+    
+    public String getModelName() {
+        return "url";
+    }
+    
+    public void init(Map initData) throws PlanetException {
+        
+        // grab a reference to the url strategy
+        this.urlStrategy = PlanetFactory.getPlanet().getURLStrategy();
+        
+        // need a weblog request so that we can know the weblog and locale
+        PlanetRequest planetRequest = (PlanetRequest) initData.get("planetRequest");
+        if(planetRequest == null) {
+            throw new PlanetException("Expected 'planetRequest' init param!");
+        }
+        
+        this.planet = planetRequest.getPlanet();
+    }
+    
+    
+    public String getSite() {
+        return PlanetRuntimeConfig.getProperty("site.absoluteurl");
+    }
+    
+        
+    public String getHome() {
+        return urlStrategy.getPlanetURL(planet.getHandle());
+    }
+    
+    
+    public String group(String groupHandle) {
+        return urlStrategy.getPlanetGroupURL(planet.getHandle(), groupHandle, -1);
+    }
+    
+    
+    public String group(String groupHandle, int pageNum) {
+        return urlStrategy.getPlanetGroupURL(planet.getHandle(), groupHandle, pageNum);
+    }
+    
+    
+    public FeedURLS getFeed() {
+        return new FeedURLS();
+    }
+    
+    
+    public String opml(String groupHandle) {
+        return urlStrategy.getPlanetGroupOpmlURL(planet.getHandle(), groupHandle);
+    }
+    
+    
+    ///////  Inner Classes  ///////
+    
+    public class FeedURLS {
+        
+        public String rss(String groupHandle) {
+            return urlStrategy.getPlanetGroupFeedURL(planet.getHandle(), groupHandle, "rss");
+        }
+        
+        public String atom(String groupHandle) {
+            return urlStrategy.getPlanetGroupFeedURL(planet.getHandle(), groupHandle, "atom");
+        }
+    }
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/SiteModel.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/SiteModel.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/SiteModel.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/SiteModel.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering.model; 
+
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.planet.PlanetException;
+import org.apache.roller.planet.business.PlanetFactory;
+import org.apache.roller.planet.business.PlanetManager;
+import org.apache.roller.planet.config.PlanetRuntimeConfig;
+
+
+/**
+ * Model which provides information on an application wide scope.
+ */
+public class SiteModel implements Model {
+    
+    private static Log log = LogFactory.getLog(SiteModel.class);
+    
+    
+    /** 
+     * Creates an un-initialized new instance.
+     */
+    public SiteModel() {}
+    
+    
+    /** 
+     * Template context name to be used for model.
+     */
+    public String getModelName() {
+        return "site";
+    }
+    
+    
+    /** 
+     * Init page model based on request. 
+     */
+    public void init(Map initData) throws PlanetException {
+        // no-op
+    }
+    
+    
+    public String getTitle() {
+        return PlanetRuntimeConfig.getProperty("site.name");
+    }
+    
+    
+    public String getDescription() {
+        return PlanetRuntimeConfig.getProperty("site.description");
+    }
+    
+    
+    /**
+     * Get the list of all planets.
+     */
+    public List getPlanets() {
+        PlanetManager pMgr = PlanetFactory.getPlanet().getPlanetManager();
+        try {
+            return pMgr.getPlanets();
+        } catch(Exception e) {
+            log.error("Error getting planets list", e);
+        }
+        
+        return null;
+    }
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/SiteURLModel.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/SiteURLModel.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/SiteURLModel.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/SiteURLModel.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering.model;
+
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.planet.PlanetException;
+import org.apache.roller.planet.business.PlanetFactory;
+import org.apache.roller.planet.business.URLStrategy;
+import org.apache.roller.planet.config.PlanetRuntimeConfig;
+import org.apache.roller.planet.pojos.Planet;
+import org.apache.roller.planet.ui.rendering.util.PlanetRequest;
+
+
+/**
+ * Provides access to URL building functionality.
+ *
+ * NOTE: we purposely go against the standard getter/setter bean standard
+ * for methods that take arguments so that users get a consistent way to
+ * access those methods in their templates. i.e.
+ *
+ * $url.category("foo")
+ *
+ * instead of
+ *
+ * $url.getCategory("foo")
+ */
+public class SiteURLModel implements Model {
+    
+    private static Log log = LogFactory.getLog(SiteURLModel.class);
+    
+    private URLStrategy urlStrategy = null;
+    
+    
+    public SiteURLModel() {}
+    
+    public String getModelName() {
+        return "url";
+    }
+    
+    public void init(Map initData) throws PlanetException {
+        
+        // grab a reference to the url strategy
+        this.urlStrategy = PlanetFactory.getPlanet().getURLStrategy();
+    }
+    
+    
+    public String getSite() {
+        return PlanetRuntimeConfig.getProperty("site.absoluteurl");
+    }
+    
+    
+    public String planet(String planetHandle) {
+        return this.urlStrategy.getPlanetURL(planetHandle);
+    }
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/UtilitiesModel.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/UtilitiesModel.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/UtilitiesModel.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/model/UtilitiesModel.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,484 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering.model;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.planet.PlanetException;
+import org.apache.roller.util.DateUtil;
+import org.apache.roller.util.RegexUtil;
+import org.apache.roller.planet.util.Utilities;
+
+
+/**
+ * Model which provides access to a set of general utilities.
+ */
+public class UtilitiesModel implements Model {
+    
+    private static Log log = LogFactory.getLog(UtilitiesModel.class); 
+    
+    private static Pattern mLinkPattern =
+            Pattern.compile("<a href=.*?>", Pattern.CASE_INSENSITIVE);    
+    private static final Pattern OPENING_B_TAG_PATTERN = 
+            Pattern.compile("&lt;b&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern CLOSING_B_TAG_PATTERN = 
+            Pattern.compile("&lt;/b&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern OPENING_I_TAG_PATTERN = 
+            Pattern.compile("&lt;i&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern CLOSING_I_TAG_PATTERN = 
+            Pattern.compile("&lt;/i&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern OPENING_BLOCKQUOTE_TAG_PATTERN = 
+            Pattern.compile("&lt;blockquote&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern CLOSING_BLOCKQUOTE_TAG_PATTERN = 
+            Pattern.compile("&lt;/blockquote&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern BR_TAG_PATTERN = 
+            Pattern.compile("&lt;br */*&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern OPENING_P_TAG_PATTERN = 
+            Pattern.compile("&lt;p&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern CLOSING_P_TAG_PATTERN = 
+            Pattern.compile("&lt;/p&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern OPENING_PRE_TAG_PATTERN = 
+            Pattern.compile("&lt;pre&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern CLOSING_PRE_TAG_PATTERN = 
+            Pattern.compile("&lt;/pre&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern OPENING_UL_TAG_PATTERN = 
+            Pattern.compile("&lt;ul&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern CLOSING_UL_TAG_PATTERN = 
+            Pattern.compile("&lt;/ul&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern OPENING_OL_TAG_PATTERN = 
+            Pattern.compile("&lt;ol&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern CLOSING_OL_TAG_PATTERN = 
+            Pattern.compile("&lt;/ol&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern OPENING_LI_TAG_PATTERN = 
+            Pattern.compile("&lt;li&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern CLOSING_LI_TAG_PATTERN = 
+            Pattern.compile("&lt;/li&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern CLOSING_A_TAG_PATTERN = 
+            Pattern.compile("&lt;/a&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern OPENING_A_TAG_PATTERN = 
+            Pattern.compile("&lt;a href=.*?&gt;", Pattern.CASE_INSENSITIVE);
+    private static final Pattern QUOTE_PATTERN = 
+            Pattern.compile("&quot;", Pattern.CASE_INSENSITIVE);
+    
+    private TimeZone tz = null;
+    
+    
+    /** Template context name to be used for model */
+    public String getModelName() {
+        return "utils";
+    }
+    
+    
+    /** Init page model based on request */
+    public void init(Map initData) throws PlanetException {
+    }
+    
+        
+    //-------------------------------------------------------------- Date utils
+    /**
+     * Return date for current time.
+     */
+    public static Date getNow() {
+        return new Date();
+    }
+    
+    /**
+     * Format date using SimpleDateFormat format string.
+     */
+    public String formatDate(Date d, String fmt) {
+        if(d == null || fmt == null)
+            return fmt;
+        
+        SimpleDateFormat format = new SimpleDateFormat(fmt);
+        if (tz != null) {
+            format.setTimeZone(tz);
+        }
+        return format.format(d);
+    }
+    
+    /**
+     * Format date using SimpleDateFormat format string.
+     */
+    public static String formatDate(Date d, String fmt, TimeZone tzOverride) {
+        if(d == null || fmt == null)
+            return fmt;
+        
+        SimpleDateFormat format = new SimpleDateFormat(fmt);
+        format.setTimeZone(tzOverride);
+        return format.format(d);
+    }
+    
+    /**
+     * Format date in ISO-8601 format.
+     */
+    public static String formatIso8601Date(Date d) {
+        return DateUtil.formatIso8601(d);
+    }
+    
+    /**
+     * Format date in ISO-8601 format.
+     */
+    public static String formatIso8601Day(Date d) {
+        return DateUtil.formatIso8601Day(d);
+    }
+    
+    /**
+     * Return a date in RFC-822 format.
+     */
+    public static String formatRfc822Date(Date date) {
+        return DateUtil.formatRfc822(date);
+    }
+    
+    /**
+     * Return a date in RFC-822 format.
+     */
+    public static String format8charsDate(Date date) {
+        return DateUtil.format8chars(date);
+    }
+
+    //------------------------------------------------------------ String utils
+    
+    public static boolean isEmpty(String str) {
+        if (str == null) return true;
+        return "".equals(str.trim());
+    }
+    
+    public static boolean isNotEmpty(String str) {
+        return !isEmpty(str);
+    }
+    
+    public static String[] split(String str1, String str2) {
+        return StringUtils.split(str1, str2);
+    }
+    
+    
+    public static boolean equals(String str1, String str2) {
+        return StringUtils.equals(str1, str2);
+    }
+    
+    public static boolean isAlphanumeric(String str) {
+        return StringUtils.isAlphanumeric(str);
+    }
+    
+    public static String[] stripAll(String[] strs) {
+        return StringUtils.stripAll(strs);
+    }
+    
+    public static String left(String str, int length) {
+        return StringUtils.left(str, length);
+    }
+    
+    public static String escapeHTML(String str) {
+        return StringEscapeUtils.escapeHtml(str);
+    }
+    
+    public static String unescapeHTML(String str) {
+        return StringEscapeUtils.unescapeHtml(str);
+    }
+    
+    public static String escapeXML(String str) {
+        return StringEscapeUtils.escapeXml(str);
+    }
+    
+    public static String unescapeXML(String str) {
+        return StringEscapeUtils.unescapeXml(str);
+    }
+    
+    public static String replace(String src, String target, String rWith) {
+        return StringUtils.replace(src, target, rWith);
+    }
+    
+    public static String replace(String src, String target, String rWith, int maxCount) {
+        return StringUtils.replace(src, target, rWith, maxCount);
+    }
+    
+    private static String replace(String string, Pattern pattern, String replacement) {
+        Matcher m = pattern.matcher(string);
+        return m.replaceAll(replacement);
+    }
+    
+    /**
+     * Remove occurences of html, defined as any text
+     * between the characters "&lt;" and "&gt;".  Replace
+     * any HTML tags with a space.
+     */
+    public static String removeHTML(String str) {
+        return removeHTML(str, true);
+    }
+    
+    /**
+     * Remove occurences of html, defined as any text
+     * between the characters "&lt;" and "&gt;".
+     * Optionally replace HTML tags with a space.
+     */
+    public static String removeHTML(String str, boolean addSpace) {
+        return Utilities.removeHTML(str, addSpace);
+    }
+        
+    /**
+     * Autoformat.
+     */
+    public static String autoformat(String s) {
+        String ret = StringUtils.replace(s, "\n", "<br />");
+        return ret;
+    }
+    /**
+     * Strips HTML and truncates.
+     */
+    public static String truncate(
+            String str, int lower, int upper, String appendToEnd) {
+        // strip markup from the string
+        String str2 = removeHTML(str, false);
+        
+        // quickly adjust the upper if it is set lower than 'lower'
+        if (upper < lower) {
+            upper = lower;
+        }
+        
+        // now determine if the string fits within the upper limit
+        // if it does, go straight to return, do not pass 'go' and collect $200
+        if(str2.length() > upper) {
+            // the magic location int
+            int loc;
+            
+            // first we determine where the next space appears after lower
+            loc = str2.lastIndexOf(' ', upper);
+            
+            // now we'll see if the location is greater than the lower limit
+            if(loc >= lower) {
+                // yes it was, so we'll cut it off here
+                str2 = str2.substring(0, loc);
+            } else {
+                // no it wasnt, so we'll cut it off at the upper limit
+                str2 = str2.substring(0, upper);
+                loc = upper;
+            }
+            
+            // the string was truncated, so we append the appendToEnd String
+            str2 = str2 + appendToEnd;
+        }
+        
+        return str2;
+    }
+    
+    public static String truncateNicely(String str, int lower, int upper, String appendToEnd) {
+        return Utilities.truncateNicely(str, lower, upper, appendToEnd);
+    }
+    
+    public static String truncateText(String str, int lower, int upper, String appendToEnd) {
+        // strip markup from the string
+        String str2 = removeHTML(str, false);
+        boolean diff = (str2.length() < str.length());
+        
+        // quickly adjust the upper if it is set lower than 'lower'
+        if(upper < lower) {
+            upper = lower;
+        }
+        
+        // now determine if the string fits within the upper limit
+        // if it does, go straight to return, do not pass 'go' and collect $200
+        if(str2.length() > upper) {
+            // the magic location int
+            int loc;
+            
+            // first we determine where the next space appears after lower
+            loc = str2.lastIndexOf(' ', upper);
+            
+            // now we'll see if the location is greater than the lower limit
+            if(loc >= lower) {
+                // yes it was, so we'll cut it off here
+                str2 = str2.substring(0, loc);
+            } else {
+                // no it wasnt, so we'll cut it off at the upper limit
+                str2 = str2.substring(0, upper);
+                loc = upper;
+            }
+            // the string was truncated, so we append the appendToEnd String
+            str = str2 + appendToEnd;
+        }
+        return str;
+    }    
+    
+    public static String hexEncode(String str) {
+        if (StringUtils.isEmpty(str)) return str;
+        
+        return RegexUtil.encode(str);
+    }
+    
+    public static String encodeEmail(String str) {
+        return str!=null ? RegexUtil.encodeEmail(str) : null;
+    }
+    
+    /**
+     * URL encoding.
+     * @param s a string to be URL-encoded
+     * @return URL encoding of s using character encoding UTF-8; null if s is null.
+     */
+    public static final String encode(String s) {
+        try {
+            if (s != null)
+                return URLEncoder.encode(s, "UTF-8");
+            else
+                return s;
+        } catch (UnsupportedEncodingException e) {
+            // Java Spec requires UTF-8 be in all Java environments, so this should not happen
+            return s;
+        }
+    }
+    
+    /**
+     * URL decoding.
+     * @param s a URL-encoded string to be URL-decoded
+     * @return URL decoded value of s using character encoding UTF-8; null if s is null.
+     */
+    public static final String decode(String s) {
+        try {
+            if (s != null)
+                return URLDecoder.decode(s, "UTF-8");
+            else
+                return s;
+        } catch (UnsupportedEncodingException e) {
+            // Java Spec requires UTF-8 be in all Java environments, so this should not happen
+            return s;
+        }
+    }
+        
+    /**
+     * Code (stolen from Pebble) to add rel="nofollow" string to all links in HTML.
+     */
+    public static String addNofollow(String html) {
+        if (html == null || html.length() == 0) {
+            return html;
+        }
+        Matcher m = mLinkPattern.matcher(html);
+        StringBuffer buf = new StringBuffer();
+        while (m.find()) {
+            int start = m.start();
+            int end = m.end();
+            String link = html.substring(start, end);
+            buf.append(html.substring(0, start));
+            if (link.indexOf("rel=\"nofollow\"") == -1) {
+                buf.append(
+                        link.substring(0, link.length() - 1) + " rel=\"nofollow\">");
+            } else {
+                buf.append(link);
+            }
+            html = html.substring(end, html.length());
+            m = mLinkPattern.matcher(html);
+        }
+        buf.append(html);
+        return buf.toString();
+    }
+    
+    /**
+     * Transforms the given String into a subset of HTML displayable on a web
+     * page. The subset includes &lt;b&gt;, &lt;i&gt;, &lt;p&gt;, &lt;br&gt;,
+     * &lt;pre&gt; and &lt;a href&gt; (and their corresponding end tags).
+     *
+     * @param s   the String to transform
+     * @return    the transformed String
+     */
+    public static String transformToHTMLSubset(String s) {
+        
+        if (s == null) {
+            return null;
+        }
+        
+        s = replace(s, OPENING_B_TAG_PATTERN, "<b>");
+        s = replace(s, CLOSING_B_TAG_PATTERN, "</b>");
+        s = replace(s, OPENING_I_TAG_PATTERN, "<i>");
+        s = replace(s, CLOSING_I_TAG_PATTERN, "</i>");
+        s = replace(s, OPENING_BLOCKQUOTE_TAG_PATTERN, "<blockquote>");
+        s = replace(s, CLOSING_BLOCKQUOTE_TAG_PATTERN, "</blockquote>");
+        s = replace(s, BR_TAG_PATTERN, "<br />");
+        s = replace(s, OPENING_P_TAG_PATTERN, "<p>");
+        s = replace(s, CLOSING_P_TAG_PATTERN, "</p>");
+        s = replace(s, OPENING_PRE_TAG_PATTERN, "<pre>");
+        s = replace(s, CLOSING_PRE_TAG_PATTERN, "</pre>");
+        s = replace(s, OPENING_UL_TAG_PATTERN, "<ul>");
+        s = replace(s, CLOSING_UL_TAG_PATTERN, "</ul>");
+        s = replace(s, OPENING_OL_TAG_PATTERN, "<ol>");
+        s = replace(s, CLOSING_OL_TAG_PATTERN, "</ol>");
+        s = replace(s, OPENING_LI_TAG_PATTERN, "<li>");
+        s = replace(s, CLOSING_LI_TAG_PATTERN, "</li>");
+        s = replace(s, QUOTE_PATTERN, "\"");
+        
+        // HTTP links
+        s = replace(s, CLOSING_A_TAG_PATTERN, "</a>");
+        Matcher m = OPENING_A_TAG_PATTERN.matcher(s);
+        while (m.find()) {
+            int start = m.start();
+            int end = m.end();
+            String link = s.substring(start, end);
+            link = "<" + link.substring(4, link.length() - 4) + ">";
+            s = s.substring(0, start) + link + s.substring(end, s.length());
+            m = OPENING_A_TAG_PATTERN.matcher(s);
+        }
+        
+        // escaped angle brackets
+        s = s.replaceAll("&amp;lt;", "&lt;");
+        s = s.replaceAll("&amp;gt;", "&gt;");
+        s = s.replaceAll("&amp;#", "&#");
+        
+        return s;
+    }
+    
+    /**
+     * Convert a byte array into a Base64 string (as used in mime formats)
+     */
+    public static String toBase64(byte[] aValue) {
+        
+        final String m_strBase64Chars =
+                "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+        
+        int byte1;
+        int byte2;
+        int byte3;
+        int iByteLen = aValue.length;
+        StringBuffer tt = new StringBuffer();
+        
+        for (int i = 0; i < iByteLen; i += 3) {
+            boolean bByte2 = (i + 1) < iByteLen;
+            boolean bByte3 = (i + 2) < iByteLen;
+            byte1 = aValue[i] & 0xFF;
+            byte2 = (bByte2) ? (aValue[i + 1] & 0xFF) : 0;
+            byte3 = (bByte3) ? (aValue[i + 2] & 0xFF) : 0;
+            
+            tt.append(m_strBase64Chars.charAt(byte1 / 4));
+            tt.append(m_strBase64Chars.charAt((byte2 / 16) + ((byte1 & 0x3) * 16)));
+            tt.append(((bByte2) ? m_strBase64Chars.charAt((byte3 / 64) + ((byte2 & 0xF) * 4)) : '='));
+            tt.append(((bByte3) ? m_strBase64Chars.charAt(byte3 & 0x3F) : '='));
+        }
+        
+        return tt.toString();
+    }
+       
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/pagers/AbstractPager.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/pagers/AbstractPager.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/pagers/AbstractPager.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/pagers/AbstractPager.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering.pagers;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.roller.planet.util.URLUtilities;
+
+
+/**
+ * Abstract base for simple pagers.
+ */
+public abstract class AbstractPager implements Pager {
+    
+    private String url = null;
+    private int page = 0;
+    
+    
+    public AbstractPager(String baseUrl, int pageNum) {
+        
+        this.url = baseUrl;
+        if(pageNum > 0) {
+            this.page = pageNum;
+        }
+    }
+    
+    
+    public String getHomeLink() {
+        return url;
+    }
+    
+    
+    public String getHomeName() {
+        return "Home";
+    }
+    
+    
+    public String getNextLink() {
+        if(hasMoreItems()) {
+            int nextPage = page + 1;
+            Map params = new HashMap();
+            params.put("page", ""+nextPage);
+            return createURL(url, params);
+        }
+        return null;
+    }
+    
+    
+    public String getNextName() {
+        if(hasMoreItems()) {
+            return "Next";
+        }
+        return null;
+    }
+    
+    
+    public String getPrevLink() {
+        if (page > 1) {
+            int prevPage = page - 1;
+            Map params = new HashMap();
+            params.put("page", ""+prevPage);
+            return createURL(url, params);
+        } else if (page == 1) {
+            return url;
+        }
+        return null;
+    }
+    
+    
+    public String getPrevName() {
+        if (page > 0) {
+            return "Previous";
+        }
+        return null;
+    }
+    
+    
+    public boolean hasMoreItems() {
+        return false;
+    }
+    
+    
+    protected String createURL(String url, Map params) {
+        
+        return url + URLUtilities.getQueryString(params);
+    }
+
+    
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public int getPage() {
+        return page;
+    }
+
+    public void setPage(int page) {
+        this.page = page;
+    }
+    
+}

Added: roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/pagers/Pager.java
URL: http://svn.apache.org/viewvc/roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/pagers/Pager.java?rev=925653&view=auto
==============================================================================
--- roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/pagers/Pager.java (added)
+++ roller/trunk/planet-web/src/main/java/org/apache/roller/planet/ui/rendering/pagers/Pager.java Sat Mar 20 18:37:51 2010
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.planet.ui.rendering.pagers;
+
+import java.util.List;
+
+/**
+ * Common pager interface.
+ */
+public interface Pager {
+    /**
+     * Link value for returning to pager home
+     */
+    public String getHomeLink();
+
+    /**
+     * Name of pager home.
+     */
+    public String getHomeName();
+
+    /**
+     * Link value for next page in current collection view
+     */
+    public String getNextLink();
+
+    /**
+     * Name for next page in current collection view
+     */
+    public String getNextName();
+
+    /**
+     * Link value for prev page in current collection view
+     */
+    public String getPrevLink();
+
+    /**
+     * Link value for prev page in current collection view
+     */
+    public String getPrevName();
+    
+    /**
+     * Get current list of items available from the pager.
+     */
+    public List getItems();
+    
+}