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 2007/04/05 20:15:38 UTC

svn commit: r525922 [1/2] - in /incubator/roller/trunk: src/org/apache/roller/business/ src/org/apache/roller/business/themes/ src/org/apache/roller/business/utils/ src/org/apache/roller/pojos/ src/org/apache/roller/pojos/wrapper/ src/org/apache/roller...

Author: agilliland
Date: Thu Apr  5 11:15:32 2007
New Revision: 525922

URL: http://svn.apache.org/viewvc?view=rev&rev=525922
Log:
Some refactoring of the object model regarding Templates, Resources, and Themes.

This commit introduces a more natural OO design with regards to weblog Themes and their relationship to Templates and Resources.  Here is an overview of what these changes are ...

Template (interface) - more abstract version of the old Template interface
ThemeTemplate (interface) - effectively the same as the old Template interface, a Template tied to a Theme

Resource (interface) - a generic interface representing a static resource
ThemeResource (interface) - a Resource tied to a Theme

Theme (interface) - access to the things which compose a weblog theme
WeblogTheme (abstract class) - an instance of a Theme for a given weblog

There are then included a variety of implementation classes and subclasses for these various interfaces.


Added:
    incubator/roller/trunk/src/org/apache/roller/business/themes/SharedTheme.java
    incubator/roller/trunk/src/org/apache/roller/business/themes/SharedThemeFromDir.java
    incubator/roller/trunk/src/org/apache/roller/business/themes/SharedThemeResourceFromDir.java
    incubator/roller/trunk/src/org/apache/roller/business/themes/SharedThemeTemplate.java
    incubator/roller/trunk/src/org/apache/roller/business/themes/WeblogCustomTheme.java
    incubator/roller/trunk/src/org/apache/roller/business/themes/WeblogSharedTheme.java
    incubator/roller/trunk/src/org/apache/roller/pojos/Resource.java
    incubator/roller/trunk/src/org/apache/roller/pojos/StaticThemeTemplate.java
    incubator/roller/trunk/src/org/apache/roller/pojos/ThemeResource.java
    incubator/roller/trunk/src/org/apache/roller/pojos/WeblogTheme.java
Removed:
    incubator/roller/trunk/src/org/apache/roller/pojos/WeblogResource.java
Modified:
    incubator/roller/trunk/src/org/apache/roller/business/FileManager.java
    incubator/roller/trunk/src/org/apache/roller/business/FileManagerImpl.java
    incubator/roller/trunk/src/org/apache/roller/business/themes/ThemeManager.java
    incubator/roller/trunk/src/org/apache/roller/business/themes/ThemeManagerImpl.java
    incubator/roller/trunk/src/org/apache/roller/business/utils/UpgradeDatabase.java
    incubator/roller/trunk/src/org/apache/roller/pojos/StaticTemplate.java
    incubator/roller/trunk/src/org/apache/roller/pojos/Template.java
    incubator/roller/trunk/src/org/apache/roller/pojos/Theme.java
    incubator/roller/trunk/src/org/apache/roller/pojos/ThemeTemplate.java
    incubator/roller/trunk/src/org/apache/roller/pojos/WeblogTemplate.java
    incubator/roller/trunk/src/org/apache/roller/pojos/WebsiteData.java
    incubator/roller/trunk/src/org/apache/roller/pojos/wrapper/TemplateWrapper.java
    incubator/roller/trunk/src/org/apache/roller/pojos/wrapper/WebsiteDataWrapper.java
    incubator/roller/trunk/src/org/apache/roller/ui/authoring/struts/actions/ImportEntriesAction.java
    incubator/roller/trunk/src/org/apache/roller/ui/authoring/struts/actions/ThemeEditorAction.java
    incubator/roller/trunk/src/org/apache/roller/ui/authoring/struts/actions/UploadFileFormAction.java
    incubator/roller/trunk/src/org/apache/roller/ui/authoring/struts/actions/WeblogTemplateFormAction.java
    incubator/roller/trunk/src/org/apache/roller/ui/core/RollerRequest.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/model/PlanetModel.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/model/SiteModel.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/pagers/CommentsPager.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/pagers/WeblogEntriesListPager.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/servlets/FeedServlet.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/servlets/PageServlet.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/servlets/PlanetFeedServlet.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/servlets/PreviewResourceServlet.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/servlets/PreviewServlet.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/servlets/RSDServlet.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/servlets/ResourceServlet.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/servlets/SearchServlet.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/util/WeblogPageRequest.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/util/cache/WeblogCacheWarmupJob.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/velocity/ThemeResourceLoader.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/velocity/VelocityRenderer.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/velocity/deprecated/ContextLoader.java
    incubator/roller/trunk/src/org/apache/roller/ui/rendering/velocity/deprecated/OldWeblogPageModel.java
    incubator/roller/trunk/src/org/apache/roller/util/URLUtilities.java
    incubator/roller/trunk/src/org/apache/roller/webservices/atomprotocol/RollerAtomHandler.java
    incubator/roller/trunk/tests/org/apache/roller/business/FileManagerTest.java
    incubator/roller/trunk/web/WEB-INF/jsps/authoring/edit-pages.jsp
    incubator/roller/trunk/web/WEB-INF/jsps/authoring/theme-editor.jsp

Modified: incubator/roller/trunk/src/org/apache/roller/business/FileManager.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/business/FileManager.java?view=diff&rev=525922&r1=525921&r2=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/business/FileManager.java (original)
+++ incubator/roller/trunk/src/org/apache/roller/business/FileManager.java Thu Apr  5 11:15:32 2007
@@ -19,7 +19,7 @@
 package org.apache.roller.business;
 
 import java.io.InputStream;
-import org.apache.roller.pojos.WeblogResource;
+import org.apache.roller.pojos.ThemeResource;
 import org.apache.roller.pojos.WebsiteData;
 
 
@@ -41,16 +41,16 @@
      * @throws FileNotFoundException If path does not exist.
      * @throws FilePathException If path is invalid, is a directory, or can't be read.
      *
-     * @return WeblogResource representing the real file resource.
+     * @return ThemeResource representing the real file resource.
      */
-    public WeblogResource getFile(WebsiteData weblog, String path) 
+    public ThemeResource getFile(WebsiteData weblog, String path) 
         throws FileNotFoundException, FilePathException;
     
     
     /**
      * Get list of files from a specific path of the weblog's uploads area.
      * 
-     * This method will return a WeblogResource[] array of all files at the 
+     * This method will return a ThemeResource[] array of all files at the 
      * given path if it exists, otherwise it will throw an exception.
      * 
      * This method should return the files at the root of the weblog's uploads
@@ -65,9 +65,9 @@
      * @throws FileNotFoundException If path does not exist.
      * @throws FilePathException If path is invalid, is not a directory, or can't be read.
      *
-     * @return WeblogResource[] of files in website's uploads area at given path.
+     * @return ThemeResource[] of files in website's uploads area at given path.
      */
-    public WeblogResource[] getFiles(WebsiteData weblog, String path) 
+    public ThemeResource[] getFiles(WebsiteData weblog, String path) 
         throws FileNotFoundException, FilePathException;
     
     
@@ -82,9 +82,9 @@
      * @throws FileNotFoundException If path does not exist.
      * @throws FilePathException If path is invalid, or can't be read.
      *
-     * @return WeblogResource[] of directories in website's uploads area.
+     * @return ThemeResource[] of directories in website's uploads area.
      */
-    public WeblogResource[] getDirectories(WebsiteData weblog)
+    public ThemeResource[] getDirectories(WebsiteData weblog)
             throws FileNotFoundException, FilePathException;
     
     

Modified: incubator/roller/trunk/src/org/apache/roller/business/FileManagerImpl.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/business/FileManagerImpl.java?view=diff&rev=525922&r1=525921&r2=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/business/FileManagerImpl.java (original)
+++ incubator/roller/trunk/src/org/apache/roller/business/FileManagerImpl.java Thu Apr  5 11:15:32 2007
@@ -31,11 +31,7 @@
 import org.apache.commons.logging.LogFactory;
 import org.apache.roller.config.RollerConfig;
 import org.apache.roller.config.RollerRuntimeConfig;
-import org.apache.roller.business.FileIOException;
-import org.apache.roller.business.FilePathException;
-import org.apache.roller.business.FileManager;
-import org.apache.roller.business.FileNotFoundException;
-import org.apache.roller.pojos.WeblogResource;
+import org.apache.roller.pojos.ThemeResource;
 import org.apache.roller.pojos.WebsiteData;
 import org.apache.roller.util.RollerMessages;
 import org.apache.roller.util.URLUtilities;
@@ -74,7 +70,7 @@
     /**
      * @see org.apache.roller.model.FileManager#getFile(weblog, java.lang.String)
      */
-    public WeblogResource getFile(WebsiteData weblog, String path) 
+    public ThemeResource getFile(WebsiteData weblog, String path) 
             throws FileNotFoundException, FilePathException {
         
         // get a reference to the file, checks that file exists & is readable
@@ -94,7 +90,7 @@
     /**
      * @see org.apache.roller.model.FileManager#getFiles(weblog, java.lang.String)
      */
-    public WeblogResource[] getFiles(WebsiteData weblog, String path) 
+    public ThemeResource[] getFiles(WebsiteData weblog, String path) 
             throws FileNotFoundException, FilePathException {
         
         // get a reference to the dir, checks that dir exists & is readable
@@ -107,7 +103,7 @@
         }
         
         // everything looks good, list contents
-        WeblogResource dir = new WeblogResourceFile(weblog, path, dirFile);
+        ThemeResource dir = new WeblogResourceFile(weblog, path, dirFile);
         
         return dir.getChildren();
     }
@@ -116,7 +112,7 @@
     /**
      * @see org.apache.roller.model.FileManager#getDirectories(weblog)
      */
-    public WeblogResource[] getDirectories(WebsiteData weblog)
+    public ThemeResource[] getDirectories(WebsiteData weblog)
             throws FileNotFoundException, FilePathException {
         
         // get a reference to the root dir, checks that dir exists & is readable
@@ -129,8 +125,8 @@
             }
         });
         
-        // convert 'em to WeblogResource objects
-        WeblogResource[] resources = new WeblogResource[dirFiles.length];
+        // convert 'em to ThemeResource objects
+        ThemeResource[] resources = new ThemeResource[dirFiles.length];
         for(int i=0; i < dirFiles.length; i++) {
             String filePath = dirFiles[i].getName();
             resources[i] = new WeblogResourceFile(weblog, filePath, dirFiles[i]);
@@ -141,7 +137,7 @@
     
     
     /**
- * @see org.apache.roller.model.FileManager#saveFile(weblog, java.lang.String, java.lang.String, long, java.io.InputStream)
+     * @see org.apache.roller.model.FileManager#saveFile(weblog, java.lang.String, java.lang.String, long, java.io.InputStream)
      */
     public void saveFile(WebsiteData weblog, 
                          String path, 
@@ -163,6 +159,19 @@
         
         // make sure uploads area exists for this weblog
         File dirPath = this.getRealFile(weblog, null);
+        
+        // if we are saving into a subfolder, make sure it exists
+        if(path.indexOf("/") != -1) {
+            String subDir = path.substring(0, path.indexOf("/"));
+            File subDirFile = new File(dirPath.getAbsolutePath() + File.separator + subDir);
+            if(!subDirFile.exists()) {
+                // directory doesn't exist yet, create it
+                log.debug("Creating directory ["+subDir+"] automatically");
+                subDirFile.mkdir();
+            }
+        }
+        
+        // create File that we are about to save
         File saveFile = new File(dirPath.getAbsolutePath() + File.separator + savePath);
         
         byte[] buffer = new byte[8192];
@@ -336,20 +345,12 @@
         
         // fifth check, is save path viable?
         if(path.indexOf("/") != -1) {
-            // see if directory path exists already
-            String dirPath = path.substring(0, path.lastIndexOf("/"));
-            
-            try {
-                File parent = this.getRealFile(weblog, dirPath);
-                if(parent == null || !parent.exists()) {
-                    messages.addError("error.upload.badPath");
-                }
-            } catch (Exception ex) {
-                // this is okay, just means that parent dir doesn't exist
+            // just make sure there is only 1 directory, we don't allow multi
+            // level directory hierarchies right now
+            if(path.lastIndexOf("/") != path.indexOf("/")) {
                 messages.addError("error.upload.badPath");
                 return false;
             }
-            
         }
         
         return true;
@@ -546,16 +547,16 @@
     
     
     /**
-     * A FileManagerImpl specific implementation of a WeblogResource.
+     * A FileManagerImpl specific implementation of a ThemeResource.
      *
-     * WeblogResources from the FileManagerImpl are backed by a java.io.File
+     * ThemeResources from the FileManagerImpl are backed by a java.io.File
      * object which represents the resource on a filesystem.
      *
      * This class is internal to the FileManagerImpl class because there should 
      * not be any external classes which need to construct their own instances
      * of this class.
      */
-    class WeblogResourceFile implements WeblogResource {
+    class WeblogResourceFile implements ThemeResource {
         
         // the physical java.io.File backing this resource
         private File resourceFile = null;
@@ -577,11 +578,7 @@
             return weblog;
         }
         
-        public String getURL(boolean absolute) {
-            return URLUtilities.getWeblogResourceURL(weblog, relativePath, absolute);
-        }
-        
-        public WeblogResource[] getChildren() {
+        public ThemeResource[] getChildren() {
             
             if(!resourceFile.isDirectory()) {
                 return null;
@@ -594,8 +591,8 @@
                 }
             });
             
-            // convert Files into WeblogResources
-            WeblogResource[] resources = new WeblogResource[dirFiles.length];
+            // convert Files into ThemeResources
+            ThemeResource[] resources = new ThemeResource[dirFiles.length];
             for(int i=0; i < dirFiles.length; i++) {
                 String filePath = dirFiles[i].getName();
                 if(relativePath != null && !relativePath.trim().equals("")) {

Added: incubator/roller/trunk/src/org/apache/roller/business/themes/SharedTheme.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/business/themes/SharedTheme.java?view=auto&rev=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/business/themes/SharedTheme.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/business/themes/SharedTheme.java Thu Apr  5 11:15:32 2007
@@ -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.business.themes;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.ArrayList;
+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.roller.pojos.Theme;
+import org.apache.roller.pojos.ThemeResource;
+import org.apache.roller.pojos.ThemeTemplate;
+
+
+/**
+ * A SharedTheme is a theme implementation which is designed to be shared by
+ * multiple weblogs using a common set of resources.
+ */
+public abstract class SharedTheme implements Theme, Serializable, Comparable {
+    
+    protected String id = null;
+    protected String name = null;
+    protected String description = null;
+    protected String author = null;
+    protected String customStylesheet = null;
+    protected Date lastModified = null;
+    protected boolean enabled = false;
+    
+    public abstract List getResources();
+    
+    
+    /**
+     * @see java.lang.Comparable#compareTo(java.lang.Object)
+     */
+    public int compareTo(Object o) {
+        SharedTheme other = (SharedTheme) o;
+        return getName().compareTo(other.getName());
+    }
+    
+    
+    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 getCustomStylesheet() {
+        return customStylesheet;
+    }
+
+    public void setCustomStylesheet(String customStylesheet) {
+        this.customStylesheet = customStylesheet;
+    }
+    
+    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;
+    }
+
+}

Added: incubator/roller/trunk/src/org/apache/roller/business/themes/SharedThemeFromDir.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/business/themes/SharedThemeFromDir.java?view=auto&rev=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/business/themes/SharedThemeFromDir.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/business/themes/SharedThemeFromDir.java Thu Apr  5 11:15:32 2007
@@ -0,0 +1,280 @@
+/*
+ * 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.business.themes;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+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.apache.roller.pojos.Theme;
+import org.apache.roller.pojos.ThemeResource;
+import org.apache.roller.pojos.ThemeTemplate;
+
+
+/**
+ * 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.
+ */
+public class SharedThemeFromDir extends SharedTheme {
+    
+    private static Log log = LogFactory.getLog(SharedThemeFromDir.class);
+    
+    // the filesystem directory where we should read this theme from
+    private String themeDir = null;
+    
+    // we keep templates in a Map for faster lookups by name
+    // the Map contains ... (template name, ThemeTemplate)
+    private Map templatesByName = new HashMap();
+    
+    // we keep templates in a Map for faster lookups by link
+    // the Map contains ... (template link, ThemeTemplate)
+    private Map templatesByLink = new HashMap();
+    
+    // we keep templates in a Map for faster lookups by action
+    // the Map contains ... (template action, ThemeTemplate)
+    private Map templatesByAction = new HashMap();
+    
+    // we keep resources in a Map for faster lookups by path
+    // the Map contains ... (resource path, ThemeResource)
+    private Map resources = new HashMap();
+    
+    
+    public SharedThemeFromDir(String themeDirPath) {
+        this.themeDir = themeDirPath;
+        
+        // load the theme elements and cache 'em
+        loadThemeFromDisk();
+    }
+
+    
+    /**
+     * Get the collection of all templates associated with this Theme.
+     */
+    public List getTemplates() {
+        return new ArrayList(this.templatesByName.values());
+    }
+    
+    
+    public ThemeTemplate getDefaultTemplate() {
+        return (ThemeTemplate) this.templatesByAction.get(ThemeTemplate.ACTION_WEBLOG);
+    }
+    
+    
+    /**
+     * Lookup the specified template by name.
+     * Returns null if the template cannot be found.
+     */
+    public ThemeTemplate getTemplateByName(String name) {
+        return (ThemeTemplate) this.templatesByName.get(name);
+    }
+    
+    
+    /**
+     * Lookup the specified template by link.
+     * Returns null if the template cannot be found.
+     */
+    public ThemeTemplate getTemplateByLink(String link) {
+        return (ThemeTemplate) this.templatesByLink.get(link);
+    }
+    
+    
+    /**
+     * Lookup the specified template by action.
+     * Returns null if the template cannot be found.
+     */
+    public ThemeTemplate getTemplateByAction(String action) {
+        return (ThemeTemplate) this.templatesByAction.get(action);
+    }
+    
+    
+    /**
+     * Set the value for a given template name.
+     */
+    public void addTemplate(ThemeTemplate template) {
+        this.templatesByName.put(template.getName(), template);
+        this.templatesByLink.put(template.getLink(), template);
+        this.templatesByAction.put(template.getAction(), template);
+    }
+    
+    
+    /**
+     * Get the collection of all resources associated with this Theme.
+     *
+     * It is assured that the resources are returned sorted by pathname.
+     */
+    public List getResources() {
+        
+        // make sure resources are sorted.
+        List myResources = new ArrayList(this.resources.values());
+        Collections.sort(myResources);
+        
+        return myResources;
+    }
+    
+    
+    /**
+     * Lookup the specified resource by path.
+     * Returns null if the resource cannot be found.
+     */
+    public ThemeResource getResource(String path) {
+        return (ThemeResource) this.resources.get(path);
+    }
+    
+    
+    /**
+     * Set the value for a given resource path.
+     */
+    public void setResource(String path, SharedThemeResourceFromDir resource) {
+        this.resources.put(path, resource);
+    }
+    
+    
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(name);
+        sb.append("\n");
+        
+        Iterator it = this.templatesByName.values().iterator();
+        while(it.hasNext()) {
+            sb.append(it.next());
+            sb.append("\n");
+        }
+        
+        return sb.toString();
+        
+    }
+    
+    
+    /**
+     * Load all the elements of this theme from disk and cache them.
+     */
+    private void loadThemeFromDisk() {
+        
+        log.debug("Parsing theme descriptor for "+this.themeDir);
+        
+        ThemeMetadata themeMetadata = null;
+        try {
+            // lookup theme descriptor and parse it
+            ThemeMetadataParser parser = new ThemeMetadataParser();
+            InputStream is = new FileInputStream(this.themeDir + File.separator + "theme.xml");
+            themeMetadata = parser.unmarshall(is);
+        } catch (Exception ex) {
+            log.warn("Unable to parse theme descriptor for theme "+this.themeDir, ex);
+            return;
+        }
+        
+        log.debug("Loading Theme "+themeMetadata.getName());
+        
+        // use parsed theme descriptor to load Theme data
+        setId(themeMetadata.getId());
+        setName(themeMetadata.getName());
+        setDescription(themeMetadata.getName());
+        setAuthor(themeMetadata.getAuthor());
+        setCustomStylesheet(themeMetadata.getCustomStylesheet());
+        setLastModified(new Date());
+        setEnabled(true);
+        
+        // go through static resources and add them to the theme
+        String resourcePath = null;
+        Iterator resourcesIter = themeMetadata.getResources().iterator();
+        while (resourcesIter.hasNext()) {
+            resourcePath = (String) resourcesIter.next();
+            
+            // construct ThemeResource object from resource
+            File resourceFile = new File(this.themeDir + File.separator + resourcePath);
+            
+            // Continue reading theme even if problem encountered with one file
+            if(!resourceFile.exists() || !resourceFile.canRead()) {
+                log.warn("Couldn't read theme resource file ["+resourcePath+"]");
+                continue;
+            }
+            
+            // add it to the theme
+            setResource(resourcePath, new SharedThemeResourceFromDir(resourcePath, resourceFile));
+        }
+        
+        // go through templates and read in contents to a ThemeTemplate
+        ThemeTemplate theme_template = null;
+        ThemeMetadataTemplate templateMetadata = null;
+        Iterator templatesIter = themeMetadata.getTemplates().iterator();
+        while (templatesIter.hasNext()) {
+            templateMetadata = (ThemeMetadataTemplate) templatesIter.next();
+            
+            // construct File object from path
+            File templateFile = new File(this.themeDir + File.separator + 
+                    templateMetadata.getContentsFile());
+            
+            // Continue reading theme even if problem encountered with one file
+            if(!templateFile.exists() && !templateFile.canRead()) {
+                log.error("Couldn't read theme template file ["+templateFile+"]");
+                continue;
+            }
+            
+            char[] chars = null;
+            int length;
+            try {
+                chars = new char[(int) templateFile.length()];
+            	FileInputStream stream = new FileInputStream(templateFile);
+            	InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
+                length = reader.read(chars);            
+            } catch (Exception noprob) {
+                log.error("Exception reading template file ["+templateFile+"]");
+                if (log.isDebugEnabled()) 
+                    log.debug(noprob);
+                continue;
+            }
+            
+            String decorator = "_decorator";
+            if("_decorator".equals(templateMetadata.getName())) {
+                decorator = null;
+            }
+            
+            // construct ThemeTemplate representing this file
+            // a few restrictions for now:
+            //   - decorator is always "_decorator" or null
+            theme_template = new SharedThemeTemplate(
+                    this,
+                    themeMetadata.getId()+":"+templateMetadata.getName(),
+                    templateMetadata.getAction(),
+                    templateMetadata.getName(),
+                    templateMetadata.getDescription(),
+                    new String(chars, 0, length),
+                    templateMetadata.getLink(),
+                    new Date(templateFile.lastModified()),
+                    templateMetadata.getTemplateLanguage(),
+                    templateMetadata.isHidden(),
+                    templateMetadata.isNavbar(),
+                    decorator);
+
+            // add it to the theme
+            addTemplate(theme_template);
+        }
+    }
+    
+}

Added: incubator/roller/trunk/src/org/apache/roller/business/themes/SharedThemeResourceFromDir.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/business/themes/SharedThemeResourceFromDir.java?view=auto&rev=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/business/themes/SharedThemeResourceFromDir.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/business/themes/SharedThemeResourceFromDir.java Thu Apr  5 11:15:32 2007
@@ -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.business.themes;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.Serializable;
+import org.apache.roller.pojos.ThemeResource;
+
+
+/**
+ * A FileManagerImpl specific implementation of a ThemeResource.
+ *
+ * ThemeResources from the FileManagerImpl are backed by a java.io.File
+ * object which represents the resource on a filesystem.
+ *
+ * This class is internal to the FileManagerImpl class because there should
+ * not be any external classes which need to construct their own instances
+ * of this class.
+ */
+public class SharedThemeResourceFromDir 
+        implements ThemeResource, Serializable, Comparable {
+    
+    // the physical java.io.File backing this resource
+    private File resourceFile = null;
+    
+    // the relative path of the resource within the theme
+    private String relativePath = null;
+    
+    
+    public SharedThemeResourceFromDir(String path, File file) {
+        relativePath = path;
+        resourceFile = file;
+    }
+    
+    
+    /**
+     * @see java.lang.Comparable#compareTo(java.lang.Object)
+     */
+    public int compareTo(Object o) {
+        ThemeResource other = (ThemeResource) o;
+        return getPath().compareTo(other.getPath());
+    }
+    
+    
+    public ThemeResource[] getChildren() {
+        return null;
+    }
+    
+    
+    public String getName() {
+        return resourceFile.getName();
+    }
+    
+    public String getPath() {
+        return relativePath;
+    }
+    
+    public long getLastModified() {
+        return resourceFile.lastModified();
+    }
+    
+    public long getLength() {
+        return resourceFile.length();
+    }
+    
+    public boolean isDirectory() {
+        return resourceFile.isDirectory();
+    }
+    
+    public boolean isFile() {
+        return resourceFile.isFile();
+    }
+    
+    public InputStream getInputStream() {
+        try {
+            return new FileInputStream(resourceFile);
+        } catch (java.io.FileNotFoundException ex) {
+            // should never happen, rethrow as runtime exception
+            throw new RuntimeException("Error constructing input stream", ex);
+        }
+    }
+    
+}

Added: incubator/roller/trunk/src/org/apache/roller/business/themes/SharedThemeTemplate.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/business/themes/SharedThemeTemplate.java?view=auto&rev=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/business/themes/SharedThemeTemplate.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/business/themes/SharedThemeTemplate.java Thu Apr  5 11:15:32 2007
@@ -0,0 +1,182 @@
+/*
+ * 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.business.themes;
+
+import java.io.Serializable;
+import java.util.Date;
+import org.apache.roller.RollerException;
+import org.apache.roller.pojos.ThemeTemplate;
+
+
+/**
+ * A Theme based implementation of a Template.  A ThemeTemplate represents a
+ * template which is part of a shared Theme.
+ */
+public class SharedThemeTemplate implements ThemeTemplate, Serializable {
+    
+    private String id = null;
+    private String action = null;
+    private String name = null;
+    private String description = null;
+    private String contents = null;
+    private String link = null;
+    private Date lastModified = null;
+    private String templateLanguage = null;
+    private boolean hidden = false;
+    private boolean navbar = false;
+    private String decoratorName = null;
+    private String  outputContentType = null;
+    
+    private SharedTheme myTheme = null;
+    
+    
+    public SharedThemeTemplate() {}
+    
+    public SharedThemeTemplate(SharedTheme theme, String id, String action, String name, 
+            String desc, String contents, String link, Date date, 
+            String tempLang, boolean hid, boolean navbar, String decor) {
+        
+        this.myTheme = theme;
+        this.id = id;
+        this.action = action;
+        this.name = name;
+        this.description = desc;
+        this.contents = contents;
+        this.link = link;
+        this.lastModified = date;
+        this.templateLanguage = tempLang;
+        this.hidden = hid;
+        this.navbar = navbar;
+        this.decoratorName = decor;
+    }
+    
+    
+    public ThemeTemplate getDecorator() {
+        if(decoratorName != null && !id.equals(decoratorName)) {
+            try {
+                return myTheme.getTemplateByName(decoratorName);
+            } catch (RollerException ex) {
+                // some kind of error getting decorator
+            }
+        }
+        return null;
+    }
+    
+    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 getTemplateLanguage() {
+        return templateLanguage;
+    }
+
+    public void setTemplateLanguage(String templateLanguage) {
+        this.templateLanguage = templateLanguage;
+    }
+
+    public boolean isHidden() {
+        return hidden;
+    }
+
+    public void setHidden(boolean isHidden) {
+        this.hidden = isHidden;
+    }
+
+    public boolean isNavbar() {
+        return navbar;
+    }
+
+    public void setNavbar(boolean navbar) {
+        this.navbar = navbar;
+    }
+
+    public String getDecoratorName() {
+        return decoratorName;
+    }
+
+    public void setDecoratorName(String decorator) {
+        this.decoratorName = decorator;
+    }
+
+    public String getOutputContentType() {
+        return outputContentType;
+    }
+
+    public void setOutputContentType(String outputContentType) {
+        this.outputContentType = outputContentType;
+    }
+    
+    public String toString() {
+        return (id + "," + name + "," + description + "," + link + "," + 
+                lastModified + "\n\n" + contents + "\n");
+    }
+
+    public String getAction() {
+        return action;
+    }
+
+    public void setAction(String action) {
+        this.action = action;
+    }
+    
+}

Modified: incubator/roller/trunk/src/org/apache/roller/business/themes/ThemeManager.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/business/themes/ThemeManager.java?view=diff&rev=525922&r1=525921&r2=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/business/themes/ThemeManager.java (original)
+++ incubator/roller/trunk/src/org/apache/roller/business/themes/ThemeManager.java Thu Apr  5 11:15:32 2007
@@ -21,6 +21,7 @@
 import java.util.List;
 import org.apache.roller.RollerException;
 import org.apache.roller.pojos.Theme;
+import org.apache.roller.pojos.WeblogTheme;
 import org.apache.roller.pojos.WebsiteData;
 
 
@@ -36,11 +37,22 @@
      * @throws ThemeNotFoundException If the named theme cannot be found.
      * @throws RollerException If there is some kind of fatal backend error.
      **/
-    public Theme getTheme(String id)
+    public SharedTheme getTheme(String id)
         throws ThemeNotFoundException, RollerException;
     
     
     /**
+     * Get the WeblogTheme for a given weblog.
+     *
+     * @param weblog The weblog to get the theme for.
+     * @return WeblogTheme The theme to be used for the given weblog.
+     * @throws RollerException If there is some kind of fatal backend error.
+     */
+    public WeblogTheme getTheme(WebsiteData weblog)
+        throws RollerException;
+    
+    
+    /**
      * Get a list of all theme names that are currently enabled.
      * This list is ordered alphabetically by default.
      *
@@ -57,7 +69,7 @@
      *
      * @throws RollerException If there is some kind of error in saving.
      */
-    public void importTheme(WebsiteData website, Theme theme) 
+    public void importTheme(WebsiteData website, SharedTheme theme) 
         throws RollerException;
     
 }

Modified: incubator/roller/trunk/src/org/apache/roller/business/themes/ThemeManagerImpl.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/business/themes/ThemeManagerImpl.java?view=diff&rev=525922&r1=525921&r2=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/business/themes/ThemeManagerImpl.java (original)
+++ incubator/roller/trunk/src/org/apache/roller/business/themes/ThemeManagerImpl.java Thu Apr  5 11:15:32 2007
@@ -21,8 +21,6 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FilenameFilter;
-import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
@@ -40,8 +38,10 @@
 import org.apache.roller.business.UserManager;
 import org.apache.roller.config.RollerConfig;
 import org.apache.roller.pojos.Theme;
+import org.apache.roller.pojos.ThemeResource;
 import org.apache.roller.pojos.ThemeTemplate;
 import org.apache.roller.pojos.WeblogTemplate;
+import org.apache.roller.pojos.WeblogTheme;
 import org.apache.roller.pojos.WebsiteData;
 
 
@@ -96,11 +96,11 @@
     /**
      * @see org.apache.roller.model.ThemeManager#getTheme(java.lang.String)
      */
-    public Theme getTheme(String id) 
+    public SharedTheme getTheme(String id) 
             throws ThemeNotFoundException, RollerException {
         
         // try to lookup theme from library
-        Theme theme = (Theme) this.themes.get(id);
+        SharedTheme theme = (SharedTheme) this.themes.get(id);
         
         // no theme?  throw exception.
         if(theme == null) {
@@ -112,6 +112,38 @@
     
     
     /**
+     * @see org.apache.roller.model.ThemeManager#getTheme(weblog)
+     */
+    public WeblogTheme getTheme(WebsiteData weblog) throws RollerException {
+        
+        if(weblog == null)
+            return null;
+        
+        WeblogTheme weblogTheme = null;
+        
+        // if theme is custom or null then return a WeblogCustomTheme
+        if(weblog.getEditorTheme() == null || 
+                WeblogTheme.CUSTOM.equals(weblog.getEditorTheme())) {
+            weblogTheme = new WeblogCustomTheme(weblog);
+            
+        // otherwise we are returning a WeblogSharedTheme
+        } else {
+            ThemeManager themeMgr = RollerFactory.getRoller().getThemeManager();
+            SharedTheme staticTheme =
+                    (SharedTheme) this.themes.get(weblog.getEditorTheme());
+            if(staticTheme != null) {
+                weblogTheme = new WeblogSharedTheme(weblog, staticTheme);
+            }
+        }
+        
+        // TODO: if somehow the theme is still null should we provide some
+        // kind of fallback option like a default theme?
+        
+        return weblogTheme;
+    }
+
+    
+    /**
      * @see org.apache.roller.model.ThemeManager#getEnabledThemesList()
      *
      * TODO: reimplement enabled vs. disabled logic once we support it
@@ -130,10 +162,10 @@
     /**
      * @see org.apache.roller.model.ThemeManager#importTheme(website, theme)
      */
-    public void importTheme(WebsiteData website, Theme theme)
+    public void importTheme(WebsiteData website, SharedTheme theme)
             throws RollerException {
         
-        log.debug("Importing theme "+theme.getName()+" to weblog "+website.getName());
+        log.debug("Importing theme ["+theme.getName()+"] to weblog ["+website.getName()+"]");
         
         try {
             UserManager userMgr = RollerFactory.getRoller().getUserManager();
@@ -202,7 +234,7 @@
             
             
             // always update this weblog's theme and customStylesheet, then save
-            website.setEditorTheme(Theme.CUSTOM);
+            website.setEditorTheme(WeblogTheme.CUSTOM);
             website.setCustomStylesheetPath(theme.getCustomStylesheet());
             userMgr.saveWebsite(website);
             
@@ -212,26 +244,18 @@
             
             List resources = theme.getResources();
             Iterator iterat = resources.iterator();
-            File resourceFile = null;
+            ThemeResource resource = null;
             while ( iterat.hasNext() ) {
-                resourceFile = (File) iterat.next();
-                
-                String path = resourceFile.getAbsolutePath().substring(
-                        this.themeDir.length()+theme.getId().length()+1);
-                
-                // make sure path isn't prefixed with a /
-                if(path.startsWith("/")) {
-                    path = path.substring(1);
-                }
+                resource = (ThemeResource) iterat.next();
                 
-                log.debug("Importing resource "+resourceFile.getAbsolutePath()+" to "+path);
+                log.debug("Importing resource to "+resource.getPath());
                 
                 try {
-                    if(resourceFile.isDirectory()) {
-                        fileMgr.createDirectory(website, path);
+                    if(resource.isDirectory()) {
+                        fileMgr.createDirectory(website, resource.getPath());
                     } else {
-                        fileMgr.saveFile(website, path, "text/plain", 
-                                resourceFile.length(), new FileInputStream(resourceFile));
+                        fileMgr.saveFile(website, resource.getPath(), "text/plain", 
+                                resource.getLength(), resource.getInputStream());
                     }
                 } catch (Exception ex) {
                     log.info(ex);
@@ -272,7 +296,7 @@
         // now go through each theme and load it into a Theme object
         for(int i=0; i < themenames.length; i++) {
             try {
-                Theme theme = loadThemeFromDisk(this.themeDir + File.separator + themenames[i]);
+                Theme theme = new SharedThemeFromDir(this.themeDir + File.separator + themenames[i]);
                 if(theme != null) {
                     themes.put(theme.getId(), theme);
                 }
@@ -283,117 +307,6 @@
         }
         
         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 themepath) {
-        
-        log.debug("Parsing theme descriptor for "+themepath);
-        
-        ThemeMetadata themeMetadata = null;
-        try {
-            // lookup theme descriptor and parse it
-            ThemeMetadataParser parser = new ThemeMetadataParser();
-            InputStream is = new FileInputStream(themepath + File.separator + "theme.xml");
-            themeMetadata = parser.unmarshall(is);
-        } catch (Exception ex) {
-            log.warn("Unable to parse theme descriptor for theme "+themepath, ex);
-            return null;
-        }
-        
-        log.debug("Loading Theme "+themeMetadata.getName());
-        
-        // use parsed theme descriptor to load Theme object
-        Theme theme = new Theme();
-        theme.setId(themeMetadata.getId());
-        theme.setName(themeMetadata.getName());
-        theme.setDescription(themeMetadata.getName());
-        theme.setAuthor(themeMetadata.getAuthor());
-        theme.setCustomStylesheet(themeMetadata.getCustomStylesheet());
-        theme.setLastModified(new Date());
-        theme.setEnabled(true);
-        
-        // go through static resources and add them to the theme
-        String resourcePath = null;
-        Iterator resourcesIter = themeMetadata.getResources().iterator();
-        while (resourcesIter.hasNext()) {
-            resourcePath = (String) resourcesIter.next();
-            
-            // construct File object from resource
-            File resourceFile = new File(themepath + File.separator + resourcePath);
-            
-            // Continue reading theme even if problem encountered with one file
-            if(!resourceFile.exists() || !resourceFile.canRead()) {
-                log.warn("Couldn't read theme resource file ["+resourcePath+"]");
-                continue;
-            }
-            
-            // add it to the theme
-            theme.setResource(resourcePath, resourceFile);
-        }
-        
-        // go through templates and read in contents to a ThemeTemplate
-        ThemeTemplate theme_template = null;
-        ThemeMetadataTemplate templateMetadata = null;
-        Iterator templatesIter = themeMetadata.getTemplates().iterator();
-        while (templatesIter.hasNext()) {
-            templateMetadata = (ThemeMetadataTemplate) templatesIter.next();
-            
-            // construct File object from path
-            File templateFile = new File(themepath + File.separator + 
-                    templateMetadata.getContentsFile());
-            
-            // Continue reading theme even if problem encountered with one file
-            if(!templateFile.exists() && !templateFile.canRead()) {
-                log.error("Couldn't read theme template file ["+templateFile+"]");
-                continue;
-            }
-            
-            char[] chars = null;
-            int length;
-            try {
-                chars = new char[(int) templateFile.length()];
-            	FileInputStream stream = new FileInputStream(templateFile);
-            	InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
-                length = reader.read(chars);            
-            } catch (Exception noprob) {
-                log.error("Exception reading template file ["+templateFile+"]");
-                if (log.isDebugEnabled()) 
-                    log.debug(noprob);
-                continue;
-            }
-            
-            String decorator = "_decorator";
-            if("_decorator".equals(templateMetadata.getName())) {
-                decorator = null;
-            }
-            
-            // construct ThemeTemplate representing this file
-            // a few restrictions for now:
-            //   - decorator is always "_decorator" or null
-            theme_template = new ThemeTemplate(
-                    theme,
-                    themeMetadata.getId()+":"+templateMetadata.getName(),
-                    templateMetadata.getAction(),
-                    templateMetadata.getName(),
-                    templateMetadata.getDescription(),
-                    new String(chars, 0, length),
-                    templateMetadata.getLink(),
-                    new Date(templateFile.lastModified()),
-                    templateMetadata.getTemplateLanguage(),
-                    templateMetadata.isHidden(),
-                    templateMetadata.isNavbar(),
-                    decorator);
-
-            // add it to the theme
-            theme.addTemplate(theme_template);
-        }
-        
-        return theme;
     }
     
 }

Added: incubator/roller/trunk/src/org/apache/roller/business/themes/WeblogCustomTheme.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/business/themes/WeblogCustomTheme.java?view=auto&rev=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/business/themes/WeblogCustomTheme.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/business/themes/WeblogCustomTheme.java Thu Apr  5 11:15:32 2007
@@ -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.business.themes;
+
+import java.util.Date;
+import java.util.List;
+import org.apache.roller.RollerException;
+import org.apache.roller.business.FileManager;
+import org.apache.roller.business.FileNotFoundException;
+import org.apache.roller.business.FilePathException;
+import org.apache.roller.business.RollerFactory;
+import org.apache.roller.business.UserManager;
+import org.apache.roller.pojos.ThemeResource;
+import org.apache.roller.pojos.ThemeTemplate;
+import org.apache.roller.pojos.WeblogTheme;
+import org.apache.roller.pojos.WebsiteData;
+
+
+/**
+ * A WeblogTheme custom defined by the weblog owner.
+ */
+public class WeblogCustomTheme extends WeblogTheme {
+    
+    
+    public WeblogCustomTheme(WebsiteData weblog) {
+        super(weblog);
+    }
+    
+    
+    public String getId() {
+        return CUSTOM;
+    }
+    
+    public String getName() {
+        return CUSTOM;
+    }
+    
+    public String getDescription() {
+        return CUSTOM;
+    }
+
+    public String getAuthor() {
+        return "N/A";
+    }
+
+    public String getCustomStylesheet() {
+        return this.weblog.getCustomStylesheetPath();
+    }
+    
+    public Date getLastModified() {
+        return this.weblog.getLastModified();
+    }
+    
+    public boolean isEnabled() {
+        return true;
+    }
+    
+    
+    /**
+     * Get the collection of all templates associated with this Theme.
+     */
+    public List getTemplates() throws RollerException {
+        UserManager userMgr = RollerFactory.getRoller().getUserManager();
+        return userMgr.getPages(this.weblog);
+    }
+    
+    
+    public ThemeTemplate getDefaultTemplate() throws RollerException {
+        UserManager userMgr = RollerFactory.getRoller().getUserManager();
+        return userMgr.getPageByAction(this.weblog, ThemeTemplate.ACTION_WEBLOG);
+    }
+    
+    
+    /**
+     * Lookup the specified template by action.
+     * Returns null if the template cannot be found.
+     */
+    public ThemeTemplate getTemplateByAction(String action) throws RollerException {
+        if(action == null)
+            return null;
+        
+        UserManager userMgr = RollerFactory.getRoller().getUserManager();
+        return userMgr.getPageByAction(this.weblog, action);
+    }
+    
+    
+    /**
+     * Lookup the specified template by name.
+     * Returns null if the template cannot be found.
+     */
+    public ThemeTemplate getTemplateByName(String name) throws RollerException {
+        if(name == null)
+            return null;
+        
+        UserManager userMgr = RollerFactory.getRoller().getUserManager();
+        return userMgr.getPageByName(this.weblog, name);
+    }
+    
+    
+    /**
+     * Lookup the specified template by link.
+     * Returns null if the template cannot be found.
+     */
+    public ThemeTemplate getTemplateByLink(String link) throws RollerException {
+        if(link == null)
+            return null;
+        
+        UserManager userMgr = RollerFactory.getRoller().getUserManager();
+        return userMgr.getPageByLink(this.weblog, link);
+    }
+    
+    
+    /**
+     * Lookup the specified resource by path.
+     * Returns null if the resource cannot be found.
+     */
+    public ThemeResource getResource(String path) {
+        
+        ThemeResource resource = null;
+        
+        try {
+            FileManager fileMgr = RollerFactory.getRoller().getFileManager();
+            resource = fileMgr.getFile(this.weblog, path);
+        } catch (RollerException ex) {
+            // ignored, resource considered not found
+        }
+        
+        return resource;
+    }
+    
+}

Added: incubator/roller/trunk/src/org/apache/roller/business/themes/WeblogSharedTheme.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/business/themes/WeblogSharedTheme.java?view=auto&rev=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/business/themes/WeblogSharedTheme.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/business/themes/WeblogSharedTheme.java Thu Apr  5 11:15:32 2007
@@ -0,0 +1,225 @@
+/*
+ * 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.business.themes;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.RollerException;
+import org.apache.roller.business.FileManager;
+import org.apache.roller.business.FileNotFoundException;
+import org.apache.roller.business.FilePathException;
+import org.apache.roller.business.RollerFactory;
+import org.apache.roller.business.UserManager;
+import org.apache.roller.pojos.ThemeResource;
+import org.apache.roller.pojos.ThemeTemplate;
+import org.apache.roller.pojos.WeblogTheme;
+import org.apache.roller.pojos.WebsiteData;
+
+
+/**
+ * A WeblogTheme shared by many weblogs and backed by a SharedTheme.
+ */
+public class WeblogSharedTheme extends WeblogTheme {
+    
+    private static Log log = LogFactory.getLog(WeblogSharedTheme.class);
+    
+    private SharedTheme theme = null;
+    
+    
+    public WeblogSharedTheme(WebsiteData weblog, SharedTheme theme) {
+        super(weblog);
+        this.theme = theme;
+    }
+    
+    
+    public String getId() {
+        return this.theme.getId();
+    }
+    
+    public String getName() {
+        return this.theme.getName();
+    }
+    
+    public String getDescription() {
+        return this.theme.getDescription();
+    }
+
+    public String getCustomStylesheet() {
+        return this.theme.getCustomStylesheet();
+    }
+    
+    public Date getLastModified() {
+        return this.theme.getLastModified();
+    }
+    
+    public boolean isEnabled() {
+        return this.theme.isEnabled();
+    }
+    
+    
+    /**
+     * Get the collection of all templates associated with this Theme.
+     */
+    public List getTemplates() throws RollerException {
+        
+        Map pages = new TreeMap();
+        
+        // first get the pages from the db
+        try {
+            ThemeTemplate template = null;
+            UserManager userMgr = RollerFactory.getRoller().getUserManager();
+            Iterator dbPages = userMgr.getPages(this.weblog).iterator();
+            while(dbPages.hasNext()) {
+                template = (ThemeTemplate) dbPages.next();
+                pages.put(template.getName(), template);
+            }
+        } catch(Exception e) {
+            // db error
+            log.error(e);
+        }
+        
+        
+        // now get theme pages if needed and put them in place of db pages
+        try {
+            ThemeTemplate template = null;
+            Iterator themePages = this.theme.getTemplates().iterator();
+            while(themePages.hasNext()) {
+                template = (ThemeTemplate) themePages.next();
+                
+                // note that this will put theme pages over custom
+                // pages in the pages list, which is what we want
+                pages.put(template.getName(), template);
+            }
+        } catch(Exception e) {
+            // how??
+            log.error(e);
+        }
+        
+        return new ArrayList(pages.values());
+    }
+    
+    
+    /**
+     * Lookup the default template.
+     */
+    public ThemeTemplate getDefaultTemplate() throws RollerException {
+        return this.theme.getDefaultTemplate();
+    }
+    
+    
+    /**
+     * Lookup the specified template by action.
+     * Returns null if the template cannot be found.
+     */
+    public ThemeTemplate getTemplateByAction(String action) throws RollerException {
+        
+        if(action == null)
+            return null;
+        
+        // NOTE: we specifically do *NOT* return templates by action from the
+        // weblog's custom templates if the weblog is using a theme because we
+        // don't want old templates to take effect when using a specific theme
+        return this.theme.getTemplateByAction(action);
+    }
+    
+    
+    /**
+     * Lookup the specified template by name.
+     * Returns null if the template cannot be found.
+     */
+    public ThemeTemplate getTemplateByName(String name) throws RollerException {
+        
+        if(name == null)
+            return null;
+        
+        ThemeTemplate template = null;
+        
+        // first check if this user has selected a theme
+        // if so then return the proper theme template
+        template = this.theme.getTemplateByName(name);
+        
+        // if we didn't get the Template from a theme then look in the db
+        if(template == null) {
+            UserManager userMgr = RollerFactory.getRoller().getUserManager();
+            template = userMgr.getPageByName(this.weblog, name);
+        }
+        
+        return template;
+    }
+    
+    
+    /**
+     * Lookup the specified template by link.
+     * Returns null if the template cannot be found.
+     */
+    public ThemeTemplate getTemplateByLink(String link) throws RollerException {
+        
+        if(link == null)
+            return null;
+        
+        ThemeTemplate template = null;
+        
+        // first check if this user has selected a theme
+        // if so then return the proper theme template
+        template = this.theme.getTemplateByLink(link);
+        
+        // if we didn't get the Template from a theme then look in the db
+        if(template == null) {
+            UserManager userMgr = RollerFactory.getRoller().getUserManager();
+            template = userMgr.getPageByLink(this.weblog, link);
+        }
+        
+        return template;
+    }
+    
+    
+    /**
+     * Lookup the specified resource by path.
+     * Returns null if the resource cannot be found.
+     */
+    public ThemeResource getResource(String path) {
+        
+        if(path == null)
+            return null;
+        
+        ThemeResource resource = null;
+        
+        // first check in our shared theme
+        resource = this.theme.getResource(path);
+        
+        // if we didn't find it in our theme then look in weblog uploads
+        if(resource == null) {
+            try {
+                FileManager fileMgr = RollerFactory.getRoller().getFileManager();
+                resource = fileMgr.getFile(this.weblog, path);
+            } catch (RollerException ex) {
+                // ignored, resource considered not found
+            }
+        }
+        
+        return resource;
+    }
+    
+}

Modified: incubator/roller/trunk/src/org/apache/roller/business/utils/UpgradeDatabase.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/business/utils/UpgradeDatabase.java?view=diff&rev=525922&r1=525921&r2=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/business/utils/UpgradeDatabase.java (original)
+++ incubator/roller/trunk/src/org/apache/roller/business/utils/UpgradeDatabase.java Thu Apr  5 11:15:32 2007
@@ -166,7 +166,7 @@
             PreparedStatement setCustomThemeStmt = con.prepareStatement(
                     "update website set editortheme = ?");
             
-            setCustomThemeStmt.setString(1, org.apache.roller.pojos.Theme.CUSTOM);
+            setCustomThemeStmt.setString(1, org.apache.roller.pojos.WeblogTheme.CUSTOM);
             setCustomThemeStmt.executeUpdate();
             
             if (!con.getAutoCommit()) con.commit();

Added: incubator/roller/trunk/src/org/apache/roller/pojos/Resource.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/pojos/Resource.java?view=auto&rev=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/pojos/Resource.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/pojos/Resource.java Thu Apr  5 11:15:32 2007
@@ -0,0 +1,71 @@
+/*
+ * 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.pojos;
+
+import java.io.InputStream;
+
+
+/**
+ * Represents a static resource of some kind.
+ */
+public interface Resource {
+    
+    
+    /**
+     * The short name of this resource.
+     * i.e. "some.jpg"
+     *
+     * @returns The short name for the resource.
+     */
+    public String getName();
+    
+    
+    /**
+     * The path to this resource, relative to its container.
+     * i.e. "images/some.jpg"
+     *
+     * @returns The path to the resource, relative to its container.
+     */
+    public String getPath();
+    
+    
+    /**
+     * The last-modified time for this resource.
+     *
+     * @returns The last time the resource changed, as a long value.
+     */
+    public long getLastModified();
+    
+    
+    /**
+     * The length of this resource, in bytes.
+     *
+     * @returns The length of the resource in bytes.
+     */
+    public long getLength();
+    
+    
+    /**
+     * An InputStream that the resource can be read from.
+     *
+     * @returns an InputStream for the resource.
+     */
+    public InputStream getInputStream();
+    
+}

Modified: incubator/roller/trunk/src/org/apache/roller/pojos/StaticTemplate.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/pojos/StaticTemplate.java?view=diff&rev=525922&r1=525921&r2=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/pojos/StaticTemplate.java (original)
+++ incubator/roller/trunk/src/org/apache/roller/pojos/StaticTemplate.java Thu Apr  5 11:15:32 2007
@@ -32,41 +32,26 @@
 public class StaticTemplate implements Template, Serializable {
     
     private String id = null;
-    private String action = null;
     private String name = null;
     private String description = null;
-    private String contents = null;
-    private String link = null;
     private Date lastModified = new Date();
     private String templateLanguage = null;
-    private boolean hidden = false;
-    private boolean navbar = false;
     private String  outputContentType = null;
     
     
-    public StaticTemplate() {}
-    
-    public StaticTemplate(String id, String contents, String lang) {
+    public StaticTemplate(String id, String lang) {
         this.id = id;
         this.name = id;
         this.description = id;
-        this.contents = contents;
-        this.link = id;
         this.templateLanguage = lang;
     }
-
     
-    public Template getDecorator() {
-        return null;
-    }
     
     public String getId() {
         return id;
     }
 
     public void setId(String id) {
-        // Form bean workaround: empty string is never a valid id
-        if (id != null && id.trim().length() == 0) return; 
         this.id = id;
     }
 
@@ -86,22 +71,6 @@
         this.description = description;
     }
 
-    public String getContents() {
-        return contents;
-    }
-
-    public void setContents(String contents) {
-        this.contents = contents;
-    }
-
-    public String getLink() {
-        return link;
-    }
-
-    public void setLink(String link) {
-        this.link = link;
-    }
-
     public Date getLastModified() {
         return lastModified;
     }
@@ -117,22 +86,6 @@
     public void setTemplateLanguage(String templateLanguage) {
         this.templateLanguage = templateLanguage;
     }
-
-    public boolean isHidden() {
-        return hidden;
-    }
-
-    public void setHidden(boolean hidden) {
-        this.hidden = hidden;
-    }
-
-    public void setNavbar(boolean navbar) {
-        this.navbar = navbar;
-    }
-    
-    public boolean isNavbar() {
-        return navbar; 
-    }
     
     public String getOutputContentType() {
         return outputContentType;
@@ -140,13 +93,6 @@
 
     public void setOutputContentType(String outputContentType) {
         this.outputContentType = outputContentType;
-    }    
-
-    public String getAction() {
-        return action;
-    }
-
-    public void setAction(String action) {
-        this.action = action;
     }
+    
 }

Added: incubator/roller/trunk/src/org/apache/roller/pojos/StaticThemeTemplate.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/pojos/StaticThemeTemplate.java?view=auto&rev=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/pojos/StaticThemeTemplate.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/pojos/StaticThemeTemplate.java Thu Apr  5 11:15:32 2007
@@ -0,0 +1,162 @@
+/*
+ * 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.pojos;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * Represents a simple static Template.
+ *
+ * This template is not persisted or managed in any way, this class is here
+ * mainly as a wrapper so that we can represent our static template files as
+ * an object.
+ */
+public class StaticThemeTemplate implements ThemeTemplate, Serializable {
+    
+    private String id = null;
+    private String name = null;
+    private String description = null;
+    private String action = null;
+    private String link = null;
+    private String contents = null;
+    private boolean hidden = false;
+    private boolean navbar = false;
+    private Date lastModified = new Date();
+    private String templateLanguage = null;
+    private String outputContentType = null;
+    private String decoratorName = null;
+    private ThemeTemplate decorator = null;
+    
+    
+    public StaticThemeTemplate(String id, String lang) {
+        this.id = id;
+        this.name = id;
+        this.description = id;
+        this.link = id;
+        this.templateLanguage = lang;
+    }
+    
+    
+    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 Date getLastModified() {
+        return lastModified;
+    }
+
+    public void setLastModified(Date lastModified) {
+        this.lastModified = lastModified;
+    }
+
+    public String getTemplateLanguage() {
+        return templateLanguage;
+    }
+
+    public void setTemplateLanguage(String templateLanguage) {
+        this.templateLanguage = templateLanguage;
+    }
+    
+    public String getOutputContentType() {
+        return outputContentType;
+    }
+
+    public void setOutputContentType(String outputContentType) {
+        this.outputContentType = outputContentType;
+    }
+
+    public String getAction() {
+        return action;
+    }
+
+    public void setAction(String action) {
+        this.action = action;
+    }
+
+    public String getLink() {
+        return link;
+    }
+
+    public void setLink(String link) {
+        this.link = link;
+    }
+
+    public boolean isHidden() {
+        return hidden;
+    }
+
+    public void setHidden(boolean hidden) {
+        this.hidden = hidden;
+    }
+
+    public boolean isNavbar() {
+        return navbar;
+    }
+
+    public void setNavbar(boolean navbar) {
+        this.navbar = navbar;
+    }
+
+    public ThemeTemplate getDecorator() {
+        return decorator;
+    }
+
+    public void setDecorator(ThemeTemplate decorator) {
+        this.decorator = decorator;
+    }
+
+    public String getContents() {
+        return contents;
+    }
+
+    public void setContents(String contents) {
+        this.contents = contents;
+    }
+
+    public String getDecoratorName() {
+        return decoratorName;
+    }
+
+    public void setDecoratorName(String decoratorName) {
+        this.decoratorName = decoratorName;
+    }
+    
+}

Modified: incubator/roller/trunk/src/org/apache/roller/pojos/Template.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/pojos/Template.java?view=diff&rev=525922&r1=525921&r2=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/pojos/Template.java (original)
+++ incubator/roller/trunk/src/org/apache/roller/pojos/Template.java Thu Apr  5 11:15:32 2007
@@ -29,95 +29,35 @@
  */
 public interface Template {
     
-    public static final String ACTION_WEBLOG = "weblog";
-    public static final String ACTION_PERMALINK = "permalink";
-    public static final String ACTION_SEARCH = "search";
-    public static final String ACTION_TAGSINDEX = "tagsIndex";
-    public static final String ACTION_CUSTOM = "custom";
-    
-    // the full list of supported special actions, which purposely does not
-    // contain an entry for the 'custom' action
-    public static final String[] ACTIONS = {
-        ACTION_WEBLOG, 
-        ACTION_PERMALINK, 
-        ACTION_SEARCH, 
-        ACTION_TAGSINDEX
-    };
-    
-    
     /**
      * The unique identifier for this Template.
-     *
-     * @roller.wrapPojoMethod type="simple"
      */
     public String getId();
     
-    /**
-     * The action this template is defined for.
-     */
-    public String getAction();
     
     /**
      * A simple name for this Template.
-     *
-     * @roller.wrapPojoMethod type="simple"
      */
     public String getName();
     
+    
     /**
      * A description of the contents of this Template.
-     *
-     * @roller.wrapPojoMethod type="simple"
      */
     public String getDescription();
     
-    /**
-     * The contents or body of the Template.
-     *
-     * @roller.wrapPojoMethod type="simple"
-     */
-    public String getContents();
-    
-    /**
-     * The url link value for this Template.  If this template is not
-     * private this is the url that it can be accessed at.
-     *
-     * @roller.wrapPojoMethod type="simple"
-     */
-    public String getLink();
     
     /**
      * The last time the template was modified.
-     *
-     * @roller.wrapPojoMethod type="simple"
      */
     public Date getLastModified();
     
-    /**
-     * Is the Template hidden?  A hidden template cannot be accessed directly.
-     *
-     * @roller.wrapPojoMethod type="simple"
-     */
-    
-    public boolean isHidden();
-    
-    /**
-     * Is the Template to be included in the navbar?
-     *
-     * @roller.wrapPojoMethod type="simple"
-     */
-    public boolean isNavbar();
     
     /**
      * The templating language used by this template.
      */
     public String getTemplateLanguage();
     
-    /**
-     * The decorator Template to apply.  This returns null if no decorator
-     * should be applied.
-     */
-    public Template getDecorator();
     
     /**
      * Content-type of output or null if none defined.

Modified: incubator/roller/trunk/src/org/apache/roller/pojos/Theme.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/pojos/Theme.java?view=diff&rev=525922&r1=525921&r2=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/pojos/Theme.java (original)
+++ incubator/roller/trunk/src/org/apache/roller/pojos/Theme.java Thu Apr  5 11:15:32 2007
@@ -18,216 +18,91 @@
 
 package org.apache.roller.pojos;
 
-import java.io.File;
-import java.io.Serializable;
-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.roller.RollerException;
 
 
 /**
- * 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.
+ * A Theme represents the set of components which are used to generate the
+ * web design for a weblog along with some metadata like a name, etc.
  */
-public class Theme implements Serializable, Comparable {
-    
-    // this is the name that will be used to identify a user customized theme
-    public static final String CUSTOM = "custom";
-    
-    private String id = null;
-    private String name = null;
-    private String description = null;
-    private String author = null;
-    private String customStylesheet = null;
-    private Date lastModified = null;
-    private boolean enabled = false;
-    
-    // we keep templates in a Map for faster lookups by name
-    // the Map contains ... (template name, ThemeTemplate)
-    private Map templatesByName = new HashMap();
-    
-    // we keep templates in a Map for faster lookups by link
-    // the Map contains ... (template link, ThemeTemplate)
-    private Map templatesByLink = new HashMap();
-    
-    // we keep templates in a Map for faster lookups by action
-    // the Map contains ... (template action, ThemeTemplate)
-    private Map templatesByAction = new HashMap();
-    
-    // we keep resources in a Map for faster lookups by path
-    // the Map contains ... (resource path, File)
-    private Map resources = new HashMap();
+public interface Theme {
     
+    /**
+     * A unique identifier for this Theme.
+     */
+    public String getId();
     
-    public Theme() {}
-
     
     /**
-     * Get the collection of all templates associated with this Theme.
+     * A common or display name for this Theme.
      */
-    public List getTemplates() {
-        return new ArrayList(this.templatesByName.values());
-    }
+    public String getName();
     
     
-    public Template getDefaultTemplate() {
-        return (ThemeTemplate) this.templatesByAction.get(Template.ACTION_WEBLOG);
-    }
+    /**
+     * A description of the Theme.
+     */
+    public String getDescription();
     
     
     /**
-     * Lookup the specified template by name.
-     * Returns null if the template cannot be found.
+     * The last modification date of the Theme.
      */
-    public ThemeTemplate getTemplate(String name) {
-        return (ThemeTemplate) this.templatesByName.get(name);
-    }
+    public Date getLastModified();
     
     
     /**
-     * Lookup the specified template by link.
-     * Returns null if the template cannot be found.
+     * The path within the Theme to a custom stylesheet override, or null if
+     * no stylesheet override is set.
      */
-    public Template getTemplateByLink(String link) {
-        return (ThemeTemplate) this.templatesByLink.get(link);
-    }
+    public String getCustomStylesheet();
     
     
     /**
-     * Lookup the specified template by action.
-     * Returns null if the template cannot be found.
+     * Is the Theme enable for use?
      */
-    public Template getTemplateByAction(String action) {
-        return (ThemeTemplate) this.templatesByAction.get(action);
-    }
+    public boolean isEnabled();
     
     
     /**
-     * Set the value for a given template name.
+     * Get the list of all templates associated with this Theme.
      */
-    public void addTemplate(ThemeTemplate template) {
-        this.templatesByName.put(template.getName(), template);
-        this.templatesByLink.put(template.getLink(), template);
-        this.templatesByAction.put(template.getAction(), template);
-    }
+    public List getTemplates() throws RollerException;
     
     
     /**
-     * Get the collection of all resources associated with this Theme.
-     *
-     * It is assured that the resources are returned sorted by pathname.
+     * Lookup the default template for the Theme.
      */
-    public List getResources() {
-        
-        // make sure resources are sorted.
-        List myResources = new ArrayList(this.resources.values());
-        Collections.sort(myResources);
-        
-        return myResources;
-    }
+    public ThemeTemplate getDefaultTemplate() throws RollerException;
     
     
     /**
-     * Lookup the specified resource by path.
-     * Returns null if the resource cannot be found.
+     * Lookup a template by action.
+     * Returns null if the template cannot be found.
      */
-    public File getResource(String path) {
-        return (File) this.resources.get(path);
-    }
+    public ThemeTemplate getTemplateByAction(String action) throws RollerException;
     
     
     /**
-     * Set the value for a given resource path.
+     * Lookup a template by name.
+     * Returns null if the template cannot be found.
      */
-    public void setResource(String path, File resource) {
-        this.resources.put(path, resource);
-    }
+    public ThemeTemplate getTemplateByName(String name) throws RollerException;
     
     
-    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 getCustomStylesheet() {
-        return customStylesheet;
-    }
-
-    public void setCustomStylesheet(String customStylesheet) {
-        this.customStylesheet = customStylesheet;
-    }
-    
-    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.templatesByName.values().iterator();
-        while(it.hasNext()) {
-            sb.append(it.next());
-            sb.append("\n");
-        }
-        
-        return sb.toString();
-        
-    }
+    /**
+     * Lookup a template by link.
+     * Returns null if the template cannot be found.
+     */
+    public ThemeTemplate getTemplateByLink(String link) throws RollerException;
     
     
     /**
-     * @see java.lang.Comparable#compareTo(java.lang.Object)
-     */
-    public int compareTo(Object o) {
-        Theme other = (Theme) o;
-        return getName().compareTo(other.getName());
-    }
-
+     * Lookup a resource by path.
+     * Returns null if the resource cannot be found.
+     */
+    public ThemeResource getResource(String path);
+    
 }

Added: incubator/roller/trunk/src/org/apache/roller/pojos/ThemeResource.java
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/src/org/apache/roller/pojos/ThemeResource.java?view=auto&rev=525922
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/pojos/ThemeResource.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/pojos/ThemeResource.java Thu Apr  5 11:15:32 2007
@@ -0,0 +1,53 @@
+/*
+ * 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.pojos;
+
+
+/**
+ * A Resource that is attached to a Theme.
+ */
+public interface ThemeResource extends Resource {
+    
+    /**
+     * Does this resource represent a directory?  True if yes, False otherwise.
+     *
+     * @returns True if the resource is a directory, False otherwise.
+     */
+    public boolean isDirectory();
+    
+    
+    /**
+     * Does this resource represent a file?  True if yes, False otherwise.
+     *
+     * @returns True if the resource is a file, False otherwise.
+     */
+    public boolean isFile();
+    
+    
+    /**
+     * List child resources if this resource represents a directory.
+     *
+     * The children returned by this method should only be actual files.  No
+     * directories should be returned by this method.
+     *
+     * @returns null if resource is not a directory, otherwise a WeblogResource[].
+     */
+    public ThemeResource[] getChildren();
+    
+}