From fc4d838bc784899f883f5e59c37505ab83f38855 Mon Sep 17 00:00:00 2001 From: Jens Pelzetter Date: Sun, 13 Sep 2020 16:51:50 +0200 Subject: [PATCH] Integrate Krazo Facelets View Engine with LibreCCM themes --- .../mvc/facelets/CcmThemeUrlConnection.java | 104 ++++++++++++++++++ .../facelets/CcmThemeUrlStreamHandler.java | 45 ++++++++ .../mvc/facelets/CcmThemeViewResource.java | 59 ++++++++++ .../mvc/facelets/CcmViewResourceHandler.java | 72 ++++++++++++ 4 files changed, 280 insertions(+) create mode 100644 ccm-core/src/main/java/org/libreccm/mvc/facelets/CcmThemeUrlConnection.java create mode 100644 ccm-core/src/main/java/org/libreccm/mvc/facelets/CcmThemeUrlStreamHandler.java create mode 100644 ccm-core/src/main/java/org/libreccm/mvc/facelets/CcmThemeViewResource.java create mode 100644 ccm-core/src/main/java/org/libreccm/mvc/facelets/CcmViewResourceHandler.java diff --git a/ccm-core/src/main/java/org/libreccm/mvc/facelets/CcmThemeUrlConnection.java b/ccm-core/src/main/java/org/libreccm/mvc/facelets/CcmThemeUrlConnection.java new file mode 100644 index 000000000..cde1d8636 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/mvc/facelets/CcmThemeUrlConnection.java @@ -0,0 +1,104 @@ +/* + * 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.mvc.facelets; + +import org.libreccm.theming.ThemeInfo; +import org.libreccm.theming.ThemeVersion; +import org.libreccm.theming.Themes; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.util.Arrays; +import java.util.Objects; + +/** + * + * @author Jens Pelzetter + */ +class CcmThemeUrlConnection extends URLConnection { + + private final Themes themes; + + private final String path; + + private ThemeInfo themeInfo; + + private String filePath; + + public CcmThemeUrlConnection(final Themes themes, final URL url) { + super(url); + this.themes = themes; + + final String urlStr = url.toString(); + + if (urlStr.startsWith("/")) { + path = urlStr.substring(1); + } else { + path = urlStr; + } + } + + @Override + public void connect() throws IOException { + final String[] tokens = path.split("/"); + if (tokens.length >= 4) { + final String themeName = tokens[1]; + final ThemeVersion version = ThemeVersion.valueOf(tokens[2]); + filePath = String.join( + "/", + Arrays.copyOfRange( + tokens, 3, tokens.length, String[].class + ) + ); + + themeInfo = themes.getTheme(themeName, version) + .orElseThrow(() -> new IOException( + String.format( + "Theme %s is available as %s version.", + themeName, + Objects.toString(version) + ))); + } else { + throw new IOException( + "Illegal URL for loading a facelets template from a theme." + ); + } + + } + + @Override + public InputStream getInputStream() throws IOException { + return themes + .getFileFromTheme(themeInfo, filePath) + .orElseThrow( + () -> new IOException( + String.format( + "Template %s not found in %s version of the theme %s.", + filePath, + themeInfo.getVersion(), + themeInfo.getName() + ) + ) + ); + + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/mvc/facelets/CcmThemeUrlStreamHandler.java b/ccm-core/src/main/java/org/libreccm/mvc/facelets/CcmThemeUrlStreamHandler.java new file mode 100644 index 000000000..2242bf47e --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/mvc/facelets/CcmThemeUrlStreamHandler.java @@ -0,0 +1,45 @@ +/* + * 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.mvc.facelets; + +import org.libreccm.theming.Themes; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +/** + * + * @author Jens Pelzetter + */ +class CcmThemeUrlStreamHandler extends URLStreamHandler { + + private final Themes themes; + + public CcmThemeUrlStreamHandler(final Themes themes) { + this.themes = themes; + } + + @Override + protected URLConnection openConnection(final URL url) throws IOException { + return new CcmThemeUrlConnection(themes, url); + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/mvc/facelets/CcmThemeViewResource.java b/ccm-core/src/main/java/org/libreccm/mvc/facelets/CcmThemeViewResource.java new file mode 100644 index 000000000..4d70648c2 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/mvc/facelets/CcmThemeViewResource.java @@ -0,0 +1,59 @@ +/* + * 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.mvc.facelets; + +import org.libreccm.core.UnexpectedErrorException; +import org.libreccm.theming.Themes; + +import java.net.MalformedURLException; +import java.net.URL; + +import javax.faces.application.ViewResource; + +/** + * + * @author Jens Pelzetter + */ +class CcmThemeViewResource extends ViewResource { + + private final String path; + + private final Themes themes; + + public CcmThemeViewResource(final Themes themes, final String path) { + this.themes = themes; + this.path = path; + } + + @Override + public URL getURL() { + try { + return new URL( + "libreccm", + null, + 0, + path, + new CcmThemeUrlStreamHandler(themes) + ); + } catch (MalformedURLException ex) { + throw new UnexpectedErrorException(ex); + } + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/mvc/facelets/CcmViewResourceHandler.java b/ccm-core/src/main/java/org/libreccm/mvc/facelets/CcmViewResourceHandler.java new file mode 100644 index 000000000..88332b49e --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/mvc/facelets/CcmViewResourceHandler.java @@ -0,0 +1,72 @@ +/* + * 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.mvc.facelets; + +import org.libreccm.theming.Themes; + +import javax.faces.application.ResourceHandler; +import javax.faces.application.ResourceHandlerWrapper; +import javax.faces.application.ViewResource; +import javax.faces.context.FacesContext; +import javax.inject.Inject; + +/** + * A Facelets resource handler that loads Facelets templates from LibreCCM + * themes. + * + * This handler only works for view resources. Only resource path which are + * starting with {@code @themes} or {@code /@themes} are used processed. All + * other paths are delegated to the wrapped resource handler. + * + * To enable this resource handler to following snippet must be present in the + * {@code faces-config.xml} file of the WAR (bundle): + * + *
+ * <application>
+        &tl;resource-handler>org.libreccm.ui.CcmFaceletsResourceHandler</resource-handler>
+    </application>
+
+ * 
+ * + * @author Jens Pelzetter + */ +public class CcmViewResourceHandler extends ResourceHandlerWrapper { + + @Inject + private Themes themes; + + private final ResourceHandler wrapped; + + public CcmViewResourceHandler(final ResourceHandler wrapped) { + super(wrapped); + this.wrapped = wrapped; + } + + @Override + public ViewResource createViewResource( + final FacesContext context, final String path + ) { + if (path.startsWith("@themes") || path.startsWith("/@themes")) { + return new CcmThemeViewResource(themes, path); + } else { + return super.createViewResource(context, path); + } + } + +}