You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@roller.apache.org by ag...@apache.org on 2005/07/06 01:32:00 UTC

svn commit: r209350 - in /incubator/roller/trunk/src/org/roller: ./ business/ model/ pojos/ presentation/velocity/ presentation/velocity/wrappers/

Author: agilliland
Date: Tue Jul  5 16:31:59 2005
New Revision: 209350

URL: http://svn.apache.org/viewcvs?rev=209350&view=rev
Log:
New classes for Theme Management.


Added:
    incubator/roller/trunk/src/org/roller/ThemeNotFoundException.java
    incubator/roller/trunk/src/org/roller/business/ThemeManagerImpl.java
    incubator/roller/trunk/src/org/roller/model/Template.java
    incubator/roller/trunk/src/org/roller/model/ThemeManager.java
    incubator/roller/trunk/src/org/roller/pojos/Theme.java
    incubator/roller/trunk/src/org/roller/pojos/ThemeTemplate.java
    incubator/roller/trunk/src/org/roller/presentation/velocity/ThemeResourceLoader.java
    incubator/roller/trunk/src/org/roller/presentation/velocity/wrappers/
    incubator/roller/trunk/src/org/roller/presentation/velocity/wrappers/TemplateWrapper.java

Added: incubator/roller/trunk/src/org/roller/ThemeNotFoundException.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/ThemeNotFoundException.java?rev=209350&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/ThemeNotFoundException.java (added)
+++ incubator/roller/trunk/src/org/roller/ThemeNotFoundException.java Tue Jul  5 16:31:59 2005
@@ -0,0 +1,33 @@
+/*
+ * ThemeNotFoundException.java
+ *
+ * Created on June 28, 2005, 12:48 PM
+ */
+
+package org.roller;
+
+
+/**
+ * Thrown when the ThemeManager has a problem finding a named theme.
+ *
+ * @author Allen Gilliland
+ */
+public class ThemeNotFoundException extends RollerException {
+    
+    public ThemeNotFoundException(String s,Throwable t) {
+        super(s, t);
+    }
+    
+    public ThemeNotFoundException(Throwable t) {
+        super(t);
+    }
+    
+    public ThemeNotFoundException(String s) {
+        super(s);
+    }
+    
+    public ThemeNotFoundException() {
+        super();
+    }
+    
+}

Added: incubator/roller/trunk/src/org/roller/business/ThemeManagerImpl.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/business/ThemeManagerImpl.java?rev=209350&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/business/ThemeManagerImpl.java (added)
+++ incubator/roller/trunk/src/org/roller/business/ThemeManagerImpl.java Tue Jul  5 16:31:59 2005
@@ -0,0 +1,272 @@
+/*
+ * ThemeManagerImpl.java
+ *
+ * Created on June 27, 2005, 1:33 PM
+ */
+
+package org.roller.business;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FilenameFilter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.roller.RollerException;
+import org.roller.ThemeNotFoundException;
+import org.roller.config.RollerConfig;
+import org.roller.model.ThemeManager;
+import org.roller.pojos.Theme;
+import org.roller.pojos.ThemeTemplate;
+
+
+/**
+ * Base implementation of a ThemeManager.
+ * 
+ * This particular implementation reads theme data off the filesystem 
+ * and assumes that those themes are not changable at runtime.
+ *
+ * @author Allen Gilliland
+ */
+public class ThemeManagerImpl implements ThemeManager {
+    
+    private static Log mLogger = 
+        LogFactory.getFactory().getInstance(ThemeManagerImpl.class);
+    
+    private Map themes;
+    
+    
+    protected ThemeManagerImpl() {
+        
+        // rather than be lazy we are going to load all themes from
+        // the disk preemptively during initialization and cache them
+        mLogger.debug("Initializing ThemeManagerImpl");
+        mLogger.info("Loading all themes from disk ... ");
+        this.themes = this.loadAllThemesFromDisk();
+    }
+    
+    
+    /**
+     * @see org.roller.model.ThemeManager#getTheme(java.lang.String)
+     */
+    public Theme getTheme(String name) 
+        throws ThemeNotFoundException, RollerException {
+        
+        Theme theme = (Theme) this.themes.get(name);
+        if(theme == null)
+            throw new ThemeNotFoundException("Couldn't find theme ["+name+"]");
+        
+        return theme;
+    }
+    
+    
+    /**
+     * @see org.roller.model.ThemeManager#getThemeById(java.lang.String)
+     */
+    public Theme getThemeById(String id) 
+        throws ThemeNotFoundException, RollerException {
+        
+        // In this implementation where themes come from the filesystem we
+        // know that the name and id for a theme are the same
+        return this.getTheme(id);
+    }
+    
+    
+    /**
+     * @see org.roller.model.ThemeManager#getThemesList()
+     */
+    public List getThemesList() {
+        
+        List themes = new ArrayList(this.themes.keySet());
+        
+        // sort 'em ... the natural sorting order for Strings is alphabetical
+        Collections.sort(themes);
+        
+        return themes;
+    }
+    
+    
+    /**
+     * @see org.roller.model.ThemeManager#getEnabledThemesList()
+     */
+    public List getEnabledThemesList() {
+        
+        Collection all_themes = this.themes.values();
+        
+        // make a new list of only the enabled themes
+        List enabled_themes = new ArrayList();
+        Iterator it = all_themes.iterator();
+        Theme theme = null;
+        while(it.hasNext()) {
+            theme = (Theme) it.next();
+            if(theme.isEnabled())
+                enabled_themes.add(theme.getName());
+        }
+                
+        // sort 'em ... the natural sorting order for Strings is alphabetical
+        Collections.sort(enabled_themes);
+        
+        return enabled_themes;
+    }
+    
+    
+    /**
+     * @see org.roller.model.ThemeManager#getTemplate(String, String)
+     */
+    public ThemeTemplate getTemplate(String theme_name, String template_name)
+        throws ThemeNotFoundException, RollerException {
+        
+        // basically we just try and lookup the theme first, then template
+        Theme theme = this.getTheme(theme_name);
+        
+        return theme.getTemplate(template_name);
+    }
+    
+    
+    /**
+     * @see org.roller.model.ThemeManager#getTemplateById(java.lang.String)
+     */
+    public ThemeTemplate getTemplateById(String id)
+        throws ThemeNotFoundException, RollerException {
+        
+        if(id == null)
+            throw new ThemeNotFoundException("Theme id was null");
+        
+        // in our case we expect a template id to be <theme>:<template>
+        // so extract each piece and do the lookup
+        String[] split = id.split(":",  2);
+        if(split.length != 2)
+            throw new ThemeNotFoundException("Invalid theme id ["+id+"]");
+        
+        return this.getTemplate(split[0], split[1]);
+    }
+    
+    
+    /**
+     * @see org.roller.model.ThemeManager#getTemplateByLink(java.lang.String)
+     */
+    public ThemeTemplate getTemplateByLink(String theme_name, String template_link)
+        throws ThemeNotFoundException, RollerException {
+        
+        // basically we just try and lookup the theme first, then template
+        Theme theme = this.getTheme(theme_name);
+        
+        return theme.getTemplateByLink(template_link);
+    }
+    
+    
+    /**
+     * This is a convenience method which loads all the theme data from
+     * themes stored on the filesystem in the roller webapp /themes/ directory.
+     */
+    private Map loadAllThemesFromDisk() {
+        
+        Map themes = new HashMap();
+        
+        // NOTE: we need to figure out how to get the roller context path
+        String themespath = RollerConfig.getProperty("context.realpath");
+        if(themespath.endsWith(File.separator))
+            themespath += "themes";
+        else
+            themespath += File.separator + "themes";
+        
+        // first, get a list of the themes available
+        File themesdir = new File(themespath);
+        FilenameFilter filter = new FilenameFilter() {
+            public boolean accept(File dir, String name) {
+                File file =
+                        new File(dir.getAbsolutePath() + File.separator + name);
+                return file.isDirectory();
+            }
+        };
+        String[] themenames = themesdir.list(filter);
+        
+        // now go through each theme and read all it's templates
+        Theme theme = null;
+        for(int i=0; i < themenames.length; i++) {
+            theme = this.loadThemeFromDisk(themenames[i], 
+                        themespath + File.separator + themenames[i]);
+            
+            themes.put(theme.getName(), theme);
+        }
+        
+        return themes;
+    }
+    
+    
+    /**
+     * Another convenience method which knows how to load a single theme
+     * off the filesystem and return a Theme object
+     */
+    private Theme loadThemeFromDisk(String theme_name, String themepath) {
+        
+        mLogger.debug("Loading theme "+theme_name+" from "+themepath);
+        
+        Theme theme = new Theme();
+        theme.setName(theme_name);
+        theme.setAuthor("Roller");
+        theme.setLastEditor("Roller");
+        theme.setEnabled(true);
+        
+        // start by getting a list of the .vm files for this theme
+        File themedir = new File(themepath);
+        FilenameFilter filter = new FilenameFilter()
+        {
+            public boolean accept(File dir, String name)
+            {
+                return name.endsWith(".vm");
+            }
+        };
+        String[] templates = themedir.list(filter);
+        
+        // go through each .vm file and read in its contents to a ThemeTemplate
+        String template_name = null;
+        ThemeTemplate theme_template = null;
+        for (int i=0; i < templates.length; i++) {
+            // strip off the .vm part
+            template_name = templates[i].substring(0, templates[i].length() - 3);
+            
+            try {
+                File template_file = new File(themepath + File.separator + templates[i]);
+                
+                if(!template_file.exists() && !template_file.canRead()) {
+                    mLogger.warn("Couldn't read theme template file ["+template_file.getPath()+"]");
+                    continue;
+                }
+                
+                FileReader reader = new FileReader(template_file);
+                char[] chars = new char[(int) template_file.length()];
+                reader.read(chars);
+                
+                // construct ThemeTemplate representing this file
+                theme_template = new ThemeTemplate(
+                        theme_name+":"+template_name,
+                        template_name,
+                        template_name,
+                        new String(chars),
+                        template_name,
+                        new Date(template_file.lastModified()));
+                
+                // add it to the theme
+                theme.setTemplate(template_name, theme_template);
+                
+            } catch (Exception e) {
+                // warn?
+            }
+        }
+        
+        // use the last mod date of the last template file
+        // as the last mod date of the theme
+        theme.setLastModified(theme_template.getLastModified());
+        
+        return theme;
+    }
+
+}

Added: incubator/roller/trunk/src/org/roller/model/Template.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/model/Template.java?rev=209350&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/model/Template.java (added)
+++ incubator/roller/trunk/src/org/roller/model/Template.java Tue Jul  5 16:31:59 2005
@@ -0,0 +1,37 @@
+/*
+ * Template.java
+ *
+ * Created on June 27, 2005, 11:59 AM
+ */
+
+package org.roller.model;
+
+import java.util.Date;
+
+
+/**
+ * The Template interface represents the abstract concept of a single unit
+ * of templated or non-rendered content.  For Roller we mainly think of
+ * templates as Velocity templates which are meant to be fed into the 
+ * Velocity rendering engine.
+ *
+ * @author Allen Gilliland
+ */
+public interface Template {
+    
+    public String getId();
+    public String getName();
+    public String getDescription();
+    public String getContents();
+    public String getLink();
+    public Date getLastModified();
+    
+    /*
+    public void setId(String id);
+    public void setName(String name);
+    public void setDescription(String desc);
+    public void setContents(String contents);
+    public void setLink(String link);
+    public void setLastModified(Date date);
+    */
+}

Added: incubator/roller/trunk/src/org/roller/model/ThemeManager.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/model/ThemeManager.java?rev=209350&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/model/ThemeManager.java (added)
+++ incubator/roller/trunk/src/org/roller/model/ThemeManager.java Tue Jul  5 16:31:59 2005
@@ -0,0 +1,99 @@
+/*
+ * ThemeManager.java
+ *
+ * Created on June 27, 2005, 12:49 PM
+ */
+
+package org.roller.model;
+
+import java.util.List;
+import org.roller.RollerException;
+import org.roller.ThemeNotFoundException;
+import org.roller.pojos.Theme;
+import org.roller.pojos.ThemeTemplate;
+
+
+/**
+ * Manager interface for accessing Theme related objects.
+ *
+ * @author Allen Gilliland
+ */
+public interface ThemeManager {
+    
+    /**
+     * Get the Theme object with the given name.
+     *
+     * @throws ThemeNotFoundException If the named theme cannot be found.
+     * @throws RollerException If there is some kind of fatal backend error.
+     **/
+    public Theme getTheme(String name)
+        throws ThemeNotFoundException, RollerException;
+    
+    
+    /**
+     * Get the Theme object with the given theme id.
+     *
+     * @throws ThemeNotFoundException If the named theme cannot be found.
+     * @throws RollerException If there is some kind of fatal backend error.
+     */
+    public Theme getThemeById(String theme_id)
+        throws ThemeNotFoundException, RollerException;
+    
+    
+    /**
+     * Get a list of all available themes.
+     * This list is ordered alphabetically by default.
+     *
+     * NOTE: this only returns a list of theme names, not actual Theme objects.
+     **/
+    public List getThemesList();
+    
+    
+    /**
+     * Get a list of all theme names that are currently enabled.
+     * This list is ordered alphabetically by default.
+     *
+     * NOTE: this only returns a list of theme names, not actual Theme objects.
+     */
+    public List getEnabledThemesList();
+    
+    
+    /**
+     * Get the template from a given theme.
+     *
+     * @throws ThemeNotFoundException If the named theme cannot be found.
+     * @throws RollerException If there is some kind of fatal backend error.
+     */
+    public ThemeTemplate getTemplate(String theme_name, String template_name)
+        throws ThemeNotFoundException, RollerException;
+    
+    
+    /**
+     * Get the template from a given theme using the template id.
+     *
+     * Theme templates use a special id value when they come off the filesystem.
+     * When a theme is read off the filesystem it's templates are given an id
+     * like ... <theme name>:<template name>
+     *
+     * @throws ThemeNotFoundException If the named theme cannot be found.
+     * @throws RollerException If there is some kind of fatal backend error.
+     */
+    public ThemeTemplate getTemplateById(String template_id)
+        throws ThemeNotFoundException, RollerException;
+
+    
+    /**
+     * Get the template from a given theme using the template link value.
+     *
+     * Note that for themes we enforce the rule that 
+     *      Theme.name == Theme.link
+     *
+     * So doing a lookup by link is the same as doing a lookup by name.
+     *
+     * @throws ThemeNotFoundException If the named theme cannot be found.
+     * @throws RollerException If there is some kind of fatal backend error.
+     */
+    public ThemeTemplate getTemplateByLink(String theme_name, String template_link)
+        throws ThemeNotFoundException, RollerException;
+    
+}

Added: incubator/roller/trunk/src/org/roller/pojos/Theme.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/Theme.java?rev=209350&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/pojos/Theme.java (added)
+++ incubator/roller/trunk/src/org/roller/pojos/Theme.java Tue Jul  5 16:31:59 2005
@@ -0,0 +1,173 @@
+/*
+ * Theme.java
+ *
+ * Created on June 27, 2005, 12:55 PM
+ */
+
+package org.roller.pojos;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+
+/**
+ * The Theme object encapsulates all elements of a single weblog theme.  It
+ * is used mostly to contain all the templates for a theme, but does contain
+ * other theme related attributes such as name, last modifed date, etc.
+ *
+ * @author Allen Gilliland
+ */
+public class Theme implements Serializable {
+    
+    // this is the name that will be used to identify a user customized theme
+    public static final String CUSTOM = "custom";
+    
+    private String id;
+    private String name;
+    private String description;
+    private String author;
+    private String lastEditor; // user id value of last editor
+    private Date lastModified;
+    private boolean enabled;
+    
+    // we keep templates in a Map for faster lookups by name
+    // the Map contains ... (template name, ThemeTemplate)
+    private Map templates;
+    
+    
+    public Theme() {
+        this.id = null;
+        this.name = null;
+        this.description = null;
+        this.author = null;
+        this.lastEditor = null;
+        this.lastModified = null;
+        this.enabled = false;
+        this.templates = new HashMap();
+    }
+
+    
+    /**
+     * Get the collection of all templates associated with this Theme.
+     */
+    public Collection getTemplates() {
+        return this.templates.values();
+    }
+    
+    
+    /**
+     * Lookup the specified template by name.
+     * Returns null if the template cannot be found.
+     */
+    public ThemeTemplate getTemplate(String name) {
+        return (ThemeTemplate) this.templates.get(name);
+    }
+    
+    
+    /**
+     * Lookup the specified template by link.
+     * Returns null if the template cannot be found.
+     *
+     * NOTE: for themes we enforce the rule that 
+     *          Theme.link == Theme.name
+     *
+     * So this lookup is basically the same as lookup by name.
+     */
+    public ThemeTemplate getTemplateByLink(String link) {
+        return (ThemeTemplate) this.templates.get(link);
+    }
+    
+    
+    /**
+     * Set the value for a given template name.
+     */
+    public void setTemplate(String name, ThemeTemplate template) {
+        this.templates.put(name, template);
+    }
+    
+    
+    /**
+     * Check if this Theme contains the named template.
+     * Returns true if the template exists, false otherwise.
+     */
+    public boolean hasTemplate(String name) {
+        return this.templates.containsKey(name);
+    }
+    
+    
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+    
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getAuthor() {
+        return author;
+    }
+
+    public void setAuthor(String author) {
+        this.author = author;
+    }
+
+    public String getLastEditor() {
+        return lastEditor;
+    }
+
+    public void setLastEditor(String lastEditor) {
+        this.lastEditor = lastEditor;
+    }
+
+    public Date getLastModified() {
+        return lastModified;
+    }
+
+    public void setLastModified(Date lastModified) {
+        this.lastModified = lastModified;
+    }
+    
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+    
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(name);
+        sb.append("\n");
+        
+        Iterator it = this.templates.values().iterator();
+        while(it.hasNext()) {
+            sb.append(it.next());
+            sb.append("\n");
+        }
+        
+        return sb.toString();
+        
+    }
+
+}

Added: incubator/roller/trunk/src/org/roller/pojos/ThemeTemplate.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/ThemeTemplate.java?rev=209350&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/pojos/ThemeTemplate.java (added)
+++ incubator/roller/trunk/src/org/roller/pojos/ThemeTemplate.java Tue Jul  5 16:31:59 2005
@@ -0,0 +1,97 @@
+/*
+ * ThemeTemplate.java
+ *
+ * Created on June 27, 2005, 12:14 PM
+ */
+
+package org.roller.pojos;
+
+import java.io.Serializable;
+import java.util.Date;
+import org.roller.model.Template;
+
+
+/**
+ * A Theme based implementation of a Template.  A ThemeTemplate represents a
+ * template which is part of a shared Theme.
+ *
+ * @author Allen Gilliland
+ */
+public class ThemeTemplate implements Template, Serializable {
+    
+    private String id;
+    private String name;
+    private String description;
+    private String contents;
+    private String link;
+    private Date lastModified;
+    
+    
+    public ThemeTemplate() {}
+    
+    public ThemeTemplate(String id, String name, 
+                String desc, String contents, String link, Date date) {
+        
+        this.id = id;
+        this.name = name;
+        this.description = desc;
+        this.contents = contents;
+        this.link = link;
+        this.lastModified = date;
+    }
+    
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getContents() {
+        return contents;
+    }
+
+    public void setContents(String contents) {
+        this.contents = contents;
+    }
+
+    public Date getLastModified() {
+        return lastModified;
+    }
+
+    public void setLastModified(Date lastModified) {
+        this.lastModified = lastModified;
+    }
+
+    public String getLink() {
+        return link;
+    }
+
+    public void setLink(String link) {
+        this.link = link;
+    }
+    
+    public String toString() {
+        return (id + "," + name + "," + description + "," + link + "," + 
+                lastModified + "\n\n" + contents + "\n");
+    }
+    
+}

Added: incubator/roller/trunk/src/org/roller/presentation/velocity/ThemeResourceLoader.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/ThemeResourceLoader.java?rev=209350&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/ThemeResourceLoader.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/ThemeResourceLoader.java Tue Jul  5 16:31:59 2005
@@ -0,0 +1,130 @@
+/*
+ * ThemeResourceLoader.java
+ *
+ * Created on June 28, 2005, 12:25 PM
+ */
+
+package org.roller.presentation.velocity;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import org.apache.commons.collections.ExtendedProperties;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.resource.Resource;
+import org.apache.velocity.runtime.resource.loader.ResourceLoader;
+import org.roller.RollerException;
+import org.roller.ThemeNotFoundException;
+import org.roller.model.RollerFactory;
+import org.roller.model.ThemeManager;
+import org.roller.pojos.Theme;
+import org.roller.pojos.ThemeTemplate;
+
+
+/**
+ * The ThemeResourceLoader is a Velocity template loader which loads
+ * templates from shared themes.
+ *
+ * @author Allen Gilliland
+ */
+public class ThemeResourceLoader extends ResourceLoader {
+    
+    private static Log mLogger = 
+        LogFactory.getFactory().getInstance(ThemeResourceLoader.class);
+        
+    
+    public void init(ExtendedProperties configuration) {
+        mLogger.debug(configuration);
+    }
+    
+    
+    public InputStream getResourceStream( String name )
+        throws ResourceNotFoundException {
+        
+        mLogger.debug("Looking up resource named ... "+name);
+        
+        if (name == null || name.length() < 1) {
+            throw new ResourceNotFoundException("Need to specify a template name!");
+        }
+        
+        try {
+            // parse the name ... theme templates name are <theme>:<template>
+            String[] split = name.split(":", 2);
+            if(split.length < 2)
+                throw new ResourceNotFoundException("Invalid ThemeRL key "+name);
+            
+            // lookup the template from the proper theme
+            ThemeManager themeMgr = RollerFactory.getRoller().getThemeManager();
+            Theme theme = themeMgr.getTheme(split[0]);
+            ThemeTemplate template = theme.getTemplate(split[1]);
+            
+            if(template == null)
+                throw new ResourceNotFoundException("Template ["+split[1]+
+                        "] doesn't seem to be part of theme ["+split[0]+"]");
+            
+            mLogger.debug("Resource found!");
+            
+            // return the input stream
+            return new ByteArrayInputStream(template.getContents().getBytes("UTF-8"));
+            
+        } catch (UnsupportedEncodingException uex) {
+            // We expect UTF-8 in all JRE installation.
+            // This rethrows as a Runtime exception after logging.
+            mLogger.error(uex);
+            throw new RuntimeException(uex);
+           
+        } catch (ThemeNotFoundException tnfe) {
+            String msg = "ThemeResourceLoader Error: " + tnfe.getMessage();
+            mLogger.error(msg, tnfe);
+            throw new ResourceNotFoundException(msg);
+            
+        } catch (RollerException re) {
+            String msg = "RollerResourceLoader Error: " + re.getMessage();
+            mLogger.error( msg, re );
+            throw new ResourceNotFoundException(msg);
+        }
+    }
+    
+    
+    public boolean isSourceModified(Resource resource) {
+        return (resource.getLastModified() != this.getLastModified(resource));
+    }
+    
+    
+    public long getLastModified(Resource resource) {
+        long last_mod = 0;
+        String name = resource.getName();
+        
+        mLogger.debug("Checking last modified time for resource named ... "+name);
+        
+        if (name == null || name.length() < 1)
+            return last_mod;
+        
+        try {
+            // parse the name ... theme templates name are <theme>:<template>
+            String[] split = name.split(":", 2);
+            if(split.length < 2)
+                return last_mod;
+            
+            // lookup the template from the proper theme
+            ThemeManager themeMgr = RollerFactory.getRoller().getThemeManager();
+            Theme theme = themeMgr.getTheme(split[0]);
+            ThemeTemplate template = theme.getTemplate(split[1]);
+            
+            if(template == null)
+                return last_mod;
+            
+            last_mod = template.getLastModified().getTime();
+            
+        } catch (ThemeNotFoundException tnfe) {
+            // ignore
+        } catch (RollerException re) {
+            // we don't like to see this happen, but oh well
+        }
+        
+        return last_mod;
+    }
+    
+}

Added: incubator/roller/trunk/src/org/roller/presentation/velocity/wrappers/TemplateWrapper.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/wrappers/TemplateWrapper.java?rev=209350&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/wrappers/TemplateWrapper.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/wrappers/TemplateWrapper.java Tue Jul  5 16:31:59 2005
@@ -0,0 +1,52 @@
+/*
+ * TemplateWrapper.java
+ *
+ * Created on July 2, 2005, 4:02 PM
+ */
+
+package org.roller.presentation.velocity.wrappers;
+
+import java.util.Date;
+import org.roller.model.Template;
+
+
+/**
+ * Wrapper class for org.roller.model.Template objects.
+ *
+ * @author Allen Gilliland
+ */
+public class TemplateWrapper {
+    
+    private Template template = null;
+    
+    
+    public TemplateWrapper(Template template) {
+        this.template = template;
+    }
+    
+    
+    public String getId() {
+        return this.template.getId();
+    }
+
+    public String getName() {
+        return this.template.getName();
+    }
+
+    public String getDescription() {
+        return this.template.getDescription();
+    }
+
+    public String getContents() {
+        return this.template.getContents();
+    }
+
+    public Date getLastModified() {
+        return this.template.getLastModified();
+    }
+
+    public String getLink() {
+        return this.template.getLink();
+    }
+
+}



New theme management code

Posted by Allen Gilliland <Al...@Sun.COM>.
This isn't exactly complete yet, but I think it's far enough along that 
it's worth putting in the repository and letting other people play with 
it.  No database changes, so it should be easy to play with.  A few 
things to keep in mind ...

- New registering users are forced to select a shared theme during 
registration
- Themes are "shared" and the templates are not editable by users
- Templates are only copied down when you "customize" a theme
- Simply changing your theme does not affect your page templates at all
- The preview servlet works the exact same way as the page servlet, 
except that it accepts a "?theme=<theme>" param which can control what 
theme the page is rendered with
- You can toggle on/off custom themes from the admin settings page.

try it out.  let me know what you think and if you find any bugs.

-- Allen


agilliland@apache.org wrote:

>Author: agilliland
>Date: Tue Jul  5 16:31:59 2005
>New Revision: 209350
>
>URL: http://svn.apache.org/viewcvs?rev=209350&view=rev
>Log:
>New classes for Theme Management.
>
>
>Added:
>    incubator/roller/trunk/src/org/roller/ThemeNotFoundException.java
>    incubator/roller/trunk/src/org/roller/business/ThemeManagerImpl.java
>    incubator/roller/trunk/src/org/roller/model/Template.java
>    incubator/roller/trunk/src/org/roller/model/ThemeManager.java
>    incubator/roller/trunk/src/org/roller/pojos/Theme.java
>    incubator/roller/trunk/src/org/roller/pojos/ThemeTemplate.java
>    incubator/roller/trunk/src/org/roller/presentation/velocity/ThemeResourceLoader.java
>    incubator/roller/trunk/src/org/roller/presentation/velocity/wrappers/
>    incubator/roller/trunk/src/org/roller/presentation/velocity/wrappers/TemplateWrapper.java
>
>Added: incubator/roller/trunk/src/org/roller/ThemeNotFoundException.java
>URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/ThemeNotFoundException.java?rev=209350&view=auto
>==============================================================================
>--- incubator/roller/trunk/src/org/roller/ThemeNotFoundException.java (added)
>+++ incubator/roller/trunk/src/org/roller/ThemeNotFoundException.java Tue Jul  5 16:31:59 2005
>@@ -0,0 +1,33 @@
>+/*
>+ * ThemeNotFoundException.java
>+ *
>+ * Created on June 28, 2005, 12:48 PM
>+ */
>+
>+package org.roller;
>+
>+
>+/**
>+ * Thrown when the ThemeManager has a problem finding a named theme.
>+ *
>+ * @author Allen Gilliland
>+ */
>+public class ThemeNotFoundException extends RollerException {
>+    
>+    public ThemeNotFoundException(String s,Throwable t) {
>+        super(s, t);
>+    }
>+    
>+    public ThemeNotFoundException(Throwable t) {
>+        super(t);
>+    }
>+    
>+    public ThemeNotFoundException(String s) {
>+        super(s);
>+    }
>+    
>+    public ThemeNotFoundException() {
>+        super();
>+    }
>+    
>+}
>
>Added: incubator/roller/trunk/src/org/roller/business/ThemeManagerImpl.java
>URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/business/ThemeManagerImpl.java?rev=209350&view=auto
>==============================================================================
>--- incubator/roller/trunk/src/org/roller/business/ThemeManagerImpl.java (added)
>+++ incubator/roller/trunk/src/org/roller/business/ThemeManagerImpl.java Tue Jul  5 16:31:59 2005
>@@ -0,0 +1,272 @@
>+/*
>+ * ThemeManagerImpl.java
>+ *
>+ * Created on June 27, 2005, 1:33 PM
>+ */
>+
>+package org.roller.business;
>+
>+import java.io.File;
>+import java.io.FileReader;
>+import java.io.FilenameFilter;
>+import java.util.ArrayList;
>+import java.util.Collection;
>+import java.util.Collections;
>+import java.util.Date;
>+import java.util.HashMap;
>+import java.util.Iterator;
>+import java.util.List;
>+import java.util.Map;
>+import org.apache.commons.logging.Log;
>+import org.apache.commons.logging.LogFactory;
>+import org.roller.RollerException;
>+import org.roller.ThemeNotFoundException;
>+import org.roller.config.RollerConfig;
>+import org.roller.model.ThemeManager;
>+import org.roller.pojos.Theme;
>+import org.roller.pojos.ThemeTemplate;
>+
>+
>+/**
>+ * Base implementation of a ThemeManager.
>+ * 
>+ * This particular implementation reads theme data off the filesystem 
>+ * and assumes that those themes are not changable at runtime.
>+ *
>+ * @author Allen Gilliland
>+ */
>+public class ThemeManagerImpl implements ThemeManager {
>+    
>+    private static Log mLogger = 
>+        LogFactory.getFactory().getInstance(ThemeManagerImpl.class);
>+    
>+    private Map themes;
>+    
>+    
>+    protected ThemeManagerImpl() {
>+        
>+        // rather than be lazy we are going to load all themes from
>+        // the disk preemptively during initialization and cache them
>+        mLogger.debug("Initializing ThemeManagerImpl");
>+        mLogger.info("Loading all themes from disk ... ");
>+        this.themes = this.loadAllThemesFromDisk();
>+    }
>+    
>+    
>+    /**
>+     * @see org.roller.model.ThemeManager#getTheme(java.lang.String)
>+     */
>+    public Theme getTheme(String name) 
>+        throws ThemeNotFoundException, RollerException {
>+        
>+        Theme theme = (Theme) this.themes.get(name);
>+        if(theme == null)
>+            throw new ThemeNotFoundException("Couldn't find theme ["+name+"]");
>+        
>+        return theme;
>+    }
>+    
>+    
>+    /**
>+     * @see org.roller.model.ThemeManager#getThemeById(java.lang.String)
>+     */
>+    public Theme getThemeById(String id) 
>+        throws ThemeNotFoundException, RollerException {
>+        
>+        // In this implementation where themes come from the filesystem we
>+        // know that the name and id for a theme are the same
>+        return this.getTheme(id);
>+    }
>+    
>+    
>+    /**
>+     * @see org.roller.model.ThemeManager#getThemesList()
>+     */
>+    public List getThemesList() {
>+        
>+        List themes = new ArrayList(this.themes.keySet());
>+        
>+        // sort 'em ... the natural sorting order for Strings is alphabetical
>+        Collections.sort(themes);
>+        
>+        return themes;
>+    }
>+    
>+    
>+    /**
>+     * @see org.roller.model.ThemeManager#getEnabledThemesList()
>+     */
>+    public List getEnabledThemesList() {
>+        
>+        Collection all_themes = this.themes.values();
>+        
>+        // make a new list of only the enabled themes
>+        List enabled_themes = new ArrayList();
>+        Iterator it = all_themes.iterator();
>+        Theme theme = null;
>+        while(it.hasNext()) {
>+            theme = (Theme) it.next();
>+            if(theme.isEnabled())
>+                enabled_themes.add(theme.getName());
>+        }
>+                
>+        // sort 'em ... the natural sorting order for Strings is alphabetical
>+        Collections.sort(enabled_themes);
>+        
>+        return enabled_themes;
>+    }
>+    
>+    
>+    /**
>+     * @see org.roller.model.ThemeManager#getTemplate(String, String)
>+     */
>+    public ThemeTemplate getTemplate(String theme_name, String template_name)
>+        throws ThemeNotFoundException, RollerException {
>+        
>+        // basically we just try and lookup the theme first, then template
>+        Theme theme = this.getTheme(theme_name);
>+        
>+        return theme.getTemplate(template_name);
>+    }
>+    
>+    
>+    /**
>+     * @see org.roller.model.ThemeManager#getTemplateById(java.lang.String)
>+     */
>+    public ThemeTemplate getTemplateById(String id)
>+        throws ThemeNotFoundException, RollerException {
>+        
>+        if(id == null)
>+            throw new ThemeNotFoundException("Theme id was null");
>+        
>+        // in our case we expect a template id to be <theme>:<template>
>+        // so extract each piece and do the lookup
>+        String[] split = id.split(":",  2);
>+        if(split.length != 2)
>+            throw new ThemeNotFoundException("Invalid theme id ["+id+"]");
>+        
>+        return this.getTemplate(split[0], split[1]);
>+    }
>+    
>+    
>+    /**
>+     * @see org.roller.model.ThemeManager#getTemplateByLink(java.lang.String)
>+     */
>+    public ThemeTemplate getTemplateByLink(String theme_name, String template_link)
>+        throws ThemeNotFoundException, RollerException {
>+        
>+        // basically we just try and lookup the theme first, then template
>+        Theme theme = this.getTheme(theme_name);
>+        
>+        return theme.getTemplateByLink(template_link);
>+    }
>+    
>+    
>+    /**
>+     * This is a convenience method which loads all the theme data from
>+     * themes stored on the filesystem in the roller webapp /themes/ directory.
>+     */
>+    private Map loadAllThemesFromDisk() {
>+        
>+        Map themes = new HashMap();
>+        
>+        // NOTE: we need to figure out how to get the roller context path
>+        String themespath = RollerConfig.getProperty("context.realpath");
>+        if(themespath.endsWith(File.separator))
>+            themespath += "themes";
>+        else
>+            themespath += File.separator + "themes";
>+        
>+        // first, get a list of the themes available
>+        File themesdir = new File(themespath);
>+        FilenameFilter filter = new FilenameFilter() {
>+            public boolean accept(File dir, String name) {
>+                File file =
>+                        new File(dir.getAbsolutePath() + File.separator + name);
>+                return file.isDirectory();
>+            }
>+        };
>+        String[] themenames = themesdir.list(filter);
>+        
>+        // now go through each theme and read all it's templates
>+        Theme theme = null;
>+        for(int i=0; i < themenames.length; i++) {
>+            theme = this.loadThemeFromDisk(themenames[i], 
>+                        themespath + File.separator + themenames[i]);
>+            
>+            themes.put(theme.getName(), theme);
>+        }
>+        
>+        return themes;
>+    }
>+    
>+    
>+    /**
>+     * Another convenience method which knows how to load a single theme
>+     * off the filesystem and return a Theme object
>+     */
>+    private Theme loadThemeFromDisk(String theme_name, String themepath) {
>+        
>+        mLogger.debug("Loading theme "+theme_name+" from "+themepath);
>+        
>+        Theme theme = new Theme();
>+        theme.setName(theme_name);
>+        theme.setAuthor("Roller");
>+        theme.setLastEditor("Roller");
>+        theme.setEnabled(true);
>+        
>+        // start by getting a list of the .vm files for this theme
>+        File themedir = new File(themepath);
>+        FilenameFilter filter = new FilenameFilter()
>+        {
>+            public boolean accept(File dir, String name)
>+            {
>+                return name.endsWith(".vm");
>+            }
>+        };
>+        String[] templates = themedir.list(filter);
>+        
>+        // go through each .vm file and read in its contents to a ThemeTemplate
>+        String template_name = null;
>+        ThemeTemplate theme_template = null;
>+        for (int i=0; i < templates.length; i++) {
>+            // strip off the .vm part
>+            template_name = templates[i].substring(0, templates[i].length() - 3);
>+            
>+            try {
>+                File template_file = new File(themepath + File.separator + templates[i]);
>+                
>+                if(!template_file.exists() && !template_file.canRead()) {
>+                    mLogger.warn("Couldn't read theme template file ["+template_file.getPath()+"]");
>+                    continue;
>+                }
>+                
>+                FileReader reader = new FileReader(template_file);
>+                char[] chars = new char[(int) template_file.length()];
>+                reader.read(chars);
>+                
>+                // construct ThemeTemplate representing this file
>+                theme_template = new ThemeTemplate(
>+                        theme_name+":"+template_name,
>+                        template_name,
>+                        template_name,
>+                        new String(chars),
>+                        template_name,
>+                        new Date(template_file.lastModified()));
>+                
>+                // add it to the theme
>+                theme.setTemplate(template_name, theme_template);
>+                
>+            } catch (Exception e) {
>+                // warn?
>+            }
>+        }
>+        
>+        // use the last mod date of the last template file
>+        // as the last mod date of the theme
>+        theme.setLastModified(theme_template.getLastModified());
>+        
>+        return theme;
>+    }
>+
>+}
>
>Added: incubator/roller/trunk/src/org/roller/model/Template.java
>URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/model/Template.java?rev=209350&view=auto
>==============================================================================
>--- incubator/roller/trunk/src/org/roller/model/Template.java (added)
>+++ incubator/roller/trunk/src/org/roller/model/Template.java Tue Jul  5 16:31:59 2005
>@@ -0,0 +1,37 @@
>+/*
>+ * Template.java
>+ *
>+ * Created on June 27, 2005, 11:59 AM
>+ */
>+
>+package org.roller.model;
>+
>+import java.util.Date;
>+
>+
>+/**
>+ * The Template interface represents the abstract concept of a single unit
>+ * of templated or non-rendered content.  For Roller we mainly think of
>+ * templates as Velocity templates which are meant to be fed into the 
>+ * Velocity rendering engine.
>+ *
>+ * @author Allen Gilliland
>+ */
>+public interface Template {
>+    
>+    public String getId();
>+    public String getName();
>+    public String getDescription();
>+    public String getContents();
>+    public String getLink();
>+    public Date getLastModified();
>+    
>+    /*
>+    public void setId(String id);
>+    public void setName(String name);
>+    public void setDescription(String desc);
>+    public void setContents(String contents);
>+    public void setLink(String link);
>+    public void setLastModified(Date date);
>+    */
>+}
>
>Added: incubator/roller/trunk/src/org/roller/model/ThemeManager.java
>URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/model/ThemeManager.java?rev=209350&view=auto
>==============================================================================
>--- incubator/roller/trunk/src/org/roller/model/ThemeManager.java (added)
>+++ incubator/roller/trunk/src/org/roller/model/ThemeManager.java Tue Jul  5 16:31:59 2005
>@@ -0,0 +1,99 @@
>+/*
>+ * ThemeManager.java
>+ *
>+ * Created on June 27, 2005, 12:49 PM
>+ */
>+
>+package org.roller.model;
>+
>+import java.util.List;
>+import org.roller.RollerException;
>+import org.roller.ThemeNotFoundException;
>+import org.roller.pojos.Theme;
>+import org.roller.pojos.ThemeTemplate;
>+
>+
>+/**
>+ * Manager interface for accessing Theme related objects.
>+ *
>+ * @author Allen Gilliland
>+ */
>+public interface ThemeManager {
>+    
>+    /**
>+     * Get the Theme object with the given name.
>+     *
>+     * @throws ThemeNotFoundException If the named theme cannot be found.
>+     * @throws RollerException If there is some kind of fatal backend error.
>+     **/
>+    public Theme getTheme(String name)
>+        throws ThemeNotFoundException, RollerException;
>+    
>+    
>+    /**
>+     * Get the Theme object with the given theme id.
>+     *
>+     * @throws ThemeNotFoundException If the named theme cannot be found.
>+     * @throws RollerException If there is some kind of fatal backend error.
>+     */
>+    public Theme getThemeById(String theme_id)
>+        throws ThemeNotFoundException, RollerException;
>+    
>+    
>+    /**
>+     * Get a list of all available themes.
>+     * This list is ordered alphabetically by default.
>+     *
>+     * NOTE: this only returns a list of theme names, not actual Theme objects.
>+     **/
>+    public List getThemesList();
>+    
>+    
>+    /**
>+     * Get a list of all theme names that are currently enabled.
>+     * This list is ordered alphabetically by default.
>+     *
>+     * NOTE: this only returns a list of theme names, not actual Theme objects.
>+     */
>+    public List getEnabledThemesList();
>+    
>+    
>+    /**
>+     * Get the template from a given theme.
>+     *
>+     * @throws ThemeNotFoundException If the named theme cannot be found.
>+     * @throws RollerException If there is some kind of fatal backend error.
>+     */
>+    public ThemeTemplate getTemplate(String theme_name, String template_name)
>+        throws ThemeNotFoundException, RollerException;
>+    
>+    
>+    /**
>+     * Get the template from a given theme using the template id.
>+     *
>+     * Theme templates use a special id value when they come off the filesystem.
>+     * When a theme is read off the filesystem it's templates are given an id
>+     * like ... <theme name>:<template name>
>+     *
>+     * @throws ThemeNotFoundException If the named theme cannot be found.
>+     * @throws RollerException If there is some kind of fatal backend error.
>+     */
>+    public ThemeTemplate getTemplateById(String template_id)
>+        throws ThemeNotFoundException, RollerException;
>+
>+    
>+    /**
>+     * Get the template from a given theme using the template link value.
>+     *
>+     * Note that for themes we enforce the rule that 
>+     *      Theme.name == Theme.link
>+     *
>+     * So doing a lookup by link is the same as doing a lookup by name.
>+     *
>+     * @throws ThemeNotFoundException If the named theme cannot be found.
>+     * @throws RollerException If there is some kind of fatal backend error.
>+     */
>+    public ThemeTemplate getTemplateByLink(String theme_name, String template_link)
>+        throws ThemeNotFoundException, RollerException;
>+    
>+}
>
>Added: incubator/roller/trunk/src/org/roller/pojos/Theme.java
>URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/Theme.java?rev=209350&view=auto
>==============================================================================
>--- incubator/roller/trunk/src/org/roller/pojos/Theme.java (added)
>+++ incubator/roller/trunk/src/org/roller/pojos/Theme.java Tue Jul  5 16:31:59 2005
>@@ -0,0 +1,173 @@
>+/*
>+ * Theme.java
>+ *
>+ * Created on June 27, 2005, 12:55 PM
>+ */
>+
>+package org.roller.pojos;
>+
>+import java.io.Serializable;
>+import java.util.Collection;
>+import java.util.Date;
>+import java.util.HashMap;
>+import java.util.Iterator;
>+import java.util.Map;
>+
>+
>+/**
>+ * The Theme object encapsulates all elements of a single weblog theme.  It
>+ * is used mostly to contain all the templates for a theme, but does contain
>+ * other theme related attributes such as name, last modifed date, etc.
>+ *
>+ * @author Allen Gilliland
>+ */
>+public class Theme implements Serializable {
>+    
>+    // this is the name that will be used to identify a user customized theme
>+    public static final String CUSTOM = "custom";
>+    
>+    private String id;
>+    private String name;
>+    private String description;
>+    private String author;
>+    private String lastEditor; // user id value of last editor
>+    private Date lastModified;
>+    private boolean enabled;
>+    
>+    // we keep templates in a Map for faster lookups by name
>+    // the Map contains ... (template name, ThemeTemplate)
>+    private Map templates;
>+    
>+    
>+    public Theme() {
>+        this.id = null;
>+        this.name = null;
>+        this.description = null;
>+        this.author = null;
>+        this.lastEditor = null;
>+        this.lastModified = null;
>+        this.enabled = false;
>+        this.templates = new HashMap();
>+    }
>+
>+    
>+    /**
>+     * Get the collection of all templates associated with this Theme.
>+     */
>+    public Collection getTemplates() {
>+        return this.templates.values();
>+    }
>+    
>+    
>+    /**
>+     * Lookup the specified template by name.
>+     * Returns null if the template cannot be found.
>+     */
>+    public ThemeTemplate getTemplate(String name) {
>+        return (ThemeTemplate) this.templates.get(name);
>+    }
>+    
>+    
>+    /**
>+     * Lookup the specified template by link.
>+     * Returns null if the template cannot be found.
>+     *
>+     * NOTE: for themes we enforce the rule that 
>+     *          Theme.link == Theme.name
>+     *
>+     * So this lookup is basically the same as lookup by name.
>+     */
>+    public ThemeTemplate getTemplateByLink(String link) {
>+        return (ThemeTemplate) this.templates.get(link);
>+    }
>+    
>+    
>+    /**
>+     * Set the value for a given template name.
>+     */
>+    public void setTemplate(String name, ThemeTemplate template) {
>+        this.templates.put(name, template);
>+    }
>+    
>+    
>+    /**
>+     * Check if this Theme contains the named template.
>+     * Returns true if the template exists, false otherwise.
>+     */
>+    public boolean hasTemplate(String name) {
>+        return this.templates.containsKey(name);
>+    }
>+    
>+    
>+    public String getId() {
>+        return id;
>+    }
>+
>+    public void setId(String id) {
>+        this.id = id;
>+    }
>+    
>+    public String getName() {
>+        return name;
>+    }
>+
>+    public void setName(String name) {
>+        this.name = name;
>+    }
>+
>+    public String getDescription() {
>+        return description;
>+    }
>+
>+    public void setDescription(String description) {
>+        this.description = description;
>+    }
>+
>+    public String getAuthor() {
>+        return author;
>+    }
>+
>+    public void setAuthor(String author) {
>+        this.author = author;
>+    }
>+
>+    public String getLastEditor() {
>+        return lastEditor;
>+    }
>+
>+    public void setLastEditor(String lastEditor) {
>+        this.lastEditor = lastEditor;
>+    }
>+
>+    public Date getLastModified() {
>+        return lastModified;
>+    }
>+
>+    public void setLastModified(Date lastModified) {
>+        this.lastModified = lastModified;
>+    }
>+    
>+    public boolean isEnabled() {
>+        return enabled;
>+    }
>+
>+    public void setEnabled(boolean enabled) {
>+        this.enabled = enabled;
>+    }
>+    
>+    public String toString() {
>+        StringBuffer sb = new StringBuffer();
>+        sb.append(name);
>+        sb.append("\n");
>+        
>+        Iterator it = this.templates.values().iterator();
>+        while(it.hasNext()) {
>+            sb.append(it.next());
>+            sb.append("\n");
>+        }
>+        
>+        return sb.toString();
>+        
>+    }
>+
>+}
>
>Added: incubator/roller/trunk/src/org/roller/pojos/ThemeTemplate.java
>URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/ThemeTemplate.java?rev=209350&view=auto
>==============================================================================
>--- incubator/roller/trunk/src/org/roller/pojos/ThemeTemplate.java (added)
>+++ incubator/roller/trunk/src/org/roller/pojos/ThemeTemplate.java Tue Jul  5 16:31:59 2005
>@@ -0,0 +1,97 @@
>+/*
>+ * ThemeTemplate.java
>+ *
>+ * Created on June 27, 2005, 12:14 PM
>+ */
>+
>+package org.roller.pojos;
>+
>+import java.io.Serializable;
>+import java.util.Date;
>+import org.roller.model.Template;
>+
>+
>+/**
>+ * A Theme based implementation of a Template.  A ThemeTemplate represents a
>+ * template which is part of a shared Theme.
>+ *
>+ * @author Allen Gilliland
>+ */
>+public class ThemeTemplate implements Template, Serializable {
>+    
>+    private String id;
>+    private String name;
>+    private String description;
>+    private String contents;
>+    private String link;
>+    private Date lastModified;
>+    
>+    
>+    public ThemeTemplate() {}
>+    
>+    public ThemeTemplate(String id, String name, 
>+                String desc, String contents, String link, Date date) {
>+        
>+        this.id = id;
>+        this.name = name;
>+        this.description = desc;
>+        this.contents = contents;
>+        this.link = link;
>+        this.lastModified = date;
>+    }
>+    
>+
>+    public String getId() {
>+        return id;
>+    }
>+
>+    public void setId(String id) {
>+        this.id = id;
>+    }
>+
>+    public String getName() {
>+        return name;
>+    }
>+
>+    public void setName(String name) {
>+        this.name = name;
>+    }
>+
>+    public String getDescription() {
>+        return description;
>+    }
>+
>+    public void setDescription(String description) {
>+        this.description = description;
>+    }
>+
>+    public String getContents() {
>+        return contents;
>+    }
>+
>+    public void setContents(String contents) {
>+        this.contents = contents;
>+    }
>+
>+    public Date getLastModified() {
>+        return lastModified;
>+    }
>+
>+    public void setLastModified(Date lastModified) {
>+        this.lastModified = lastModified;
>+    }
>+
>+    public String getLink() {
>+        return link;
>+    }
>+
>+    public void setLink(String link) {
>+        this.link = link;
>+    }
>+    
>+    public String toString() {
>+        return (id + "," + name + "," + description + "," + link + "," + 
>+                lastModified + "\n\n" + contents + "\n");
>+    }
>+    
>+}
>
>Added: incubator/roller/trunk/src/org/roller/presentation/velocity/ThemeResourceLoader.java
>URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/ThemeResourceLoader.java?rev=209350&view=auto
>==============================================================================
>--- incubator/roller/trunk/src/org/roller/presentation/velocity/ThemeResourceLoader.java (added)
>+++ incubator/roller/trunk/src/org/roller/presentation/velocity/ThemeResourceLoader.java Tue Jul  5 16:31:59 2005
>@@ -0,0 +1,130 @@
>+/*
>+ * ThemeResourceLoader.java
>+ *
>+ * Created on June 28, 2005, 12:25 PM
>+ */
>+
>+package org.roller.presentation.velocity;
>+
>+import java.io.ByteArrayInputStream;
>+import java.io.InputStream;
>+import java.io.UnsupportedEncodingException;
>+import org.apache.commons.collections.ExtendedProperties;
>+import org.apache.commons.logging.Log;
>+import org.apache.commons.logging.LogFactory;
>+import org.apache.velocity.exception.ResourceNotFoundException;
>+import org.apache.velocity.runtime.resource.Resource;
>+import org.apache.velocity.runtime.resource.loader.ResourceLoader;
>+import org.roller.RollerException;
>+import org.roller.ThemeNotFoundException;
>+import org.roller.model.RollerFactory;
>+import org.roller.model.ThemeManager;
>+import org.roller.pojos.Theme;
>+import org.roller.pojos.ThemeTemplate;
>+
>+
>+/**
>+ * The ThemeResourceLoader is a Velocity template loader which loads
>+ * templates from shared themes.
>+ *
>+ * @author Allen Gilliland
>+ */
>+public class ThemeResourceLoader extends ResourceLoader {
>+    
>+    private static Log mLogger = 
>+        LogFactory.getFactory().getInstance(ThemeResourceLoader.class);
>+        
>+    
>+    public void init(ExtendedProperties configuration) {
>+        mLogger.debug(configuration);
>+    }
>+    
>+    
>+    public InputStream getResourceStream( String name )
>+        throws ResourceNotFoundException {
>+        
>+        mLogger.debug("Looking up resource named ... "+name);
>+        
>+        if (name == null || name.length() < 1) {
>+            throw new ResourceNotFoundException("Need to specify a template name!");
>+        }
>+        
>+        try {
>+            // parse the name ... theme templates name are <theme>:<template>
>+            String[] split = name.split(":", 2);
>+            if(split.length < 2)
>+                throw new ResourceNotFoundException("Invalid ThemeRL key "+name);
>+            
>+            // lookup the template from the proper theme
>+            ThemeManager themeMgr = RollerFactory.getRoller().getThemeManager();
>+            Theme theme = themeMgr.getTheme(split[0]);
>+            ThemeTemplate template = theme.getTemplate(split[1]);
>+            
>+            if(template == null)
>+                throw new ResourceNotFoundException("Template ["+split[1]+
>+                        "] doesn't seem to be part of theme ["+split[0]+"]");
>+            
>+            mLogger.debug("Resource found!");
>+            
>+            // return the input stream
>+            return new ByteArrayInputStream(template.getContents().getBytes("UTF-8"));
>+            
>+        } catch (UnsupportedEncodingException uex) {
>+            // We expect UTF-8 in all JRE installation.
>+            // This rethrows as a Runtime exception after logging.
>+            mLogger.error(uex);
>+            throw new RuntimeException(uex);
>+           
>+        } catch (ThemeNotFoundException tnfe) {
>+            String msg = "ThemeResourceLoader Error: " + tnfe.getMessage();
>+            mLogger.error(msg, tnfe);
>+            throw new ResourceNotFoundException(msg);
>+            
>+        } catch (RollerException re) {
>+            String msg = "RollerResourceLoader Error: " + re.getMessage();
>+            mLogger.error( msg, re );
>+            throw new ResourceNotFoundException(msg);
>+        }
>+    }
>+    
>+    
>+    public boolean isSourceModified(Resource resource) {
>+        return (resource.getLastModified() != this.getLastModified(resource));
>+    }
>+    
>+    
>+    public long getLastModified(Resource resource) {
>+        long last_mod = 0;
>+        String name = resource.getName();
>+        
>+        mLogger.debug("Checking last modified time for resource named ... "+name);
>+        
>+        if (name == null || name.length() < 1)
>+            return last_mod;
>+        
>+        try {
>+            // parse the name ... theme templates name are <theme>:<template>
>+            String[] split = name.split(":", 2);
>+            if(split.length < 2)
>+                return last_mod;
>+            
>+            // lookup the template from the proper theme
>+            ThemeManager themeMgr = RollerFactory.getRoller().getThemeManager();
>+            Theme theme = themeMgr.getTheme(split[0]);
>+            ThemeTemplate template = theme.getTemplate(split[1]);
>+            
>+            if(template == null)
>+                return last_mod;
>+            
>+            last_mod = template.getLastModified().getTime();
>+            
>+        } catch (ThemeNotFoundException tnfe) {
>+            // ignore
>+        } catch (RollerException re) {
>+            // we don't like to see this happen, but oh well
>+        }
>+        
>+        return last_mod;
>+    }
>+    
>+}
>
>Added: incubator/roller/trunk/src/org/roller/presentation/velocity/wrappers/TemplateWrapper.java
>URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/wrappers/TemplateWrapper.java?rev=209350&view=auto
>==============================================================================
>--- incubator/roller/trunk/src/org/roller/presentation/velocity/wrappers/TemplateWrapper.java (added)
>+++ incubator/roller/trunk/src/org/roller/presentation/velocity/wrappers/TemplateWrapper.java Tue Jul  5 16:31:59 2005
>@@ -0,0 +1,52 @@
>+/*
>+ * TemplateWrapper.java
>+ *
>+ * Created on July 2, 2005, 4:02 PM
>+ */
>+
>+package org.roller.presentation.velocity.wrappers;
>+
>+import java.util.Date;
>+import org.roller.model.Template;
>+
>+
>+/**
>+ * Wrapper class for org.roller.model.Template objects.
>+ *
>+ * @author Allen Gilliland
>+ */
>+public class TemplateWrapper {
>+    
>+    private Template template = null;
>+    
>+    
>+    public TemplateWrapper(Template template) {
>+        this.template = template;
>+    }
>+    
>+    
>+    public String getId() {
>+        return this.template.getId();
>+    }
>+
>+    public String getName() {
>+        return this.template.getName();
>+    }
>+
>+    public String getDescription() {
>+        return this.template.getDescription();
>+    }
>+
>+    public String getContents() {
>+        return this.template.getContents();
>+    }
>+
>+    public Date getLastModified() {
>+        return this.template.getLastModified();
>+    }
>+
>+    public String getLink() {
>+        return this.template.getLink();
>+    }
>+
>+}
>
>
>  
>