Integration of Themes with MVC

Jens Pelzetter 2020-12-19 19:10:12 +01:00
parent ebbf951981
commit 9bbab62c8a
3 changed files with 281 additions and 74 deletions

View File

@ -34,6 +34,9 @@ import javax.xml.bind.annotation.XmlRootElement;
import static org.libreccm.theming.ThemeConstants.*;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/**
* Each theme contains a Manifest (either in XML or JSON format) which provides
@ -88,8 +91,13 @@ public class ThemeManifest implements Serializable {
@XmlElement(name = "default-template", namespace = THEMES_XML_NS)
private String defaultTemplate;
@XmlElementWrapper(name = "mvcTemplates", namespace = THEMES_XML_NS)
@XmlElement(name = "template", namespace = THEME_MANIFEST_XML)
private Map<String, Map<String, ThemeTemplate>> mvcTemplates;
public ThemeManifest() {
templates = new ArrayList<>();
mvcTemplates = new HashMap<>();
}
public String getName() {
@ -156,6 +164,65 @@ public class ThemeManifest implements Serializable {
this.defaultTemplate = defaultTemplate;
}
public Map<String, Map<String, ThemeTemplate>> getMvcTemplates() {
return Collections.unmodifiableMap(mvcTemplates);
}
public Optional<Map<String, ThemeTemplate>> getMvcTemplatesOfCategory(
final String category
) {
return Optional.ofNullable(mvcTemplates.get(category));
}
public void addMvcTemplatesCategory(final String category) {
mvcTemplates.put(category, new HashMap<>());
}
public void addMvcTemplatesCategory(
final String category, final Map<String, ThemeTemplate> templates
) {
mvcTemplates.put(category, templates);
}
public Optional<ThemeTemplate> getMvcTemplate(
final String category, final String objectType
) {
final Optional<Map<String, ThemeTemplate>> templatesInCat
= getMvcTemplatesOfCategory(category);
if (templatesInCat.isPresent()) {
return Optional.ofNullable(templatesInCat.get().get(objectType));
} else {
return Optional.empty();
}
}
public void addMvcTemplate(
final String category,
final String objectType,
final ThemeTemplate template
) {
if (!mvcTemplates.containsKey(category)) {
addMvcTemplatesCategory(category);
}
mvcTemplates
.get(category)
.put(
objectType,
Objects.requireNonNull(
template,
"Template can't be null."
)
);
}
protected void setMvcTemplates(
final Map<String, Map<String, ThemeTemplate>> mvcTemplates
) {
this.mvcTemplates = mvcTemplates;
}
@Override
public int hashCode() {
int hash = 7;
@ -166,6 +233,7 @@ public class ThemeManifest implements Serializable {
hash = 83 * hash + Objects.hashCode(description);
hash = 83 * hash + Objects.hashCode(templates);
hash = 83 * hash + Objects.hashCode(defaultTemplate);
hash = 83 * hash + Objects.hashCode(mvcTemplates);
return hash;
}
@ -202,7 +270,10 @@ public class ThemeManifest implements Serializable {
if (!Objects.equals(templates, other.getTemplates())) {
return false;
}
return Objects.equals(defaultTemplate, other.getDefaultTemplate());
if (!Objects.equals(defaultTemplate, other.getDefaultTemplate())) {
return false;
}
return mvcTemplates.equals(other.getMvcTemplates());
}
public boolean canEqual(final Object obj) {
@ -216,24 +287,28 @@ public class ThemeManifest implements Serializable {
public String toString(final String data) {
return String.format("%s{ "
+ "name = \"%s\", "
+ "type = \"%s\", "
+ "masterTheme = \"%s\", "
+ "title = \"%s\", "
+ "description = \"%s\", "
+ "templates = %s, "
+ "defaultTemplate%s"
+ " }",
super.toString(),
name,
type,
masterTheme,
Objects.toString(title),
Objects.toString(description),
Objects.toString(templates),
defaultTemplate,
data);
return String.format(
"%s{ "
+ "name = \"%s\", "
+ "type = \"%s\", "
+ "masterTheme = \"%s\", "
+ "title = \"%s\", "
+ "description = \"%s\", "
+ "templates = %s, "
+ "defaultTemplate, "
+ "mvcTemplates = %s%s"
+ " }",
super.toString(),
name,
type,
masterTheme,
Objects.toString(title),
Objects.toString(description),
Objects.toString(templates),
defaultTemplate,
Objects.toString(mvcTemplates),
data
);
}

View File

@ -18,7 +18,8 @@
*/
package org.libreccm.theming.manifest;
import static org.libreccm.theming.ThemeConstants.*;
import static org.libreccm.theming.ThemeConstants.THEME_MANIFEST_JSON;
import static org.libreccm.theming.ThemeConstants.THEME_MANIFEST_XML;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
@ -60,8 +61,6 @@ public class ThemeManifestUtil implements Serializable {
* @return The parsed manifest file.
*/
public ThemeManifest loadManifest(final Path path) {
// final String pathStr = path.toString().toLowerCase(Locale.ROOT);
final BufferedReader reader;
try {
reader = Files.newBufferedReader(path, Charset.forName("UTF-8"));
@ -70,34 +69,11 @@ public class ThemeManifestUtil implements Serializable {
}
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) {
public ThemeManifest loadManifest(
final InputStream inputStream, final String fileName
) {
final InputStreamReader reader;
try {
reader = new InputStreamReader(inputStream, "UTF-8");
@ -106,34 +82,11 @@ public class ThemeManifestUtil implements Serializable {
}
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;
}
public String serializeManifest(final ThemeManifest manifest,
final String format) {
public String serializeManifest(
final ThemeManifest manifest, final String format
) {
final ObjectMapper mapper;
switch (format) {

View File

@ -0,0 +1,179 @@
/*
* Copyright (C) 2020 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.mvc;
import org.libreccm.sites.Site;
import org.libreccm.sites.SiteRepository;
import org.libreccm.theming.ThemeInfo;
import org.libreccm.theming.ThemeVersion;
import org.libreccm.theming.Themes;
import org.libreccm.theming.manifest.ThemeManifest;
import org.libreccm.theming.manifest.ThemeTemplate;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class ThemesMvc {
@Inject
private SiteRepository siteRepo;
@Inject
private Themes themes;
public String getMvcTemplate(
final UriInfo uriInfo,
final String application
) {
final Site site = getSite(uriInfo);
final String theme = parseThemeParam(uriInfo);
final ThemeVersion themeVersion = parsePreviewParam(uriInfo);
final ThemeInfo themeInfo = getTheme(
site,
theme,
themeVersion
);
final ThemeManifest manifest = themeInfo.getManifest();
final Map<String, ThemeTemplate> applicationTemplates = manifest
.getMvcTemplatesOfCategory("applications")
.orElseThrow(
() -> new WebApplicationException(
String.format(
"Manifest of theme %s has no application templates.",
themeInfo.getName()
),
Response.Status.INTERNAL_SERVER_ERROR
)
);
final ThemeTemplate themeTemplate;
if (applicationTemplates.containsKey(application)) {
themeTemplate = applicationTemplates.get(application);
} else {
themeTemplate = Optional.ofNullable(
applicationTemplates.get("@default")
).orElseThrow(
() -> new WebApplicationException(
String.format(
"Theme %s does not provide a template for application "
+ "%s and has not default template for "
+ "applications.",
theme,
application
)
)
);
}
return String.format(
"@themes/%s/%s/%s",
theme,
Objects.toString(themeVersion),
themeTemplate.getPath()
);
}
private Site getSite(final UriInfo uriInfo) {
Objects.requireNonNull(uriInfo);
final String domain = uriInfo.getBaseUri().getHost();
final Site site;
if (siteRepo.hasSiteForDomain(domain)) {
site = siteRepo.findByDomain(domain).get();
} else {
site = siteRepo
.findDefaultSite()
.orElseThrow(() -> new NotFoundException(
"No matching Site and no default Site."));
}
return site;
}
private ThemeInfo getTheme(
final Site site,
final String theme,
final ThemeVersion themeVersion) {
if ("--DEFAULT--".equals(theme)) {
return themes
.getTheme(site.getDefaultTheme(), themeVersion)
.orElseThrow(
() -> new WebApplicationException(
String.format(
"The configured default theme \"%s\" for "
+ "site \"%s\" is not available.",
site.getDefaultTheme(),
site.getDomainOfSite()
),
Response.Status.INTERNAL_SERVER_ERROR
)
);
} else {
return themes
.getTheme(theme, themeVersion)
.orElseThrow(
() -> new WebApplicationException(
String.format(
"The theme \"%s\" is not available.",
theme
),
Response.Status.BAD_REQUEST
)
);
}
}
private String parseThemeParam(final UriInfo uriInfo) {
if (uriInfo.getQueryParameters().containsKey("theme")) {
return uriInfo.getQueryParameters().getFirst("theme");
} else {
return "--DEFAULT--";
}
}
private ThemeVersion parsePreviewParam(final UriInfo uriInfo) {
if (uriInfo.getQueryParameters().containsKey("preview")) {
final List<String> values = uriInfo
.getQueryParameters()
.get("preview");
if (values.contains("theme") || values.contains("all")) {
return ThemeVersion.DRAFT;
} else {
return ThemeVersion.LIVE;
}
} else {
return ThemeVersion.LIVE;
}
}
}