CCM NG: ThemeProcessor for XSLT based themes
git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5081 8810af33-2d31-482b-a856-94f89814c4df
Former-commit-id: 66c1c8baeb
pull/2/head
parent
497458059e
commit
7646284f47
|
|
@ -62,6 +62,7 @@ public class StaticThemeProvider implements ThemeProvider {
|
|||
* Path the the static themes.
|
||||
*/
|
||||
private static final String THEMES_DIR = "/themes";
|
||||
private static final long serialVersionUID = -8701021965452233811L;
|
||||
|
||||
@Inject
|
||||
private ThemeFileInfoUtil themeFileInfoUtil;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ package org.libreccm.theming;
|
|||
*/
|
||||
public final class ThemeConstants {
|
||||
|
||||
public static final String PAGE_PARAMETER_TEMPLATE = "template";
|
||||
|
||||
public final static String THEME_MANIFEST_JSON = "theme.json";
|
||||
public final static String THEME_MANIFEST_XML = "theme.xml";
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
package org.libreccm.theming;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
|
|
@ -25,7 +26,9 @@ import java.util.Objects;
|
|||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public class ThemeFileInfo {
|
||||
public class ThemeFileInfo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2880986115955856570L;
|
||||
|
||||
/**
|
||||
* The name of the file.
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ package org.libreccm.theming;
|
|||
import org.libreccm.core.UnexpectedErrorException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
|
|
@ -33,7 +34,9 @@ import javax.enterprise.context.RequestScoped;
|
|||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@RequestScoped
|
||||
public class ThemeFileInfoUtil {
|
||||
public class ThemeFileInfoUtil implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -3382896567742774318L;
|
||||
|
||||
/**
|
||||
* Build a {@link ThemeFileInfo} object for a file. Before calling this
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ package org.libreccm.theming;
|
|||
|
||||
import org.libreccm.theming.manifest.ThemeManifest;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
|
|
@ -27,7 +28,9 @@ import java.util.Objects;
|
|||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public class ThemeInfo {
|
||||
public class ThemeInfo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -518244930947022256L;
|
||||
|
||||
/**
|
||||
* The manifest of the theme.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
package org.libreccm.theming;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
|
|
@ -32,7 +33,7 @@ import javax.enterprise.context.RequestScoped;
|
|||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public interface ThemeProcessor {
|
||||
public interface ThemeProcessor extends Serializable {
|
||||
|
||||
/**
|
||||
* Process the provided {@link PageModel} {@code page} and convert into HTML
|
||||
|
|
@ -41,7 +42,8 @@ public interface ThemeProcessor {
|
|||
*
|
||||
* @param page The page to convert the HTML.
|
||||
* @param theme The theme to use.
|
||||
* @param themeProvider The {@link ThemeProvider} which provides the the theme.
|
||||
* @param themeProvider The {@link ThemeProvider} which provides the the
|
||||
* theme.
|
||||
*
|
||||
* @return The HTML for the provided {@code page}.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ package org.libreccm.theming;
|
|||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
|
|
@ -30,7 +31,7 @@ import java.util.Optional;
|
|||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public interface ThemeProvider {
|
||||
public interface ThemeProvider extends Serializable {
|
||||
|
||||
/**
|
||||
* Provides a list of all themes provided by this theme provider. The list
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import org.apache.logging.log4j.Logger;
|
|||
import org.libreccm.core.UnexpectedErrorException;
|
||||
import org.libreccm.pagemodel.PageModel;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -40,7 +41,9 @@ import javax.inject.Inject;
|
|||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@RequestScoped
|
||||
public class Themes {
|
||||
public class Themes implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 6861457919635241221L;
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(Themes.class);
|
||||
|
||||
|
|
@ -139,5 +142,4 @@ public class Themes {
|
|||
return processor.process(page, theme, provider);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ import javax.xml.bind.annotation.XmlRootElement;
|
|||
|
||||
import static org.libreccm.theming.ThemeConstants.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Each theme contains a Manifest (either in XML or JSON format) which provides
|
||||
* informations about the theme.
|
||||
|
|
@ -41,7 +43,9 @@ import static org.libreccm.theming.ThemeConstants.*;
|
|||
*/
|
||||
@XmlRootElement(name = "theme", namespace = THEMES_XML_NS)
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class ThemeManifest {
|
||||
public class ThemeManifest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 699497658459398231L;
|
||||
|
||||
/**
|
||||
* The name of the theme. Usually the same as the name of directory which
|
||||
|
|
@ -75,6 +79,12 @@ public class ThemeManifest {
|
|||
@XmlElement(name = "template", namespace = THEMES_XML_NS)
|
||||
private List<ThemeTemplate> templates;
|
||||
|
||||
/**
|
||||
* Path of the default template.
|
||||
*/
|
||||
@XmlElement(name = "default-template", namespace = THEMES_XML_NS)
|
||||
private String defaultTemplate;
|
||||
|
||||
public ThemeManifest() {
|
||||
templates = new ArrayList<>();
|
||||
}
|
||||
|
|
@ -94,6 +104,7 @@ public class ThemeManifest {
|
|||
public void setType(final String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public LocalizedString getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
|
@ -126,6 +137,14 @@ public class ThemeManifest {
|
|||
templates.remove(template);
|
||||
}
|
||||
|
||||
public String getDefaultTemplate() {
|
||||
return defaultTemplate;
|
||||
}
|
||||
|
||||
public void setDefaultTemplate(final String defaultTemplate) {
|
||||
this.defaultTemplate = defaultTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
|
|
@ -134,6 +153,7 @@ public class ThemeManifest {
|
|||
hash = 83 * hash + Objects.hashCode(title);
|
||||
hash = 83 * hash + Objects.hashCode(description);
|
||||
hash = 83 * hash + Objects.hashCode(templates);
|
||||
hash = 83 * hash + Objects.hashCode(defaultTemplate);
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
|
@ -164,7 +184,10 @@ public class ThemeManifest {
|
|||
if (!Objects.equals(description, other.getDescription())) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(templates, other.getTemplates());
|
||||
if (!Objects.equals(templates, other.getTemplates())) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(defaultTemplate, other.getDefaultTemplate());
|
||||
}
|
||||
|
||||
public boolean canEqual(final Object obj) {
|
||||
|
|
@ -182,13 +205,15 @@ public class ThemeManifest {
|
|||
+ "name = \"%s\", "
|
||||
+ "title = \"%s\", "
|
||||
+ "description = \"%s\", "
|
||||
+ "templates = %s%s"
|
||||
+ "templates = %s, "
|
||||
+ "defaultTemplate%s"
|
||||
+ " }",
|
||||
super.toString(),
|
||||
name,
|
||||
Objects.toString(title),
|
||||
Objects.toString(description),
|
||||
Objects.toString(templates),
|
||||
defaultTemplate,
|
||||
data);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright (C) 2017 LibreCCM Foundation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
package org.libreccm.theming.xslt;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule;
|
||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
import org.libreccm.core.UnexpectedErrorException;
|
||||
import org.libreccm.theming.ThemeInfo;
|
||||
import org.libreccm.theming.ThemeProcessor;
|
||||
import org.libreccm.theming.ThemeProvider;
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import static org.libreccm.theming.ThemeConstants.*;
|
||||
|
||||
import org.libreccm.theming.manifest.ThemeTemplate;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
/**
|
||||
* A {@link ThemeProcessor} implementation for XSLT based themes.
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@RequestScoped
|
||||
public class XsltThemeProcessor implements ThemeProcessor {
|
||||
|
||||
private static final long serialVersionUID = -3883625727845105417L;
|
||||
|
||||
@Override
|
||||
public String process(final Map<String, Object> page,
|
||||
final ThemeInfo theme,
|
||||
final ThemeProvider themeProvider) {
|
||||
|
||||
//Convert page to XML
|
||||
final JacksonXmlModule xmlModule = new JacksonXmlModule();
|
||||
final ObjectMapper mapper = new XmlMapper(xmlModule);
|
||||
|
||||
final String pageAsXml;
|
||||
try {
|
||||
pageAsXml = mapper.writeValueAsString(page);
|
||||
} catch (JsonProcessingException ex) {
|
||||
throw new UnexpectedErrorException(ex);
|
||||
}
|
||||
|
||||
final DocumentBuilderFactory documentBuilderFactory
|
||||
= DocumentBuilderFactory.newInstance();
|
||||
final DocumentBuilder documentBuilder;
|
||||
try {
|
||||
documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
||||
} catch (ParserConfigurationException ex) {
|
||||
throw new UnexpectedErrorException(ex);
|
||||
}
|
||||
|
||||
final Document document;
|
||||
try {
|
||||
document = documentBuilder.parse(pageAsXml);
|
||||
} catch (SAXException | IOException ex) {
|
||||
throw new UnexpectedErrorException(ex);
|
||||
}
|
||||
|
||||
final String pathToTemplate;
|
||||
if (page.containsKey(PAGE_PARAMETER_TEMPLATE)) {
|
||||
|
||||
final String templateName = (String) page
|
||||
.get(PAGE_PARAMETER_TEMPLATE);
|
||||
|
||||
final Optional<ThemeTemplate> template = theme
|
||||
.getManifest()
|
||||
.getTemplates()
|
||||
.stream()
|
||||
.filter(current -> current.getName().equals(templateName))
|
||||
.findAny();
|
||||
|
||||
if (template.isPresent()) {
|
||||
pathToTemplate = template.get().getPath();
|
||||
} else {
|
||||
throw new UnexpectedErrorException(String
|
||||
.format("Theme \"%s\" does provide template \"%s\".",
|
||||
theme.getName(),
|
||||
templateName));
|
||||
}
|
||||
} else {
|
||||
pathToTemplate = theme.getManifest().getDefaultTemplate();
|
||||
}
|
||||
|
||||
final InputStream xslFileInputStream = themeProvider
|
||||
.getThemeFileAsStream(theme.getName(),
|
||||
theme.getVersion(),
|
||||
pathToTemplate)
|
||||
.orElseThrow(() -> new UnexpectedErrorException(String
|
||||
.format("Failed to open XSL file \"%s\" from theme \"%s\" for "
|
||||
+ "reading.",
|
||||
pathToTemplate,
|
||||
theme.getName())));
|
||||
|
||||
final Reader reader;
|
||||
try {
|
||||
reader = new InputStreamReader(xslFileInputStream, "UTF-8");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
throw new UnexpectedErrorException(ex);
|
||||
}
|
||||
|
||||
final StreamSource xslFileStreamSource = new StreamSource(reader);
|
||||
final TransformerFactory transformerFactory = TransformerFactory
|
||||
.newInstance();
|
||||
final Transformer transformer;
|
||||
try {
|
||||
transformer = transformerFactory.newTransformer(xslFileStreamSource);
|
||||
} catch (TransformerConfigurationException ex) {
|
||||
throw new UnexpectedErrorException(ex);
|
||||
}
|
||||
|
||||
final StringWriter resultWriter = new StringWriter();
|
||||
final Result result = new StreamResult(resultWriter);
|
||||
try {
|
||||
transformer.transform(new DOMSource(document), result);
|
||||
} catch (TransformerException ex) {
|
||||
throw new UnexpectedErrorException(ex);
|
||||
}
|
||||
|
||||
return resultWriter.toString();
|
||||
}
|
||||
|
||||
}
|
||||
10
pom.xml
10
pom.xml
|
|
@ -115,7 +115,7 @@
|
|||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.7.0</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
|
|
@ -255,7 +255,7 @@
|
|||
<plugin>
|
||||
<groupId>com.vaadin</groupId>
|
||||
<artifactId>vaadin-maven-plugin</artifactId>
|
||||
<version>8.1.3</version>
|
||||
<version>8.1.5</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
|
@ -405,7 +405,7 @@
|
|||
<dependency>
|
||||
<groupId>com.vaadin</groupId>
|
||||
<artifactId>vaadin-bom</artifactId>
|
||||
<version>8.1.3</version>
|
||||
<version>8.1.5</version>
|
||||
<scope>import</scope>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
|
|
@ -442,7 +442,7 @@
|
|||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-bom</artifactId>
|
||||
<version>2.8.2</version>
|
||||
<version>2.9.1</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
|
@ -520,7 +520,7 @@
|
|||
<dependency>
|
||||
<groupId>net.sf.saxon</groupId>
|
||||
<artifactId>Saxon-HE</artifactId>
|
||||
<version>9.8.0-3</version>
|
||||
<version>9.8.0-5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
|
|
|||
Loading…
Reference in New Issue