| /* |
| * 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.weblogger.business.themes; |
| |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.roller.weblogger.pojos.TemplateRendition.RenditionType; |
| import org.apache.roller.weblogger.pojos.TemplateRendition.TemplateLanguage; |
| import org.apache.roller.weblogger.pojos.ThemeTemplate.ComponentType; |
| import org.jdom2.Document; |
| import org.jdom2.Element; |
| import org.jdom2.JDOMException; |
| import org.jdom2.input.SAXBuilder; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.List; |
| |
| |
| /** |
| * The parser for theme xml descriptors. |
| * |
| * This class unmarshalls a theme descriptor into a set of objects. |
| */ |
| public class ThemeMetadataParser { |
| |
| /** |
| * Unmarshall the given input stream into our defined |
| * set of Java objects. |
| **/ |
| public ThemeMetadata unmarshall(InputStream instream) |
| throws ThemeParsingException, IOException, JDOMException { |
| |
| if(instream == null) { |
| throw new IOException("InputStream is null!"); |
| } |
| |
| ThemeMetadata theme = new ThemeMetadata(); |
| |
| SAXBuilder builder = new SAXBuilder(); |
| Document doc = builder.build(instream); |
| |
| // start at root and get theme id, name, description and author |
| Element root = doc.getRootElement(); |
| theme.setId(root.getChildText("id")); |
| theme.setName(root.getChildText("name")); |
| theme.setDescription(root.getChildText("description")); |
| theme.setAuthor(root.getChildText("author")); |
| |
| // dual-theme (standard & mobile) or one-theme-fits-all? |
| theme.setDualTheme("true".equalsIgnoreCase(root.getChildText("dualTheme"))); |
| |
| // if either id or name is null then throw a parsing exception |
| if(StringUtils.isEmpty(theme.getId()) || StringUtils.isEmpty(theme.getName())) { |
| throw new ThemeParsingException("'id' and 'name' are required theme elements"); |
| } |
| |
| // now grab the preview image path |
| Element previewImage = root.getChild("preview-image"); |
| if (previewImage != null) { |
| theme.setPreviewImage(previewImage.getAttributeValue("path")); |
| } else { |
| throw new ThemeParsingException("No preview image specified"); |
| } |
| |
| // grab the stylesheet if it exists |
| Element stylesheet = root.getChild("stylesheet"); |
| if (stylesheet != null) { |
| theme.setStylesheet(elementToStylesheet(stylesheet)); |
| |
| } |
| |
| // now grab the static resources |
| List<Element> resources = root.getChildren("resource"); |
| for (Element resource : resources) { |
| theme.addResource(resource.getAttributeValue("path")); |
| } |
| |
| // now grab the templates |
| boolean weblogActionTemplate = false; |
| List<Element> templates = root.getChildren("template"); |
| for (Element template : templates) { |
| |
| ThemeMetadataTemplate tmpl = elementToTemplateMetadata(template); |
| theme.addTemplate(tmpl); |
| |
| if(ComponentType.WEBLOG.equals(tmpl.getAction())) { |
| weblogActionTemplate = true; |
| } |
| } |
| |
| // make sure all required elements are present and values are valid |
| // check that there is a template with action='weblog' |
| if(!weblogActionTemplate) { |
| throw new ThemeParsingException("did not find a template of action = 'weblog'"); |
| } |
| |
| return theme; |
| } |
| |
| |
| private ThemeMetadataTemplate elementToTemplateMetadata(Element element) |
| throws ThemeParsingException { |
| |
| ThemeMetadataTemplate template = new ThemeMetadataTemplate(); |
| |
| template.setName(element.getChildText("name")); |
| template.setDescription(element.getChildText("description")); |
| template.setLink(element.getChildText("link")); |
| template.setContentType(element.getChildText("contentType")); |
| String actionString = element.getAttributeValue("action"); |
| if (StringUtils.isEmpty(actionString)) { |
| throw new ThemeParsingException("Template must contain an 'action' element"); |
| } else { |
| try { |
| template.setAction(ComponentType.valueOf(actionString.toUpperCase())); |
| } catch (IllegalArgumentException e) { |
| throw new ThemeParsingException("Unknown template action value '" + actionString + "'"); |
| } |
| } |
| |
| //parsing template code segment |
| List<Element> renditionList = element.getChildren("rendition"); |
| |
| for (Element renditionElement : renditionList) { |
| ThemeMetadataTemplateRendition rendition = new ThemeMetadataTemplateRendition(); |
| String renditionValue = renditionElement.getAttributeValue("type"); |
| if (renditionValue != null) { |
| try { |
| rendition.setType(RenditionType.valueOf(renditionValue.toUpperCase())); |
| } catch (IllegalArgumentException e) { |
| throw new ThemeParsingException("Invalid rendition type " + renditionValue + " found."); |
| } |
| } else { |
| // default to standard if type not provided, as most templates are single-rendition |
| rendition.setType(RenditionType.STANDARD); |
| } |
| String templateString = renditionElement.getChildText("templateLanguage"); |
| if (StringUtils.isEmpty(templateString)) { |
| throw new ThemeParsingException("rendition must contain a 'templateLanguage' element"); |
| } else { |
| try { |
| rendition.setTemplateLang(TemplateLanguage.valueOf(templateString.toUpperCase())); |
| } catch (IllegalArgumentException e) { |
| throw new ThemeParsingException("Unknown templateLanguage value '" + templateString + "'"); |
| } |
| } |
| rendition.setContentsFile(renditionElement.getChildText("contentsFile")); |
| if (StringUtils.isEmpty(rendition.getContentsFile())) { |
| throw new ThemeParsingException("Rendition must contain a 'contentsFile' element"); |
| } |
| template.addTemplateRendition(rendition); |
| } |
| |
| String navbar = element.getChildText("navbar"); |
| if ("true".equalsIgnoreCase(navbar)) { |
| template.setNavbar(true); |
| } |
| |
| String hidden = element.getChildText("hidden"); |
| if ("true".equalsIgnoreCase(hidden)) { |
| template.setHidden(true); |
| } |
| |
| // validate template |
| if (StringUtils.isEmpty(template.getName())) { |
| throw new ThemeParsingException("templates must contain a 'name' element"); |
| } |
| |
| return template; |
| } |
| |
| |
| private ThemeMetadataTemplate elementToStylesheet(Element element) |
| throws ThemeParsingException { |
| |
| ThemeMetadataTemplate template = new ThemeMetadataTemplate(); |
| |
| template.setName(element.getChildText("name")); |
| template.setDescription(element.getChildText("description")); |
| template.setLink(element.getChildText("link")); |
| template.setContentType(element.getChildText("contentType")); |
| template.setAction(ComponentType.STYLESHEET); |
| |
| // parsing rendition segment |
| List<Element> renditionList = element.getChildren("rendition"); |
| for (Element renditionElement : renditionList) { |
| ThemeMetadataTemplateRendition rendition = new ThemeMetadataTemplateRendition(); |
| String renditionValue = renditionElement.getAttributeValue("type"); |
| if (renditionValue != null) { |
| try { |
| rendition.setType(RenditionType.valueOf(renditionValue.toUpperCase())); |
| } catch (IllegalArgumentException e) { |
| throw new ThemeParsingException("Invalid rendition type " + renditionValue + " found."); |
| } |
| } else { |
| // default to standard if type not provided, as most templates are single-rendition |
| rendition.setType(RenditionType.STANDARD); |
| } |
| String templateString = renditionElement.getChildText("templateLanguage"); |
| if (StringUtils.isEmpty(templateString)) { |
| throw new ThemeParsingException("rendition must contain a 'templateLanguage' element"); |
| } else { |
| try { |
| rendition.setTemplateLang(TemplateLanguage.valueOf(templateString.toUpperCase())); |
| } catch (IllegalArgumentException e) { |
| throw new ThemeParsingException("Unknown templateLanguage value '" + templateString + "'"); |
| } |
| } |
| rendition.setContentsFile(renditionElement.getChildText("contentsFile")); |
| if (StringUtils.isEmpty(rendition.getContentsFile())) { |
| throw new ThemeParsingException("stylesheet must contain a 'contentsFile' element"); |
| } |
| template.addTemplateRendition(rendition); |
| } |
| |
| // validate template |
| if(StringUtils.isEmpty(template.getName())) { |
| throw new ThemeParsingException("stylesheet must contain a 'name' element"); |
| } |
| if(StringUtils.isEmpty(template.getLink())) { |
| throw new ThemeParsingException("stylesheet must contain a 'link' element"); |
| } |
| |
| return template; |
| } |
| |
| } |