CCM NG: Various things including a new version of the StaticThemeProvider (not finished yet)
git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5093 8810af33-2d31-482b-a856-94f89814c4dfpull/2/head
parent
e280aaf0a1
commit
d4d524def8
|
|
@ -196,6 +196,12 @@
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.reflections</groupId>
|
||||||
|
<artifactId>reflections</artifactId>
|
||||||
|
<version>0.9.11</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.primefaces</groupId>
|
<groupId>org.primefaces</groupId>
|
||||||
<artifactId>primefaces</artifactId>
|
<artifactId>primefaces</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,10 @@ public class SitesTab extends LayoutPanel {
|
||||||
final ActionLink addNewSite = new ActionLink(new GlobalizedMessage(
|
final ActionLink addNewSite = new ActionLink(new GlobalizedMessage(
|
||||||
"ui.admin.sites.add_new_site_link",
|
"ui.admin.sites.add_new_site_link",
|
||||||
ADMIN_BUNDLE));
|
ADMIN_BUNDLE));
|
||||||
|
addNewSite
|
||||||
|
.addActionListener(event -> {
|
||||||
|
showSiteForm(event.getPageState());
|
||||||
|
});
|
||||||
|
|
||||||
final BoxPanel right = new BoxPanel(BoxPanel.VERTICAL);
|
final BoxPanel right = new BoxPanel(BoxPanel.VERTICAL);
|
||||||
right.add(addNewSite);
|
right.add(addNewSite);
|
||||||
|
|
|
||||||
|
|
@ -18,82 +18,181 @@
|
||||||
*/
|
*/
|
||||||
package org.libreccm.theming;
|
package org.libreccm.theming;
|
||||||
|
|
||||||
import static org.libreccm.theming.ThemeConstants.*;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.libreccm.core.UnexpectedErrorException;
|
import org.libreccm.core.UnexpectedErrorException;
|
||||||
import org.libreccm.theming.manifest.ThemeManifest;
|
import org.libreccm.theming.manifest.ThemeManifest;
|
||||||
import org.libreccm.theming.manifest.ThemeManifestUtil;
|
import org.libreccm.theming.manifest.ThemeManifestUtil;
|
||||||
|
import org.reflections.Reflections;
|
||||||
|
import org.reflections.scanners.ResourcesScanner;
|
||||||
|
import org.reflections.util.ClasspathHelper;
|
||||||
|
import org.reflections.util.ConfigurationBuilder;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.URI;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.file.FileSystem;
|
import java.net.URL;
|
||||||
import java.nio.file.FileSystems;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Enumeration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A theme provider implementation which serves themes from the class path
|
|
||||||
* ({@code /themes)}. This implementation does not support changes to the
|
|
||||||
* theme(s) and files.
|
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
*/
|
*/
|
||||||
@RequestScoped
|
@RequestScoped
|
||||||
public class StaticThemeProvider implements ThemeProvider {
|
public class StaticThemeProvider implements ThemeProvider {
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManager
|
private static final long serialVersionUID = 7174370298224448067L;
|
||||||
.getLogger(StaticThemeProvider.class);
|
private static final Logger LOGGER = LogManager.getLogger(
|
||||||
|
StaticThemeProvider.class);
|
||||||
|
|
||||||
/**
|
|
||||||
* Path the the static themes.
|
|
||||||
*/
|
|
||||||
private static final String THEMES_DIR = "/themes";
|
private static final String THEMES_DIR = "/themes";
|
||||||
private static final long serialVersionUID = -8701021965452233811L;
|
private static final String THEME_MANIFEST_JSON = THEMES_DIR
|
||||||
|
+ "/%s/theme.json";
|
||||||
|
private static final String THEME_MANIFEST_XML = THEMES_DIR
|
||||||
|
+ "/%s/theme.xml";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ThemeFileInfoUtil themeFileInfoUtil;
|
private ThemeManifestUtil manifestUtil;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private ThemeManifestUtil themeManifests;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ThemeInfo> getThemes() {
|
public List<ThemeInfo> getThemes() {
|
||||||
|
|
||||||
LOGGER.debug("Retrieving info about all static themes...");
|
final Reflections reflections = new Reflections(
|
||||||
|
new ConfigurationBuilder()
|
||||||
|
.setUrls(ClasspathHelper.forPackage("themes"))
|
||||||
|
.setScanners(new ResourcesScanner()));
|
||||||
|
final Set<String> resources = reflections
|
||||||
|
.getResources(Pattern.compile("themes/.*/theme.json"));
|
||||||
|
LOGGER.debug("Found resources:");
|
||||||
|
for (final String resource : resources) {
|
||||||
|
LOGGER.debug("\t{}", resource);
|
||||||
|
}
|
||||||
|
|
||||||
try (final FileSystem jarFileSystem = FileSystems.newFileSystem(
|
final URL themesUrl = StaticThemeProvider.class.getResource(THEMES_DIR);
|
||||||
getJarUri(), Collections.emptyMap())) {
|
|
||||||
|
|
||||||
final Path themesPath = jarFileSystem.getPath(THEMES_DIR);
|
if (themesUrl == null) {
|
||||||
if (!Files.isDirectory(themesPath)) {
|
throw new UnexpectedErrorException(
|
||||||
LOGGER.warn(THEMES_DIR + " is not a directory. Returning "
|
"Static themes directory does not"
|
||||||
+ "empty list.");
|
+ "exist in class path. Something is wrong.");
|
||||||
return Collections.emptyList();
|
}
|
||||||
|
|
||||||
|
File directory;
|
||||||
|
try {
|
||||||
|
directory = new File(themesUrl.toURI());
|
||||||
|
} catch (URISyntaxException ex) {
|
||||||
|
throw new UnexpectedErrorException(ex);
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
directory = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<String> themeDirs = new ArrayList<>();
|
||||||
|
if (directory != null && directory.exists()) {
|
||||||
|
final String[] files = directory.list();
|
||||||
|
for (final String file : files) {
|
||||||
|
themeDirs.add(file);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
final String jarPath = themesUrl
|
||||||
|
.getFile()
|
||||||
|
.replaceFirst("[.]jar[!].*", ".jar")
|
||||||
|
.replaceFirst("file:", "");
|
||||||
|
|
||||||
return Files
|
final JarFile jarFile;
|
||||||
.list(themesPath)
|
try {
|
||||||
.filter(this::isTheme)
|
jarFile = new JarFile(jarPath);
|
||||||
.map(this::generateThemeInfo)
|
} catch (IOException ex) {
|
||||||
.collect(Collectors.toList());
|
throw new UnexpectedErrorException(ex);
|
||||||
|
}
|
||||||
|
final Enumeration<JarEntry> jarEntries = jarFile.entries();
|
||||||
|
while (jarEntries.hasMoreElements()) {
|
||||||
|
final JarEntry jarEntry = jarEntries.nextElement();
|
||||||
|
final String jarEntryName = jarEntry.getName();
|
||||||
|
|
||||||
|
if (jarEntryName.startsWith("themes")
|
||||||
|
&& jarEntryName.length() > "themes/".length()
|
||||||
|
&& jarEntryName.endsWith("/")) {
|
||||||
|
themeDirs.add(jarEntryName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return themeDirs
|
||||||
|
.stream()
|
||||||
|
.filter(dirPath -> isThemeDir(dirPath))
|
||||||
|
.map(dirPath -> loadThemeManifest(dirPath))
|
||||||
|
.map(manifest -> generateThemeInfo(manifest))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isThemeDir(final String dirPath) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(dirPath);
|
||||||
|
|
||||||
|
final URL manifestJsonUrl = StaticThemeProvider.class.getResource(
|
||||||
|
String.format(THEME_MANIFEST_JSON, dirPath));
|
||||||
|
final URL manifestXmlUrl = StaticThemeProvider.class.getResource(
|
||||||
|
String.format(THEME_MANIFEST_XML, dirPath));
|
||||||
|
|
||||||
|
return (manifestJsonUrl != null) || (manifestXmlUrl != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ThemeManifest loadThemeManifest(final String dirPath) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(dirPath);
|
||||||
|
|
||||||
|
final URL manifestJsonUrl = StaticThemeProvider.class.getResource(
|
||||||
|
String.format(THEME_MANIFEST_JSON, dirPath));
|
||||||
|
final URL manifestXmlUrl = StaticThemeProvider.class.getResource(
|
||||||
|
String.format(THEME_MANIFEST_XML, dirPath));
|
||||||
|
|
||||||
|
final URL manifestUrl;
|
||||||
|
if (manifestJsonUrl != null) {
|
||||||
|
manifestUrl = manifestJsonUrl;
|
||||||
|
} else if (manifestXmlUrl != null) {
|
||||||
|
manifestUrl = manifestXmlUrl;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(String
|
||||||
|
.format("Path \"%s\" does not point to a valid theme manifest.",
|
||||||
|
dirPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
final ThemeManifest themeManifest;
|
||||||
|
try (final InputStream inputStream = manifestUrl.openStream()) {
|
||||||
|
|
||||||
|
themeManifest = manifestUtil.loadManifest(inputStream,
|
||||||
|
manifestUrl.toString());
|
||||||
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new UnexpectedErrorException(ex);
|
throw new UnexpectedErrorException(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return themeManifest;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ThemeInfo generateThemeInfo(final ThemeManifest manifest) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(manifest);
|
||||||
|
|
||||||
|
final ThemeInfo info = new ThemeInfo();
|
||||||
|
info.setManifest(manifest);
|
||||||
|
info.setProvider(getClass());
|
||||||
|
info.setVersion(ThemeVersion.LIVE);
|
||||||
|
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -106,31 +205,13 @@ public class StaticThemeProvider implements ThemeProvider {
|
||||||
final ThemeVersion version) {
|
final ThemeVersion version) {
|
||||||
|
|
||||||
Objects.requireNonNull(theme);
|
Objects.requireNonNull(theme);
|
||||||
Objects.requireNonNull(version);
|
|
||||||
|
|
||||||
if (theme.matches("\\s*")) {
|
if (isThemeDir(theme)) {
|
||||||
throw new IllegalArgumentException(
|
return Optional.of(generateThemeInfo(loadThemeManifest(theme)));
|
||||||
"The name of the theme can't be empty.");
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGGER.debug("Trying to find static theme \"{}\"...",
|
|
||||||
theme);
|
|
||||||
|
|
||||||
try (final FileSystem jarFileSystem = FileSystems
|
|
||||||
.newFileSystem(getJarUri(), Collections.emptyMap())) {
|
|
||||||
|
|
||||||
final Path themePath = jarFileSystem
|
|
||||||
.getPath(String.format(THEMES_DIR + "/%s", theme));
|
|
||||||
|
|
||||||
if (isTheme(themePath)) {
|
|
||||||
return Optional.of(generateThemeInfo(themePath));
|
|
||||||
} else {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new UnexpectedErrorException(ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -138,30 +219,9 @@ public class StaticThemeProvider implements ThemeProvider {
|
||||||
final ThemeVersion version) {
|
final ThemeVersion version) {
|
||||||
|
|
||||||
Objects.requireNonNull(theme);
|
Objects.requireNonNull(theme);
|
||||||
Objects.requireNonNull(version);
|
|
||||||
|
|
||||||
if (theme.isEmpty() || theme.matches("\\s*")) {
|
return isThemeDir(theme);
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"The name of the theme can't be empty.");
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGER.debug("Determining if there is static theme \"{}\"...",
|
|
||||||
theme);
|
|
||||||
|
|
||||||
try (final FileSystem jarFileSystem = FileSystems
|
|
||||||
.newFileSystem(getJarUri(), Collections.emptyMap())) {
|
|
||||||
|
|
||||||
final Path themePath = jarFileSystem
|
|
||||||
.getPath(String.format(THEMES_DIR + "/%s", theme));
|
|
||||||
|
|
||||||
LOGGER.debug("Is there a static theme \"{}\": {}",
|
|
||||||
theme,
|
|
||||||
isTheme(themePath));
|
|
||||||
return isTheme(themePath);
|
|
||||||
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new UnexpectedErrorException(ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -169,128 +229,19 @@ public class StaticThemeProvider implements ThemeProvider {
|
||||||
final ThemeVersion version,
|
final ThemeVersion version,
|
||||||
final String path) {
|
final String path) {
|
||||||
|
|
||||||
Objects.requireNonNull(theme);
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
Objects.requireNonNull(version);
|
|
||||||
Objects.requireNonNull(path);
|
|
||||||
|
|
||||||
if (theme.isEmpty() || theme.matches("\\s*")) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"The name of the theme can't be empty.");
|
|
||||||
}
|
|
||||||
|
|
||||||
final String pathToDir;
|
|
||||||
if ("".equals(path)) {
|
|
||||||
pathToDir = "/";
|
|
||||||
} else {
|
|
||||||
pathToDir = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGER.debug("Listing all files in path \"{]\" of theme \"{}\"...",
|
|
||||||
path,
|
|
||||||
theme);
|
|
||||||
|
|
||||||
final List<ThemeFileInfo> infos;
|
|
||||||
try (final FileSystem jarFileSystem = FileSystems
|
|
||||||
.newFileSystem(getJarUri(), Collections.emptyMap())) {
|
|
||||||
|
|
||||||
final Path themePath = jarFileSystem
|
|
||||||
.getPath(String.format(THEMES_DIR + "/%s", theme));
|
|
||||||
|
|
||||||
if (!isTheme(themePath)) {
|
|
||||||
throw new IllegalArgumentException(String
|
|
||||||
.format("Theme \"%s\" does not exist.",
|
|
||||||
theme));
|
|
||||||
}
|
|
||||||
|
|
||||||
final Path dirPath = themePath.resolve(pathToDir);
|
|
||||||
if (Files.exists(dirPath)) {
|
|
||||||
|
|
||||||
if (Files.isDirectory(dirPath)) {
|
|
||||||
|
|
||||||
try (final Stream<Path> stream = Files.list(dirPath)) {
|
|
||||||
infos = stream
|
|
||||||
.map(themeFileInfoUtil::buildThemeInfo)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
infos = new ArrayList<>();
|
|
||||||
infos.add(themeFileInfoUtil.buildThemeInfo(dirPath));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(String
|
|
||||||
.format("No file/directory \"%s\" in theme \"%s\".",
|
|
||||||
path,
|
|
||||||
theme));
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new UnexpectedErrorException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGER.debug("Files in path \"{}\" of static theme \"{}\": {}",
|
|
||||||
pathToDir,
|
|
||||||
theme,
|
|
||||||
Objects.toString(infos));
|
|
||||||
return infos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<InputStream> getThemeFileAsStream(final String theme,
|
public Optional<InputStream> getThemeFileAsStream(String theme,
|
||||||
final ThemeVersion version,
|
ThemeVersion version,
|
||||||
final String path) {
|
String path) {
|
||||||
Objects.requireNonNull(theme);
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
Objects.requireNonNull(version);
|
|
||||||
Objects.requireNonNull(path);
|
|
||||||
|
|
||||||
if (theme.isEmpty() || theme.matches("\\s*")) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"The name of the theme can't be empty.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path.isEmpty() || path.matches("\\s*")) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"The name of the theme can't be empty.");
|
|
||||||
}
|
|
||||||
|
|
||||||
try (final FileSystem jarFileSystem = FileSystems
|
|
||||||
.newFileSystem(getJarUri(), Collections.emptyMap())) {
|
|
||||||
|
|
||||||
final Path themePath = jarFileSystem
|
|
||||||
.getPath(String.format(THEMES_DIR + "/%s", theme));
|
|
||||||
|
|
||||||
final Path filePath;
|
|
||||||
if (path.charAt(0) == '/') {
|
|
||||||
filePath = themePath.resolve(path.substring(1));
|
|
||||||
} else {
|
|
||||||
filePath = themePath.resolve(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Files.isRegularFile(filePath)) {
|
|
||||||
throw new IllegalArgumentException(String
|
|
||||||
.format("The provided path \"%s\" in theme \"%s\" points "
|
|
||||||
+ "not to a regular file.",
|
|
||||||
path,
|
|
||||||
theme));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Files.exists(filePath)) {
|
|
||||||
return Optional.of(Files.newInputStream(filePath));
|
|
||||||
} else {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new UnexpectedErrorException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OutputStream getOutputStreamForThemeFile(final String theme,
|
public OutputStream getOutputStreamForThemeFile(String theme, String path) {
|
||||||
final String path) {
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
|
||||||
throw new UnsupportedOperationException("Not supported by this"
|
|
||||||
+ " implemetentation");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -305,72 +256,7 @@ public class StaticThemeProvider implements ThemeProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void publishTheme(final String theme) {
|
public void publishTheme(final String theme) {
|
||||||
LOGGER.info("StaticThemeProvider#publishTheme(String) called, but "
|
//No op in this implementation.
|
||||||
+ "StaticThemeProvider does not support draft/live "
|
|
||||||
+ "themes.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private URI getJarUri() {
|
|
||||||
|
|
||||||
LOGGER.debug("Getting URI of JAR...");
|
|
||||||
|
|
||||||
final String themesUrl = getClass().getResource(THEMES_DIR).toString();
|
|
||||||
LOGGER.debug("Full URL of " + THEMES_DIR + " directory: {}", themesUrl);
|
|
||||||
|
|
||||||
final int index = themesUrl.indexOf('!');
|
|
||||||
final String pathToJar = themesUrl.substring(0, index);
|
|
||||||
|
|
||||||
final URI uri = URI.create(pathToJar);
|
|
||||||
LOGGER.debug("URI to JAR is \"%s\".", uri.toString());
|
|
||||||
return uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isTheme(final Path path) {
|
|
||||||
|
|
||||||
Objects.requireNonNull(path);
|
|
||||||
|
|
||||||
if (!Files.isDirectory(path)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Path manifestPathJson = path.resolve(THEME_MANIFEST_JSON);
|
|
||||||
final Path manifestPathXml = path.resolve(THEME_MANIFEST_XML);
|
|
||||||
|
|
||||||
return Files.exists(manifestPathJson) || Files.exists(manifestPathXml);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ThemeInfo generateThemeInfo(final Path path) {
|
|
||||||
|
|
||||||
Objects.requireNonNull(path);
|
|
||||||
|
|
||||||
if (!Files.exists(path)) {
|
|
||||||
throw new IllegalArgumentException(String
|
|
||||||
.format("The provided path \"%s\" does "
|
|
||||||
+ "not exist.",
|
|
||||||
path.toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
final Path manifestPathJson = path.resolve(THEME_MANIFEST_JSON);
|
|
||||||
final Path manifestPathXml = path.resolve(THEME_MANIFEST_XML);
|
|
||||||
|
|
||||||
final ThemeManifest manifest;
|
|
||||||
if (Files.exists(manifestPathJson)) {
|
|
||||||
manifest = themeManifests.loadManifest(manifestPathJson);
|
|
||||||
} else if (Files.exists(manifestPathXml)) {
|
|
||||||
manifest = themeManifests.loadManifest(manifestPathXml);
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(String
|
|
||||||
.format("The provided path \"%s\" does "
|
|
||||||
+ "contain a theme manifest file.",
|
|
||||||
path.toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
final ThemeInfo themeInfo = new ThemeInfo();
|
|
||||||
themeInfo.setVersion(ThemeVersion.LIVE);
|
|
||||||
themeInfo.setProvider(getClass());
|
|
||||||
themeInfo.setManifest(manifest);
|
|
||||||
|
|
||||||
return themeInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,376 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import static org.libreccm.theming.ThemeConstants.*;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.libreccm.core.UnexpectedErrorException;
|
||||||
|
import org.libreccm.theming.manifest.ThemeManifest;
|
||||||
|
import org.libreccm.theming.manifest.ThemeManifestUtil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.file.FileSystem;
|
||||||
|
import java.nio.file.FileSystems;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import javax.enterprise.context.RequestScoped;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A theme provider implementation which serves themes from the class path
|
||||||
|
* ({@code /themes)}. This implementation does not support changes to the
|
||||||
|
* theme(s) and files.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
@RequestScoped
|
||||||
|
public class StaticThemeProvider implements ThemeProvider {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LogManager
|
||||||
|
.getLogger(StaticThemeProvider.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path the the static themes.
|
||||||
|
*/
|
||||||
|
private static final String THEMES_DIR = "/themes";
|
||||||
|
private static final long serialVersionUID = -8701021965452233811L;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ThemeFileInfoUtil themeFileInfoUtil;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ThemeManifestUtil themeManifests;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ThemeInfo> getThemes() {
|
||||||
|
|
||||||
|
LOGGER.debug("Retrieving info about all static themes...");
|
||||||
|
|
||||||
|
try (final FileSystem jarFileSystem = FileSystems.newFileSystem(
|
||||||
|
getJarUri(), Collections.emptyMap())) {
|
||||||
|
|
||||||
|
final Path themesPath = jarFileSystem.getPath(THEMES_DIR);
|
||||||
|
if (!Files.isDirectory(themesPath)) {
|
||||||
|
LOGGER.warn(THEMES_DIR + " is not a directory. Returning "
|
||||||
|
+ "empty list.");
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Files
|
||||||
|
.list(themesPath)
|
||||||
|
.filter(this::isTheme)
|
||||||
|
.map(this::generateThemeInfo)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new UnexpectedErrorException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ThemeInfo> getLiveThemes() {
|
||||||
|
return getThemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<ThemeInfo> getThemeInfo(final String theme,
|
||||||
|
final ThemeVersion version) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(theme);
|
||||||
|
Objects.requireNonNull(version);
|
||||||
|
|
||||||
|
if (theme.matches("\\s*")) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"The name of the theme can't be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.debug("Trying to find static theme \"{}\"...",
|
||||||
|
theme);
|
||||||
|
|
||||||
|
try (final FileSystem jarFileSystem = FileSystems
|
||||||
|
.newFileSystem(getJarUri(), Collections.emptyMap())) {
|
||||||
|
|
||||||
|
final Path themePath = jarFileSystem
|
||||||
|
.getPath(String.format(THEMES_DIR + "/%s", theme));
|
||||||
|
|
||||||
|
if (isTheme(themePath)) {
|
||||||
|
return Optional.of(generateThemeInfo(themePath));
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new UnexpectedErrorException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean providesTheme(final String theme,
|
||||||
|
final ThemeVersion version) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(theme);
|
||||||
|
Objects.requireNonNull(version);
|
||||||
|
|
||||||
|
if (theme.isEmpty() || theme.matches("\\s*")) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"The name of the theme can't be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.debug("Determining if there is static theme \"{}\"...",
|
||||||
|
theme);
|
||||||
|
|
||||||
|
try (final FileSystem jarFileSystem = FileSystems
|
||||||
|
.newFileSystem(getJarUri(), Collections.emptyMap())) {
|
||||||
|
|
||||||
|
final Path themePath = jarFileSystem
|
||||||
|
.getPath(String.format(THEMES_DIR + "/%s", theme));
|
||||||
|
|
||||||
|
LOGGER.debug("Is there a static theme \"{}\": {}",
|
||||||
|
theme,
|
||||||
|
isTheme(themePath));
|
||||||
|
return isTheme(themePath);
|
||||||
|
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new UnexpectedErrorException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ThemeFileInfo> listThemeFiles(final String theme,
|
||||||
|
final ThemeVersion version,
|
||||||
|
final String path) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(theme);
|
||||||
|
Objects.requireNonNull(version);
|
||||||
|
Objects.requireNonNull(path);
|
||||||
|
|
||||||
|
if (theme.isEmpty() || theme.matches("\\s*")) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"The name of the theme can't be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
final String pathToDir;
|
||||||
|
if ("".equals(path)) {
|
||||||
|
pathToDir = "/";
|
||||||
|
} else {
|
||||||
|
pathToDir = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.debug("Listing all files in path \"{]\" of theme \"{}\"...",
|
||||||
|
path,
|
||||||
|
theme);
|
||||||
|
|
||||||
|
final List<ThemeFileInfo> infos;
|
||||||
|
try (final FileSystem jarFileSystem = FileSystems
|
||||||
|
.newFileSystem(getJarUri(), Collections.emptyMap())) {
|
||||||
|
|
||||||
|
final Path themePath = jarFileSystem
|
||||||
|
.getPath(String.format(THEMES_DIR + "/%s", theme));
|
||||||
|
|
||||||
|
if (!isTheme(themePath)) {
|
||||||
|
throw new IllegalArgumentException(String
|
||||||
|
.format("Theme \"%s\" does not exist.",
|
||||||
|
theme));
|
||||||
|
}
|
||||||
|
|
||||||
|
final Path dirPath = themePath.resolve(pathToDir);
|
||||||
|
if (Files.exists(dirPath)) {
|
||||||
|
|
||||||
|
if (Files.isDirectory(dirPath)) {
|
||||||
|
|
||||||
|
try (final Stream<Path> stream = Files.list(dirPath)) {
|
||||||
|
infos = stream
|
||||||
|
.map(themeFileInfoUtil::buildThemeInfo)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
infos = new ArrayList<>();
|
||||||
|
infos.add(themeFileInfoUtil.buildThemeInfo(dirPath));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(String
|
||||||
|
.format("No file/directory \"%s\" in theme \"%s\".",
|
||||||
|
path,
|
||||||
|
theme));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new UnexpectedErrorException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.debug("Files in path \"{}\" of static theme \"{}\": {}",
|
||||||
|
pathToDir,
|
||||||
|
theme,
|
||||||
|
Objects.toString(infos));
|
||||||
|
return infos;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<InputStream> getThemeFileAsStream(final String theme,
|
||||||
|
final ThemeVersion version,
|
||||||
|
final String path) {
|
||||||
|
Objects.requireNonNull(theme);
|
||||||
|
Objects.requireNonNull(version);
|
||||||
|
Objects.requireNonNull(path);
|
||||||
|
|
||||||
|
if (theme.isEmpty() || theme.matches("\\s*")) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"The name of the theme can't be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.isEmpty() || path.matches("\\s*")) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"The name of the theme can't be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try (final FileSystem jarFileSystem = FileSystems
|
||||||
|
.newFileSystem(getJarUri(), Collections.emptyMap())) {
|
||||||
|
|
||||||
|
final Path themePath = jarFileSystem
|
||||||
|
.getPath(String.format(THEMES_DIR + "/%s", theme));
|
||||||
|
|
||||||
|
final Path filePath;
|
||||||
|
if (path.charAt(0) == '/') {
|
||||||
|
filePath = themePath.resolve(path.substring(1));
|
||||||
|
} else {
|
||||||
|
filePath = themePath.resolve(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Files.isRegularFile(filePath)) {
|
||||||
|
throw new IllegalArgumentException(String
|
||||||
|
.format("The provided path \"%s\" in theme \"%s\" points "
|
||||||
|
+ "not to a regular file.",
|
||||||
|
path,
|
||||||
|
theme));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Files.exists(filePath)) {
|
||||||
|
return Optional.of(Files.newInputStream(filePath));
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new UnexpectedErrorException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OutputStream getOutputStreamForThemeFile(final String theme,
|
||||||
|
final String path) {
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException("Not supported by this"
|
||||||
|
+ " implemetentation");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsChanges() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsDraftThemes() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publishTheme(final String theme) {
|
||||||
|
LOGGER.info("StaticThemeProvider#publishTheme(String) called, but "
|
||||||
|
+ "StaticThemeProvider does not support draft/live "
|
||||||
|
+ "themes.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private URI getJarUri() {
|
||||||
|
|
||||||
|
LOGGER.debug("Getting URI of JAR...");
|
||||||
|
|
||||||
|
final String themesUrl = getClass().getResource(THEMES_DIR).toString();
|
||||||
|
LOGGER.debug("Full URL of " + THEMES_DIR + " directory: {}", themesUrl);
|
||||||
|
|
||||||
|
final int index = themesUrl.indexOf('!');
|
||||||
|
final String pathToJar = themesUrl.substring(0, index);
|
||||||
|
|
||||||
|
final URI uri = URI.create(pathToJar);
|
||||||
|
LOGGER.debug("URI to JAR is \"%s\".", uri.toString());
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTheme(final Path path) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(path);
|
||||||
|
|
||||||
|
if (!Files.isDirectory(path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Path manifestPathJson = path.resolve(THEME_MANIFEST_JSON);
|
||||||
|
final Path manifestPathXml = path.resolve(THEME_MANIFEST_XML);
|
||||||
|
|
||||||
|
return Files.exists(manifestPathJson) || Files.exists(manifestPathXml);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ThemeInfo generateThemeInfo(final Path path) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(path);
|
||||||
|
|
||||||
|
if (!Files.exists(path)) {
|
||||||
|
throw new IllegalArgumentException(String
|
||||||
|
.format("The provided path \"%s\" does "
|
||||||
|
+ "not exist.",
|
||||||
|
path.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
final Path manifestPathJson = path.resolve(THEME_MANIFEST_JSON);
|
||||||
|
final Path manifestPathXml = path.resolve(THEME_MANIFEST_XML);
|
||||||
|
|
||||||
|
final ThemeManifest manifest;
|
||||||
|
if (Files.exists(manifestPathJson)) {
|
||||||
|
manifest = themeManifests.loadManifest(manifestPathJson);
|
||||||
|
} else if (Files.exists(manifestPathXml)) {
|
||||||
|
manifest = themeManifests.loadManifest(manifestPathXml);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(String
|
||||||
|
.format("The provided path \"%s\" does "
|
||||||
|
+ "contain a theme manifest file.",
|
||||||
|
path.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
final ThemeInfo themeInfo = new ThemeInfo();
|
||||||
|
themeInfo.setVersion(ThemeVersion.LIVE);
|
||||||
|
themeInfo.setProvider(getClass());
|
||||||
|
themeInfo.setManifest(manifest);
|
||||||
|
|
||||||
|
return themeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -28,7 +28,11 @@ import org.libreccm.core.UnexpectedErrorException;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
@ -50,11 +54,12 @@ public class ThemeManifestUtil implements Serializable {
|
||||||
* Reads the manifest file at {@code path}.
|
* Reads the manifest file at {@code path}.
|
||||||
*
|
*
|
||||||
* @param path The path of the manifest file.
|
* @param path The path of the manifest file.
|
||||||
|
*
|
||||||
* @return The parsed manifest file.
|
* @return The parsed manifest file.
|
||||||
*/
|
*/
|
||||||
public ThemeManifest loadManifest(final Path path) {
|
public ThemeManifest loadManifest(final Path path) {
|
||||||
|
|
||||||
final String pathStr = path.toString().toLowerCase(Locale.ROOT);
|
// final String pathStr = path.toString().toLowerCase(Locale.ROOT);
|
||||||
|
|
||||||
final BufferedReader reader;
|
final BufferedReader reader;
|
||||||
try {
|
try {
|
||||||
|
|
@ -63,6 +68,72 @@ public class ThemeManifestUtil implements Serializable {
|
||||||
throw new UnexpectedErrorException(ex);
|
throw new UnexpectedErrorException(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return parseManifest(reader, path.toString());
|
||||||
|
|
||||||
|
// final ObjectMapper mapper;
|
||||||
|
// if (pathStr.endsWith(THEME_MANIFEST_JSON)) {
|
||||||
|
// mapper = new ObjectMapper();
|
||||||
|
// } else if (pathStr.endsWith(THEME_MANIFEST_XML)) {
|
||||||
|
// final JacksonXmlModule xmlModule = new JacksonXmlModule();
|
||||||
|
// mapper = new XmlMapper(xmlModule);
|
||||||
|
// } else {
|
||||||
|
// throw new IllegalArgumentException(String
|
||||||
|
// .format("The provided path \"%s\" does not point to a theme "
|
||||||
|
// + "manifest file.",
|
||||||
|
// path.toString()));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// mapper.registerModule(new JaxbAnnotationModule());
|
||||||
|
//
|
||||||
|
// final ThemeManifest manifest;
|
||||||
|
// try {
|
||||||
|
// manifest = mapper.readValue(reader, ThemeManifest.class);
|
||||||
|
// } catch (IOException ex) {
|
||||||
|
// throw new UnexpectedErrorException(ex);
|
||||||
|
// }
|
||||||
|
// return manifest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThemeManifest loadManifest(final InputStream inputStream,
|
||||||
|
final String fileName) {
|
||||||
|
|
||||||
|
final InputStreamReader reader;
|
||||||
|
try {
|
||||||
|
reader = new InputStreamReader(inputStream, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException ex) {
|
||||||
|
throw new UnexpectedErrorException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseManifest(reader, fileName);
|
||||||
|
|
||||||
|
// final ObjectMapper mapper;
|
||||||
|
// if (fileName.endsWith(THEME_MANIFEST_JSON)) {
|
||||||
|
// mapper = new ObjectMapper();
|
||||||
|
// } else if (fileName.endsWith(THEME_MANIFEST_XML)) {
|
||||||
|
// final JacksonXmlModule xmlModule = new JacksonXmlModule();
|
||||||
|
// mapper = new XmlMapper(xmlModule);
|
||||||
|
// } else {
|
||||||
|
// throw new IllegalArgumentException(String
|
||||||
|
// .format("The provided path \"%s\" does not point to a theme "
|
||||||
|
// + "manifest file.",
|
||||||
|
// fileName));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// mapper.registerModule(new JaxbAnnotationModule());
|
||||||
|
//
|
||||||
|
// final ThemeManifest manifest;
|
||||||
|
// try {
|
||||||
|
// manifest = mapper.readValue(reader, ThemeManifest.class);
|
||||||
|
// } catch (IOException ex) {
|
||||||
|
// throw new UnexpectedErrorException(ex);
|
||||||
|
// }
|
||||||
|
// return manifest;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ThemeManifest parseManifest(final Reader reader, final String path) {
|
||||||
|
|
||||||
|
final String pathStr = path.toLowerCase(Locale.ROOT);
|
||||||
|
|
||||||
final ObjectMapper mapper;
|
final ObjectMapper mapper;
|
||||||
if (pathStr.endsWith(THEME_MANIFEST_JSON)) {
|
if (pathStr.endsWith(THEME_MANIFEST_JSON)) {
|
||||||
mapper = new ObjectMapper();
|
mapper = new ObjectMapper();
|
||||||
|
|
@ -73,7 +144,7 @@ public class ThemeManifestUtil implements Serializable {
|
||||||
throw new IllegalArgumentException(String
|
throw new IllegalArgumentException(String
|
||||||
.format("The provided path \"%s\" does not point to a theme "
|
.format("The provided path \"%s\" does not point to a theme "
|
||||||
+ "manifest file.",
|
+ "manifest file.",
|
||||||
path.toString()));
|
path));
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper.registerModule(new JaxbAnnotationModule());
|
mapper.registerModule(new JaxbAnnotationModule());
|
||||||
|
|
|
||||||
|
|
@ -616,3 +616,12 @@ ui.user.roles.remove=Remove
|
||||||
ui.role.parties.remove=Remove
|
ui.role.parties.remove=Remove
|
||||||
ui.admin.role_edit.description.label=Description
|
ui.admin.role_edit.description.label=Description
|
||||||
ui.admin.tab.sites.title=Sites
|
ui.admin.tab.sites.title=Sites
|
||||||
|
ui.admin.sites.add_new_site_link=Create new Site
|
||||||
|
ui.admin.sites.no_sites=No Sites available
|
||||||
|
ui.admin.sites.table.columns.domain.header=Domain
|
||||||
|
ui.admin.sites.table.columns.default_site.header=Default Site?
|
||||||
|
ui.admin.sites.table.columns.default_theme.header=Default theme
|
||||||
|
ui.admin.sites.table.columns.applications.header=Applications
|
||||||
|
ui.admin.sites.table.columns.delete.header=Delete
|
||||||
|
ui.admin.sites.delete.confirm=Are you sure to delete this site?
|
||||||
|
ui.admin.sites.table.columns.remove.label=Delete
|
||||||
|
|
|
||||||
|
|
@ -620,3 +620,12 @@ ui.user.roles.remove=Entfernen
|
||||||
ui.role.parties.remove=Entfernen
|
ui.role.parties.remove=Entfernen
|
||||||
ui.admin.role_edit.description.label=Beschreibung
|
ui.admin.role_edit.description.label=Beschreibung
|
||||||
ui.admin.tab.sites.title=Sites
|
ui.admin.tab.sites.title=Sites
|
||||||
|
ui.admin.sites.add_new_site_link=Neue Site anlegen
|
||||||
|
ui.admin.sites.no_sites=Keine Sites vorhanden
|
||||||
|
ui.admin.sites.table.columns.domain.header=Domain
|
||||||
|
ui.admin.sites.table.columns.default_site.header=Standard Site?
|
||||||
|
ui.admin.sites.table.columns.default_theme.header=Standard Theme
|
||||||
|
ui.admin.sites.table.columns.applications.header=Applications
|
||||||
|
ui.admin.sites.table.columns.delete.header=L\u00f6schen
|
||||||
|
ui.admin.sites.delete.confirm=Sind Sie sicher, dass Sie diese Site l\u00f6schen wollen?
|
||||||
|
ui.admin.sites.table.columns.remove.label=L\u00f6schen
|
||||||
|
|
|
||||||
|
|
@ -613,3 +613,12 @@ ui.user.roles.remove=Remove
|
||||||
ui.role.parties.remove=Remove
|
ui.role.parties.remove=Remove
|
||||||
ui.admin.role_edit.description.label=Description
|
ui.admin.role_edit.description.label=Description
|
||||||
ui.admin.tab.sites.title=Sites
|
ui.admin.tab.sites.title=Sites
|
||||||
|
ui.admin.sites.add_new_site_link=Create new Site
|
||||||
|
ui.admin.sites.no_sites=No Sites available
|
||||||
|
ui.admin.sites.table.columns.domain.header=Domain
|
||||||
|
ui.admin.sites.table.columns.default_site.header=Default Site?
|
||||||
|
ui.admin.sites.table.columns.default_theme.header=Default theme
|
||||||
|
ui.admin.sites.table.columns.applications.header=Applications
|
||||||
|
ui.admin.sites.table.columns.delete.header=Delete
|
||||||
|
ui.admin.sites.delete.confirm=Are you sure to delete this site?
|
||||||
|
ui.admin.sites.table.columns.remove.label=Delete
|
||||||
|
|
|
||||||
|
|
@ -604,3 +604,12 @@ ui.user.roles.remove=Remove
|
||||||
ui.role.parties.remove=Remove
|
ui.role.parties.remove=Remove
|
||||||
ui.admin.role_edit.description.label=Description
|
ui.admin.role_edit.description.label=Description
|
||||||
ui.admin.tab.sites.title=Sites
|
ui.admin.tab.sites.title=Sites
|
||||||
|
ui.admin.sites.add_new_site_link=Create new Site
|
||||||
|
ui.admin.sites.no_sites=No Sites available
|
||||||
|
ui.admin.sites.table.columns.domain.header=Domain
|
||||||
|
ui.admin.sites.table.columns.default_site.header=Default Site?
|
||||||
|
ui.admin.sites.table.columns.default_theme.header=Default theme
|
||||||
|
ui.admin.sites.table.columns.applications.header=Applications
|
||||||
|
ui.admin.sites.table.columns.delete.header=Delete
|
||||||
|
ui.admin.sites.delete.confirm=Are you sure to delete this site?
|
||||||
|
ui.admin.sites.table.columns.remove.label=Delete
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue