File Source: SharedThemeFromDir.java

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   *  contributor license agreements.  The ASF licenses this file to You
     4   * under the Apache License, Version 2.0 (the "License"); you may not
     5   * use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.  For additional information regarding
    15   * copyright in this work, please see the NOTICE file in the top level
    16   * directory of this distribution.
    17   */
    18  
    19  package org.apache.roller.weblogger.business.themes;
    20  
    21  import java.io.File;
    22  import java.io.FileInputStream;
    23  import java.io.InputStream;
    24  import java.io.InputStreamReader;
    25  import java.util.ArrayList;
    26  import java.util.Collections;
    27  import java.util.Date;
    28  import java.util.HashMap;
    29  import java.util.Iterator;
    30  import java.util.List;
    31  import java.util.Map;
    32  import org.apache.commons.lang.StringUtils;
    33  import org.apache.commons.logging.Log;
    34  import org.apache.commons.logging.LogFactory;
    35  import org.apache.roller.weblogger.pojos.ThemeResource;
    36  import org.apache.roller.weblogger.pojos.ThemeTemplate;
    37  import org.apache.roller.weblogger.pojos.WeblogTemplate;
    38  
    39  
    40  /**
    41   * The Theme object encapsulates all elements of a single weblog theme.  It
    42   * is used mostly to contain all the templates for a theme, but does contain
    43   * other theme related attributes such as name, last modifed date, etc.
    44   */
    45  public class SharedThemeFromDir extends SharedTheme {
    46      
             /* 
    P/P       *  Method: org.apache.roller.weblogger.business.themes.SharedThemeFromDir__static_init
              * 
              *  Postconditions:
              *    init'ed(log)
              */
    47      private static Log log = LogFactory.getLog(SharedThemeFromDir.class);
    48      
    49      // the filesystem directory where we should read this theme from
    50      private String themeDir = null;
    51      
    52      // the theme preview image
    53      private ThemeResource previewImage = null;
    54      
    55      // the theme stylesheet
    56      private ThemeTemplate stylesheet = null;
    57      
    58      // we keep templates in a Map for faster lookups by name
    59      // the Map contains ... (template name, ThemeTemplate)
    60      private Map templatesByName = new HashMap();
    61      
    62      // we keep templates in a Map for faster lookups by link
    63      // the Map contains ... (template link, ThemeTemplate)
    64      private Map templatesByLink = new HashMap();
    65      
    66      // we keep templates in a Map for faster lookups by action
    67      // the Map contains ... (template action, ThemeTemplate)
    68      private Map templatesByAction = new HashMap();
    69      
    70      // we keep resources in a Map for faster lookups by path
    71      // the Map contains ... (resource path, ThemeResource)
    72      private Map resources = new HashMap();
    73      
    74      
    75      public SharedThemeFromDir(String themeDirPath) 
                     /* 
    P/P               *  Method: void org.apache.roller.weblogger.business.themes.SharedThemeFromDir(String)
                      * 
                      *  Preconditions:
                      *    log != null
                      * 
                      *  Postconditions:
                      *    java.lang.StringBuilder:toString(...)._tainted == 0
                      *    init'ed(this.author)
                      *    init'ed(this.description)
                      *    this.enabled == 1
                      *    init'ed(this.id)
                      *    this.lastModified == &new Date(loadThemeFromDisk#8)
                      *    init'ed(this.name)
                      *    this.previewImage == One-of{null, &new SharedThemeResourceFromDir(loadThemeFromDisk#12)}
                      *    this.previewImage in Addr_Set{null,&new SharedThemeResourceFromDir(loadThemeFromDisk#12)}
                      *    this.resources == &new HashMap(SharedThemeFromDir#4)
                      *    ...
                      */
    76              throws ThemeInitializationException {
    77          
    78          this.themeDir = themeDirPath;
    79          
    80          // load the theme elements and cache 'em
    81          loadThemeFromDisk();
    82      }
    83  
    84      
    85      /**
    86       * Get a resource representing the preview image for this theme.
    87       */
    88      public ThemeResource getPreviewImage() {
                 /* 
    P/P           *  Method: ThemeResource getPreviewImage()
                  * 
                  *  Preconditions:
                  *    init'ed(this.previewImage)
                  * 
                  *  Postconditions:
                  *    return_value == this.previewImage
                  *    init'ed(return_value)
                  */
    89          return this.previewImage;
    90      }
    91      
    92      
    93      /**
    94       * Get the collection of all templates associated with this Theme.
    95       */
    96      public List getTemplates() {
                 /* 
    P/P           *  Method: List getTemplates()
                  * 
                  *  Preconditions:
                  *    this.templatesByName != null
                  * 
                  *  Postconditions:
                  *    return_value == &new ArrayList(getTemplates#1)
                  *    new ArrayList(getTemplates#1) num objects == 1
                  */
    97          return new ArrayList(this.templatesByName.values());
    98      }
    99      
   100      
   101      /**
   102       * Lookup the stylesheet.
   103       * Returns null if no stylesheet defined.
   104       */
   105      public ThemeTemplate getStylesheet() {
                 /* 
    P/P           *  Method: ThemeTemplate getStylesheet()
                  * 
                  *  Preconditions:
                  *    init'ed(this.stylesheet)
                  * 
                  *  Postconditions:
                  *    return_value == this.stylesheet
                  *    init'ed(return_value)
                  */
   106          return this.stylesheet;
   107      }
   108      
   109      
   110      /**
   111       * Looup the default template, action = weblog.
   112       * Returns null if the template cannot be found.
   113       */
   114      public ThemeTemplate getDefaultTemplate() {
                 /* 
    P/P           *  Method: ThemeTemplate getDefaultTemplate()
                  * 
                  *  Preconditions:
                  *    this.templatesByAction != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   115          return (ThemeTemplate) this.templatesByAction.get(ThemeTemplate.ACTION_WEBLOG);
   116      }
   117      
   118      
   119      /**
   120       * Lookup the specified template by name.
   121       * Returns null if the template cannot be found.
   122       */
   123      public ThemeTemplate getTemplateByName(String name) {
                 /* 
    P/P           *  Method: ThemeTemplate getTemplateByName(String)
                  * 
                  *  Preconditions:
                  *    this.templatesByName != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   124          return (ThemeTemplate) this.templatesByName.get(name);
   125      }
   126      
   127      
   128      /**
   129       * Lookup the specified template by link.
   130       * Returns null if the template cannot be found.
   131       */
   132      public ThemeTemplate getTemplateByLink(String link) {
                 /* 
    P/P           *  Method: ThemeTemplate getTemplateByLink(String)
                  * 
                  *  Preconditions:
                  *    this.templatesByLink != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   133          return (ThemeTemplate) this.templatesByLink.get(link);
   134      }
   135      
   136      
   137      /**
   138       * Lookup the specified template by action.
   139       * Returns null if the template cannot be found.
   140       */
   141      public ThemeTemplate getTemplateByAction(String action) {
                 /* 
    P/P           *  Method: ThemeTemplate getTemplateByAction(String)
                  * 
                  *  Preconditions:
                  *    this.templatesByAction != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   142          return (ThemeTemplate) this.templatesByAction.get(action);
   143      }
   144      
   145      
   146      /**
   147       * Get the collection of all resources associated with this Theme.
   148       *
   149       * It is assured that the resources are returned sorted by pathname.
   150       */
   151      public List getResources() {
   152          
   153          // make sure resources are sorted.
                 /* 
    P/P           *  Method: List getResources()
                  * 
                  *  Preconditions:
                  *    this.resources != null
                  * 
                  *  Postconditions:
                  *    return_value == &new ArrayList(getResources#1)
                  *    new ArrayList(getResources#1) num objects == 1
                  */
   154          List myResources = new ArrayList(this.resources.values());
   155          Collections.sort(myResources);
   156          
   157          return myResources;
   158      }
   159      
   160      
   161      /**
   162       * Lookup the specified resource by path.
   163       * Returns null if the resource cannot be found.
   164       */
   165      public ThemeResource getResource(String path) {
                 /* 
    P/P           *  Method: ThemeResource getResource(String)
                  * 
                  *  Preconditions:
                  *    this.resources != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   166          return (ThemeResource) this.resources.get(path);
   167      }
   168      
   169      
   170      public String toString() {
                 /* 
    P/P           *  Method: String toString()
                  * 
                  *  Preconditions:
                  *    init'ed(this.name)
                  *    this.templatesByName != null
                  * 
                  *  Presumptions:
                  *    java.util.Map:values(...)@175 != null
                  * 
                  *  Postconditions:
                  *    init'ed(java.lang.StringBuffer:toString(...)._tainted)
                  *    return_value == &java.lang.StringBuffer:toString(...)
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@176: {0}, {1}
                  */
   171          StringBuffer sb = new StringBuffer();
   172          sb.append(name);
   173          sb.append("\n");
   174          
   175          Iterator it = this.templatesByName.values().iterator();
   176          while(it.hasNext()) {
   177              sb.append(it.next());
   178              sb.append("\n");
   179          }
   180          
   181          return sb.toString();
   182          
   183      }
   184      
   185      
   186      /**
   187       * Load all the elements of this theme from disk and cache them.
   188       */
   189      private void loadThemeFromDisk() throws ThemeInitializationException {
   190          
                 /* 
    P/P           *  Method: void loadThemeFromDisk()
                  * 
                  *  Preconditions:
                  *    log != null
                  *    init'ed(this.themeDir)
                  *    (soft) this.resources != null
                  *    (soft) this.templatesByAction != null
                  *    (soft) this.templatesByLink != null
                  *    (soft) this.templatesByName != null
                  * 
                  *  Presumptions:
                  *    init'ed(java.io.File.separator)
                  *    java.util.Iterator:next(...)@283 != null
                  * 
                  *  Postconditions:
                  *    java.lang.StringBuilder:toString(...)._tainted == 0
                  *    init'ed(this.author)
                  *    init'ed(this.description)
                  *    this.enabled == 1
                  *    init'ed(this.id)
                  *    this.lastModified == &new Date(loadThemeFromDisk#8)
                  *    init'ed(this.name)
                  *    this.previewImage == One-of{old this.previewImage, &new SharedThemeResourceFromDir(loadThemeFromDisk#12)}
                  *    this.stylesheet == One-of{old this.stylesheet, &new SharedThemeTemplate(loadThemeFromDisk#16)}
                  *    new Date(loadThemeFromDisk#18) num objects <= 1
                  *    ...
                  * 
                  *  Test Vectors:
                  *    java.io.File:canRead(...)@215: {1}, {0}
                  *    java.io.File:canRead(...)@269: {1}, {0}
                  *    java.io.File:exists(...)@215: {0}, {1}
                  *    java.io.File:exists(...)@269: {0}, {1}
                  *    java.util.Iterator:hasNext(...)@262: {0}, {1}
                  *    java.util.Iterator:hasNext(...)@282: {0}, {1}
                  */
   191          log.debug("Parsing theme descriptor for "+this.themeDir);
   192          
   193          ThemeMetadata themeMetadata = null;
   194          try {
   195              // lookup theme descriptor and parse it
   196              ThemeMetadataParser parser = new ThemeMetadataParser();
   197              InputStream is = new FileInputStream(this.themeDir + File.separator + "theme.xml");
   198              themeMetadata = parser.unmarshall(is);
   199          } catch (Exception ex) {
   200              throw new ThemeInitializationException("Unable to parse theme descriptor for theme "+this.themeDir, ex);
   201          }
   202          
   203          log.debug("Loading Theme "+themeMetadata.getName());
   204          
   205          // use parsed theme descriptor to load Theme data
   206          setId(themeMetadata.getId());
   207          setName(themeMetadata.getName());
   208          setDescription(themeMetadata.getName());
   209          setAuthor(themeMetadata.getAuthor());
   210          setLastModified(new Date());
   211          setEnabled(true);
   212          
   213          // load resource representing preview image
   214          File previewFile = new File(this.themeDir + File.separator + themeMetadata.getPreviewImage());
   215          if(!previewFile.exists() || !previewFile.canRead()) {
   216              log.warn("Couldn't read theme [" + this.getName() + "] preview image file ["+themeMetadata.getPreviewImage()+"]");
   217          } else {
   218              this.previewImage = new SharedThemeResourceFromDir(themeMetadata.getPreviewImage(), previewFile);
   219          }
   220          
   221          // load stylesheet if possible
   222          if(themeMetadata.getStylesheet() != null) {
   223              
   224              ThemeMetadataTemplate stylesheetTmpl = themeMetadata.getStylesheet();
   225              
   226              // construct File object from path
   227              File templateFile = new File(this.themeDir + File.separator + 
   228                      stylesheetTmpl.getContentsFile());
   229              
   230              // read stylesheet contents
   231              String contents = loadTemplateFile(templateFile);
   232              if(contents == null) {
   233                  // if we don't have any contents then skip this one
   234                  log.error("Couldn't load stylesheet theme [" + this.getName() + "] template file ["+templateFile+"]");
   235              } else {
   236                  
   237                  // construct ThemeTemplate representing this file
   238                  SharedThemeTemplate theme_template = new SharedThemeTemplate(
   239                          this,
   240                          themeMetadata.getId()+":"+stylesheetTmpl.getName(),
   241                          WeblogTemplate.ACTION_CUSTOM,
   242                          stylesheetTmpl.getName(),
   243                          stylesheetTmpl.getDescription(),
   244                          contents,
   245                          stylesheetTmpl.getLink(),
   246                          new Date(templateFile.lastModified()),
   247                          stylesheetTmpl.getTemplateLanguage(),
   248                          false,
   249                          false);
   250                  
   251                  // store it
   252                  this.stylesheet = theme_template;
   253                  
   254                  // add it to templates list
   255                  addTemplate(theme_template);
   256              }
   257          }
   258          
   259          // go through static resources and add them to the theme
   260          String resourcePath = null;
   261          Iterator resourcesIter = themeMetadata.getResources().iterator();
   262          while (resourcesIter.hasNext()) {
   263              resourcePath = (String) resourcesIter.next();
   264              
   265              // construct ThemeResource object from resource
   266              File resourceFile = new File(this.themeDir + File.separator + resourcePath);
   267              
   268              // Continue reading theme even if problem encountered with one file
   269              if(!resourceFile.exists() || !resourceFile.canRead()) {
   270                  log.warn("Couldn't read  theme [" + this.getName() + "] resource file ["+resourcePath+"]");
   271                  continue;
   272              }
   273              
   274              // add it to the theme
   275              setResource(resourcePath, new SharedThemeResourceFromDir(resourcePath, resourceFile));
   276          }
   277          
   278          // go through templates and read in contents to a ThemeTemplate
   279          ThemeTemplate theme_template = null;
   280          ThemeMetadataTemplate templateMetadata = null;
   281          Iterator templatesIter = themeMetadata.getTemplates().iterator();
   282          while (templatesIter.hasNext()) {
   283              templateMetadata = (ThemeMetadataTemplate) templatesIter.next();
   284              
   285              // construct File object from path
   286              File templateFile = new File(this.themeDir + File.separator + 
   287                      templateMetadata.getContentsFile());
   288              
   289              String contents = loadTemplateFile(templateFile);
   290              if(contents == null) {
   291                  // if we don't have any contents then skip this one
+  292                  throw new ThemeInitializationException("Couldn't load theme [" + this.getName() + "] template file ["+templateFile+"]");
   293              }
   294              
   295              // construct ThemeTemplate representing this file
   296              theme_template = new SharedThemeTemplate(
   297                      this,
   298                      themeMetadata.getId()+":"+templateMetadata.getName(),
   299                      templateMetadata.getAction(),
   300                      templateMetadata.getName(),
   301                      templateMetadata.getDescription(),
   302                      contents,
   303                      templateMetadata.getLink(),
   304                      new Date(templateFile.lastModified()),
   305                      templateMetadata.getTemplateLanguage(),
   306                      templateMetadata.isHidden(),
   307                      templateMetadata.isNavbar());
   308  
   309              // add it to the theme
   310              addTemplate(theme_template);
   311          }
   312      }
   313      
   314      
   315      /**
   316       * Load a single template file as a string, returns null if can't read file.
   317       */
   318      private String loadTemplateFile(File templateFile) {
   319          // Continue reading theme even if problem encountered with one file
                 /* 
    P/P           *  Method: String loadTemplateFile(File)
                  * 
                  *  Preconditions:
                  *    templateFile != null
                  *    (soft) log != null
                  *    (soft) init'ed(this.name)
                  * 
                  *  Presumptions:
                  *    java.io.File:length(...)@327 >= 0
                  * 
                  *  Postconditions:
                  *    return_value in Addr_Set{null,&new String(loadTemplateFile#5)}
                  *    new String(loadTemplateFile#5) num objects <= 1
                  * 
                  *  Test Vectors:
                  *    java.io.File:canRead(...)@320: {1}, {0}
                  *    java.io.File:exists(...)@320: {1}, {0}
                  */
   320          if(!templateFile.exists() && !templateFile.canRead()) {
   321              return null;
   322          }
   323          
   324          char[] chars = null;
   325          int length;
   326          try {
   327              chars = new char[(int) templateFile.length()];
   328              FileInputStream stream = new FileInputStream(templateFile);
   329              InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
   330              length = reader.read(chars);
   331          } catch (Exception noprob) {
   332              log.error("Exception reading theme [" + this.getName() + "] template file ["+templateFile+"]");
   333              if (log.isDebugEnabled())
   334                  log.debug(noprob);
   335              return null;
   336          }
   337          
   338          return new String(chars, 0, length);
   339      }
   340      
   341      
   342      /**
   343       * Set the value for a given template name.
   344       */
   345      private void addTemplate(ThemeTemplate template) {
                 /* 
    P/P           *  Method: void addTemplate(ThemeTemplate)
                  * 
                  *  Preconditions:
                  *    template != null
                  *    this.templatesByLink != null
                  *    this.templatesByName != null
                  *    (soft) this.templatesByAction != null
                  * 
                  *  Test Vectors:
                  *    java.lang.String:equals(...)@348: {1}, {0}
                  */
   346          this.templatesByName.put(template.getName(), template);
   347          this.templatesByLink.put(template.getLink(), template);
   348          if(!ThemeTemplate.ACTION_CUSTOM.equals(template.getAction())) {
   349              this.templatesByAction.put(template.getAction(), template);
   350          }
   351      }
   352      
   353      
   354      /**
   355       * Set the value for a given resource path.
   356       */
   357      private void setResource(String path, SharedThemeResourceFromDir resource) {
   358          // normalize to use web-style separators
                 /* 
    P/P           *  Method: void setResource(String, SharedThemeResourceFromDir)
                  * 
                  *  Preconditions:
                  *    this.resources != null
                  */
   359          String normalizedPath = StringUtils.replace(path, "\\", "/");
   360          this.resources.put(normalizedPath, resource);
   361      }
   362      
   363  }








SofCheck Inspector Build Version : 2.18479
SharedThemeFromDir.java 2009-Jan-02 14:25:48
SharedThemeFromDir.class 2009-Sep-04 03:12:31