CcM NG: First part for ThemeManager UI
git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5691 8810af33-2d31-482b-a856-94f89814c4df
Former-commit-id: 4297bbc4cc
pull/2/head
parent
e1a37f7bdb
commit
69d3f449e2
|
|
@ -434,14 +434,6 @@ public class NIOFileSystemAdapter implements FileSystemAdapter {
|
||||||
throw new InsufficientPermissionsException(path);
|
throw new InsufficientPermissionsException(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
if (Files.isDirectory(nioPath) && Files.list(nioPath).count() > 0) {
|
|
||||||
throw new DirectoryNotEmptyException(path);
|
|
||||||
}
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new FileAccessException(path, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recursively && Files.isDirectory(nioPath)) {
|
if (recursively && Files.isDirectory(nioPath)) {
|
||||||
final List<String> files;
|
final List<String> files;
|
||||||
try {
|
try {
|
||||||
|
|
@ -455,7 +447,11 @@ public class NIOFileSystemAdapter implements FileSystemAdapter {
|
||||||
for (final String file : files) {
|
for (final String file : files) {
|
||||||
deleteFile(file, recursively);
|
deleteFile(file, recursively);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deleteFile(path);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
||||||
deleteFile(path);
|
deleteFile(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,15 +22,20 @@ import org.libreccm.core.UnexpectedErrorException;
|
||||||
import org.libreccm.files.CcmFiles;
|
import org.libreccm.files.CcmFiles;
|
||||||
import org.libreccm.files.DirectoryNotEmptyException;
|
import org.libreccm.files.DirectoryNotEmptyException;
|
||||||
import org.libreccm.files.FileAccessException;
|
import org.libreccm.files.FileAccessException;
|
||||||
|
import org.libreccm.files.FileAlreadyExistsException;
|
||||||
import org.libreccm.files.FileDoesNotExistException;
|
import org.libreccm.files.FileDoesNotExistException;
|
||||||
import org.libreccm.files.InsufficientPermissionsException;
|
import org.libreccm.files.InsufficientPermissionsException;
|
||||||
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 java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
@ -84,8 +89,8 @@ public class FileSystemThemeProvider implements ThemeProvider {
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
} catch (FileAccessException
|
} catch (FileAccessException
|
||||||
| FileDoesNotExistException
|
| FileDoesNotExistException
|
||||||
| InsufficientPermissionsException ex) {
|
| InsufficientPermissionsException ex) {
|
||||||
|
|
||||||
throw new UnexpectedErrorException(ex);
|
throw new UnexpectedErrorException(ex);
|
||||||
}
|
}
|
||||||
|
|
@ -96,7 +101,7 @@ public class FileSystemThemeProvider implements ThemeProvider {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!ccmFiles.isDirectory(BASE_PATH)
|
if (!ccmFiles.isDirectory(BASE_PATH)
|
||||||
|| !ccmFiles.isDirectory(DRAFT_THEMES_PATH)) {
|
|| !ccmFiles.isDirectory(LIVE_THEMES_PATH)) {
|
||||||
|
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
@ -109,8 +114,8 @@ public class FileSystemThemeProvider implements ThemeProvider {
|
||||||
.map(info -> info.get())
|
.map(info -> info.get())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
} catch (FileAccessException
|
} catch (FileAccessException
|
||||||
| FileDoesNotExistException
|
| FileDoesNotExistException
|
||||||
| InsufficientPermissionsException ex) {
|
| InsufficientPermissionsException ex) {
|
||||||
|
|
||||||
throw new UnexpectedErrorException(ex);
|
throw new UnexpectedErrorException(ex);
|
||||||
}
|
}
|
||||||
|
|
@ -137,6 +142,86 @@ public class FileSystemThemeProvider implements ThemeProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ThemeInfo createTheme(final String themeName) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(themeName);
|
||||||
|
|
||||||
|
if (themeName.isEmpty() || themeName.matches("\\s*")) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"The name of a theme can't be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ccmFiles.createDirectory(String.format(DRAFT_THEMES_PATH + "/%s",
|
||||||
|
themeName));
|
||||||
|
} catch (FileAccessException
|
||||||
|
| FileAlreadyExistsException
|
||||||
|
| InsufficientPermissionsException ex) {
|
||||||
|
throw new UnexpectedErrorException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ThemeManifest manifest = new ThemeManifest();
|
||||||
|
manifest.setName(themeName);
|
||||||
|
|
||||||
|
final OutputStream outputStream;
|
||||||
|
try {
|
||||||
|
outputStream = ccmFiles.createOutputStream(
|
||||||
|
String.format(DRAFT_THEMES_PATH + "/%s/"
|
||||||
|
+ ThemeConstants.THEME_MANIFEST_JSON,
|
||||||
|
themeName));
|
||||||
|
} catch (FileAccessException
|
||||||
|
| InsufficientPermissionsException ex) {
|
||||||
|
throw new UnexpectedErrorException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
try(final OutputStreamWriter writer = new OutputStreamWriter(
|
||||||
|
outputStream, StandardCharsets.UTF_8)) {
|
||||||
|
writer
|
||||||
|
.append(manifestUtil
|
||||||
|
.serializeManifest(manifest,
|
||||||
|
ThemeConstants.THEME_MANIFEST_JSON));
|
||||||
|
writer.flush();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new UnexpectedErrorException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getThemeInfo(themeName, ThemeVersion.DRAFT).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteTheme(final String themeName) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(themeName);
|
||||||
|
|
||||||
|
if (themeName.isEmpty() || themeName.matches("\\s*")) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"The name of a theme can't be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
final Optional<ThemeInfo> liveTheme = getLiveThemes()
|
||||||
|
.stream()
|
||||||
|
.filter(theme -> theme.getName().equals(themeName))
|
||||||
|
.findAny();
|
||||||
|
|
||||||
|
if (liveTheme.isPresent()) {
|
||||||
|
throw new IllegalArgumentException(String
|
||||||
|
.format("The theme \"%s\" is live and can't be deleted.",
|
||||||
|
themeName));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ccmFiles.deleteFile(String.format(DRAFT_THEMES_PATH + "/%s",
|
||||||
|
themeName),
|
||||||
|
true);
|
||||||
|
} catch (FileAccessException
|
||||||
|
| FileDoesNotExistException
|
||||||
|
| DirectoryNotEmptyException
|
||||||
|
| InsufficientPermissionsException ex) {
|
||||||
|
throw new UnexpectedErrorException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ThemeFileInfo> listThemeFiles(final String theme,
|
public List<ThemeFileInfo> listThemeFiles(final String theme,
|
||||||
final ThemeVersion version,
|
final ThemeVersion version,
|
||||||
|
|
@ -154,8 +239,8 @@ public class FileSystemThemeProvider implements ThemeProvider {
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
} catch (FileAccessException
|
} catch (FileAccessException
|
||||||
| FileDoesNotExistException
|
| FileDoesNotExistException
|
||||||
| InsufficientPermissionsException ex) {
|
| InsufficientPermissionsException ex) {
|
||||||
|
|
||||||
throw new UnexpectedErrorException(ex);
|
throw new UnexpectedErrorException(ex);
|
||||||
}
|
}
|
||||||
|
|
@ -166,7 +251,7 @@ public class FileSystemThemeProvider implements ThemeProvider {
|
||||||
final String theme, final ThemeVersion version, final String path) {
|
final String theme, final ThemeVersion version, final String path) {
|
||||||
|
|
||||||
final String themePath = createThemePath(theme, version);
|
final String themePath = createThemePath(theme, version);
|
||||||
final String filePath = String.join(theme, path, "/");
|
final String filePath = String.join(themePath, path, "/");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (ccmFiles.existsFile(path)) {
|
if (ccmFiles.existsFile(path)) {
|
||||||
|
|
@ -175,8 +260,8 @@ public class FileSystemThemeProvider implements ThemeProvider {
|
||||||
return Optional.of(ccmFiles.createInputStream(filePath));
|
return Optional.of(ccmFiles.createInputStream(filePath));
|
||||||
}
|
}
|
||||||
} catch (FileAccessException
|
} catch (FileAccessException
|
||||||
| FileDoesNotExistException
|
| FileDoesNotExistException
|
||||||
| InsufficientPermissionsException ex) {
|
| InsufficientPermissionsException ex) {
|
||||||
|
|
||||||
throw new UnexpectedErrorException(ex);
|
throw new UnexpectedErrorException(ex);
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +279,7 @@ public class FileSystemThemeProvider implements ThemeProvider {
|
||||||
return ccmFiles.createOutputStream(filePath);
|
return ccmFiles.createOutputStream(filePath);
|
||||||
|
|
||||||
} catch (FileAccessException
|
} catch (FileAccessException
|
||||||
| InsufficientPermissionsException ex) {
|
| InsufficientPermissionsException ex) {
|
||||||
|
|
||||||
throw new UnexpectedErrorException(ex);
|
throw new UnexpectedErrorException(ex);
|
||||||
}
|
}
|
||||||
|
|
@ -209,9 +294,9 @@ public class FileSystemThemeProvider implements ThemeProvider {
|
||||||
try {
|
try {
|
||||||
ccmFiles.deleteFile(filePath, true);
|
ccmFiles.deleteFile(filePath, true);
|
||||||
} catch (FileAccessException
|
} catch (FileAccessException
|
||||||
| FileDoesNotExistException
|
| FileDoesNotExistException
|
||||||
| DirectoryNotEmptyException
|
| DirectoryNotEmptyException
|
||||||
| InsufficientPermissionsException ex) {
|
| InsufficientPermissionsException ex) {
|
||||||
|
|
||||||
throw new UnexpectedErrorException(ex);
|
throw new UnexpectedErrorException(ex);
|
||||||
}
|
}
|
||||||
|
|
@ -258,9 +343,9 @@ public class FileSystemThemeProvider implements ThemeProvider {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
|
|
||||||
case DRAFT:
|
case DRAFT:
|
||||||
return String.format(DRAFT_THEMES_PATH, theme);
|
return String.format(DRAFT_THEMES_PATH + "/%s", theme);
|
||||||
case LIVE:
|
case LIVE:
|
||||||
return String.format(LIVE_THEMES_PATH, theme);
|
return String.format(LIVE_THEMES_PATH + "/%s", theme);
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException(String
|
throw new IllegalArgumentException(String
|
||||||
.format("Illegal argument for ThemeVersion \"%s\".",
|
.format("Illegal argument for ThemeVersion \"%s\".",
|
||||||
|
|
@ -286,8 +371,8 @@ public class FileSystemThemeProvider implements ThemeProvider {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
} catch (FileAccessException
|
} catch (FileAccessException
|
||||||
| FileDoesNotExistException
|
| FileDoesNotExistException
|
||||||
| InsufficientPermissionsException ex) {
|
| InsufficientPermissionsException ex) {
|
||||||
|
|
||||||
throw new UnexpectedErrorException(ex);
|
throw new UnexpectedErrorException(ex);
|
||||||
}
|
}
|
||||||
|
|
@ -310,8 +395,8 @@ public class FileSystemThemeProvider implements ThemeProvider {
|
||||||
|
|
||||||
return fileInfo;
|
return fileInfo;
|
||||||
} catch (FileAccessException
|
} catch (FileAccessException
|
||||||
| FileDoesNotExistException
|
| FileDoesNotExistException
|
||||||
| InsufficientPermissionsException ex) {
|
| InsufficientPermissionsException ex) {
|
||||||
|
|
||||||
throw new UnexpectedErrorException(ex);
|
throw new UnexpectedErrorException(ex);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -254,6 +254,22 @@ public class StaticThemeProvider implements ThemeProvider {
|
||||||
return manifestJsonUrl != null || manifestXmlUrl != null;
|
return manifestJsonUrl != null || manifestXmlUrl != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ThemeInfo createTheme(final String theme) {
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException(String.format(
|
||||||
|
"The ThemeProvider %s does support the creation of new themes.",
|
||||||
|
getClass().getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteTheme(final String theme) {
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException(String.format(
|
||||||
|
"The ThemeProvider %s does support the deltion of themes.",
|
||||||
|
getClass().getName()));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ThemeFileInfo> listThemeFiles(final String theme,
|
public List<ThemeFileInfo> listThemeFiles(final String theme,
|
||||||
final ThemeVersion version,
|
final ThemeVersion version,
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,36 @@ public interface ThemeProvider extends Serializable {
|
||||||
*/
|
*/
|
||||||
boolean providesTheme(String theme, ThemeVersion version);
|
boolean providesTheme(String theme, ThemeVersion version);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new theme.
|
||||||
|
*
|
||||||
|
* The theme should be empty besides the manifest file. If a theme with the
|
||||||
|
* provided name already exists implementations should throw an
|
||||||
|
* {@link IllegalArgumentException}.
|
||||||
|
*
|
||||||
|
* {@code ThemeProvider} implementations which do not support the the
|
||||||
|
* creation of new themes the implementation of the method should throw a
|
||||||
|
* {@link UnsupportedOperationException}.
|
||||||
|
*
|
||||||
|
* @param themeName The name of the new theme.
|
||||||
|
*
|
||||||
|
* @return The {@link ThemeInfo} about the new theme.
|
||||||
|
*/
|
||||||
|
ThemeInfo createTheme(String themeName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a theme and all its content.
|
||||||
|
*
|
||||||
|
* If the is live implementations should throw an exception.
|
||||||
|
*
|
||||||
|
* {@code ThemeProvider} implementations which do not support the the
|
||||||
|
* deletion of themes the implementation of the method should throw a
|
||||||
|
* {@link UnsupportedOperationException}.
|
||||||
|
*
|
||||||
|
* @param themeName The theme to delete.
|
||||||
|
*/
|
||||||
|
void deleteTheme(String themeName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List all files in a theme at the specified path.
|
* List all files in a theme at the specified path.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -199,15 +199,16 @@ public class Themes implements Serializable {
|
||||||
* List all files in a theme at the specified path
|
* List all files in a theme at the specified path
|
||||||
*
|
*
|
||||||
* @param theme The theme from which the file is retrieved.
|
* @param theme The theme from which the file is retrieved.
|
||||||
* @param path The path of the file relative to the root directory of the
|
* @param path The path of the file relative to the root directory of the
|
||||||
* theme.
|
* theme.
|
||||||
|
*
|
||||||
* @return A list of all files in the provided directory. If there is no
|
* @return A list of all files in the provided directory. If there is no
|
||||||
* such path in the theme the list is empty. If the path is the path
|
* such path in the theme the list is empty. If the path is the path
|
||||||
* of a file and not a directory the list should have one element,
|
* of a file and not a directory the list should have one element,
|
||||||
* the data about the file itself.
|
* the data about the file itself.
|
||||||
*/
|
*/
|
||||||
public List<ThemeFileInfo> listThemesFiles(final ThemeInfo theme,
|
public List<ThemeFileInfo> listThemeFiles(final ThemeInfo theme,
|
||||||
final String path) {
|
final String path) {
|
||||||
|
|
||||||
final Instance<? extends ThemeProvider> forTheme = providers.select(
|
final Instance<? extends ThemeProvider> forTheme = providers.select(
|
||||||
theme.getProvider());
|
theme.getProvider());
|
||||||
|
|
@ -229,8 +230,8 @@ public class Themes implements Serializable {
|
||||||
public void deleteThemeFile(final ThemeInfo theme,
|
public void deleteThemeFile(final ThemeInfo theme,
|
||||||
final String path) {
|
final String path) {
|
||||||
|
|
||||||
final Instance<? extends ThemeProvider> forTheme = providers.select(
|
final Instance<? extends ThemeProvider> forTheme = providers
|
||||||
theme.getProvider());
|
.select(theme.getProvider());
|
||||||
|
|
||||||
if (forTheme.isUnsatisfied()) {
|
if (forTheme.isUnsatisfied()) {
|
||||||
LOGGER.error("ThemeProvider \"{}\" not found.",
|
LOGGER.error("ThemeProvider \"{}\" not found.",
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,39 @@ public class DatabaseThemeProvider implements ThemeProvider {
|
||||||
.isPresent();
|
.isPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ThemeInfo createTheme(final String themeName) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(themeName);
|
||||||
|
|
||||||
|
if (themeName.isEmpty() || themeName.matches("\\s*")) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"The name of a theme can't be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
final Theme theme = themeManager.createTheme(themeName);
|
||||||
|
|
||||||
|
return createThemeInfo(theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteTheme(final String themeName) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(themeName);
|
||||||
|
|
||||||
|
if (themeName.isEmpty() || themeName.matches("\\s*")) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"The name of a theme can't be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
final Theme theme = themeRepository
|
||||||
|
.findThemeByName(themeName, ThemeVersion.DRAFT)
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException(String.format(
|
||||||
|
"No theme with name \"%s\" is managed by this provider.",
|
||||||
|
themeName)));
|
||||||
|
themeManager.deleteTheme(theme);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ThemeFileInfo> listThemeFiles(final String themeName,
|
public List<ThemeFileInfo> listThemeFiles(final String themeName,
|
||||||
final ThemeVersion version,
|
final ThemeVersion version,
|
||||||
|
|
@ -270,7 +303,7 @@ public class DatabaseThemeProvider implements ThemeProvider {
|
||||||
|
|
||||||
if (file instanceof DataFile) {
|
if (file instanceof DataFile) {
|
||||||
fileManager.delete(file);
|
fileManager.delete(file);
|
||||||
} else if(file instanceof Directory) {
|
} else if (file instanceof Directory) {
|
||||||
fileManager.deleteRecursive(file);
|
fileManager.deleteRecursive(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.manager;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.ws.rs.ApplicationPath;
|
||||||
|
import javax.ws.rs.core.Application;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JAX-RS application for managing themes.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
@ApplicationPath("/thememanager")
|
||||||
|
public class ThemeManager extends Application {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Class<?>> getClasses() {
|
||||||
|
|
||||||
|
final Set<Class<?>> classes = new HashSet<>();
|
||||||
|
classes.add(Themes.class);
|
||||||
|
return classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,210 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.manager;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.libreccm.theming.ThemeInfo;
|
||||||
|
import org.libreccm.theming.ThemeProvider;
|
||||||
|
import org.libreccm.theming.ThemeVersion;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import javax.enterprise.context.RequestScoped;
|
||||||
|
import javax.enterprise.inject.Any;
|
||||||
|
import javax.enterprise.inject.Instance;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.json.Json;
|
||||||
|
import javax.json.JsonArrayBuilder;
|
||||||
|
import javax.json.JsonWriter;
|
||||||
|
import javax.ws.rs.DELETE;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.PUT;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
import javax.ws.rs.WebApplicationException;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import static javassist.CtClass.*;
|
||||||
|
import static org.reflections.util.Utils.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
@RequestScoped
|
||||||
|
@Path("/")
|
||||||
|
public class Themes implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger(Themes.class);
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@Any
|
||||||
|
private Instance<ThemeProvider> providers;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Themes themes;
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/providers")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public String getThemeProviders() {
|
||||||
|
|
||||||
|
final List<ThemeProvider> providersList = new ArrayList<>();
|
||||||
|
providers
|
||||||
|
.forEach(provider -> providersList.add(provider));
|
||||||
|
|
||||||
|
final JsonArrayBuilder jsonArrayBuilder = Json.createArrayBuilder();
|
||||||
|
|
||||||
|
providersList
|
||||||
|
.stream()
|
||||||
|
.filter(provider -> provider.supportsChanges()
|
||||||
|
&& provider.supportsDraftThemes())
|
||||||
|
.map(this::getProviderName)
|
||||||
|
.forEach(jsonArrayBuilder::add);
|
||||||
|
|
||||||
|
final StringWriter writer = new StringWriter();
|
||||||
|
final JsonWriter jsonWriter = Json.createWriter(writer);
|
||||||
|
|
||||||
|
jsonWriter.writeArray(jsonArrayBuilder.build());
|
||||||
|
|
||||||
|
return writer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/themes")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public List<ThemeInfo> getAvailableThemes() {
|
||||||
|
|
||||||
|
final List<ThemeInfo> availableThemes = new ArrayList<>();
|
||||||
|
for (final ThemeProvider provider : providers) {
|
||||||
|
if (provider.supportsChanges() && provider.supportsDraftThemes()) {
|
||||||
|
availableThemes.addAll(provider.getThemes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return availableThemes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/themes/{theme}")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public ThemeInfo getTheme(@PathParam("theme") final String themeName) {
|
||||||
|
|
||||||
|
for (final ThemeProvider provider : providers) {
|
||||||
|
if (provider.providesTheme(themeName, ThemeVersion.DRAFT)) {
|
||||||
|
return provider
|
||||||
|
.getThemeInfo(themeName, ThemeVersion.DRAFT)
|
||||||
|
.orElseThrow(() -> new WebApplicationException(
|
||||||
|
Response.Status.NOT_FOUND));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new WebApplicationException(Response.Status.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("/themes/{theme}")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public ThemeInfo createTheme(
|
||||||
|
@PathParam("theme") final String themeName,
|
||||||
|
@QueryParam("provider") final String providerName) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(themeName);
|
||||||
|
Objects.requireNonNull(providerName);
|
||||||
|
|
||||||
|
if (themeName.isEmpty() || themeName.matches("\\s*")) {
|
||||||
|
throw new WebApplicationException("No name for new theme provided.",
|
||||||
|
Response.Status.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (providerName.isEmpty() || providerName.matches("\\s*")) {
|
||||||
|
throw new WebApplicationException(
|
||||||
|
"No provider for new theme provided.",
|
||||||
|
Response.Status.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Class<ThemeProvider> providerClass;
|
||||||
|
try {
|
||||||
|
providerClass = (Class<ThemeProvider>) Class.forName(providerName);
|
||||||
|
} catch (ClassNotFoundException ex) {
|
||||||
|
throw new WebApplicationException(
|
||||||
|
String.format("No provider with name \"%s\" available.",
|
||||||
|
providerName),
|
||||||
|
Response.Status.INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
final ThemeProvider provider = providers.select(providerClass).get();
|
||||||
|
|
||||||
|
return provider.createTheme(themeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DELETE
|
||||||
|
@Path("/themes/{theme}")
|
||||||
|
public void deleteTheme(@PathParam("theme") final String themeName) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(themeName);
|
||||||
|
|
||||||
|
final List<ThemeProvider> providersList = new ArrayList<>();
|
||||||
|
providers
|
||||||
|
.forEach(provider -> providersList.add(provider));
|
||||||
|
|
||||||
|
final Optional<ThemeProvider> provider = providersList
|
||||||
|
.stream()
|
||||||
|
.filter(current -> current.providesTheme(themeName,
|
||||||
|
ThemeVersion.DRAFT))
|
||||||
|
.findAny();
|
||||||
|
|
||||||
|
if (provider.isPresent()) {
|
||||||
|
|
||||||
|
provider.get().deleteTheme(themeName);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new WebApplicationException(Response.Status.NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getProviderName(final ThemeProvider provider) {
|
||||||
|
|
||||||
|
if (provider
|
||||||
|
.getClass()
|
||||||
|
.getCanonicalName()
|
||||||
|
.toLowerCase()
|
||||||
|
.contains("$proxy")) {
|
||||||
|
|
||||||
|
final String name = provider.getClass().getCanonicalName();
|
||||||
|
return name.substring(0, name.toLowerCase().indexOf("$proxy"));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return provider.getClass().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -21,6 +21,7 @@ package org.libreccm.theming.manifest;
|
||||||
import static org.libreccm.theming.ThemeConstants.*;
|
import static org.libreccm.theming.ThemeConstants.*;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule;
|
import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule;
|
||||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||||
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
|
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
|
||||||
|
|
@ -149,6 +150,7 @@ public class ThemeManifestUtil implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper.registerModule(new JaxbAnnotationModule());
|
mapper.registerModule(new JaxbAnnotationModule());
|
||||||
|
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
|
||||||
|
|
||||||
final StringWriter writer = new StringWriter();
|
final StringWriter writer = new StringWriter();
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,7 @@ public class ThemeFiles {
|
||||||
"No theme with name \"%s\" exists.",
|
"No theme with name \"%s\" exists.",
|
||||||
theme)));
|
theme)));
|
||||||
|
|
||||||
final List<ThemeFileInfo> fileInfos = themes.listThemesFiles(themeInfo,
|
final List<ThemeFileInfo> fileInfos = themes.listThemeFiles(themeInfo,
|
||||||
path);
|
path);
|
||||||
final MultiStatus result;
|
final MultiStatus result;
|
||||||
if (fileInfos.isEmpty()) {
|
if (fileInfos.isEmpty()) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue