You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by kw...@apache.org on 2020/01/04 17:29:00 UTC
[sling-org-apache-sling-installer-console] branch master updated:
SLING-8897 dedicated console for serializing configurations (#1)
This is an automated email from the ASF dual-hosted git repository.
kwin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-installer-console.git
The following commit(s) were added to refs/heads/master by this push:
new 892b438 SLING-8897 dedicated console for serializing configurations (#1)
892b438 is described below
commit 892b438a194b8cf5ea8cc0876475564b7fba4085
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Sat Jan 4 18:28:51 2020 +0100
SLING-8897 dedicated console for serializing configurations (#1)
* SLING-8897 dedicated console for serializing configurations
Update to parent 35
---
pom.xml | 59 ++---
.../ConfigurationSerializerWebConsolePlugin.java | 292 +++++++++++++++++++++
src/main/resources/res/ui/clipboard.js | 31 +++
3 files changed, 352 insertions(+), 30 deletions(-)
diff --git a/pom.xml b/pom.xml
index 011c683..ed1611b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,35 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
+ or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
+ regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
+ with the License. You may obtain a copy of the License at
+
http://www.apache.org/licenses/LICENSE-2.0
-
+
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
+ KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.sling</groupId>
- <artifactId>sling</artifactId>
- <version>30</version>
- <relativePath />
+ <artifactId>sling-bundle-parent</artifactId>
+ <version>35</version>
+ <relativePath/>
</parent>
<artifactId>org.apache.sling.installer.console</artifactId>
<version>1.0.3-SNAPSHOT</version>
- <packaging>bundle</packaging>
<name>Apache Sling Installer WebConsole Plugin</name>
<description>
@@ -42,37 +42,36 @@
<url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-installer-console.git</url>
</scm>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <extensions>true</extensions>
- <configuration>
- <instructions>
- <Private-Package>
- org.apache.sling.installer.core.impl.console
- </Private-Package>
- </instructions>
- </configuration>
- </plugin>
- </plugins>
- </build>
-
<dependencies>
<dependency>
<groupId>org.osgi</groupId>
- <artifactId>osgi.core</artifactId>
+ <artifactId>org.osgi.framework</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.component.annotations</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.cm</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.installer.core</artifactId>
- <version>3.8.0</version>
+ <version>3.9.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
+ <scope>provided</scope>
</dependency>
</dependencies>
</project>
diff --git a/src/main/java/org/apache/sling/installer/core/impl/console/ConfigurationSerializerWebConsolePlugin.java b/src/main/java/org/apache/sling/installer/core/impl/console/ConfigurationSerializerWebConsolePlugin.java
new file mode 100644
index 0000000..d6d065f
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/core/impl/console/ConfigurationSerializerWebConsolePlugin.java
@@ -0,0 +1,292 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.installer.core.impl.console;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+import javax.servlet.GenericServlet;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.sling.installer.api.serializer.ConfigurationSerializerFactory;
+import org.apache.sling.installer.api.serializer.ConfigurationSerializerFactory.Format;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(service=javax.servlet.Servlet.class,
+ property = {
+ Constants.SERVICE_VENDOR + "=The Apache Software Foundation",
+ Constants.SERVICE_DESCRIPTION + "=Apache Sling OSGi Installer Configuration Serializer Web Console Plugin",
+ "felix.webconsole.label=" + ConfigurationSerializerWebConsolePlugin.LABEL,
+ "felix.webconsole.title=OSGi Installer Configuration Printer",
+ "felix.webconsole.category=OSGi"
+ })
+@SuppressWarnings("serial")
+public class ConfigurationSerializerWebConsolePlugin extends GenericServlet {
+
+ public static final String LABEL = "osgi-installer-config-printer";
+ private static final String RES_LOC = LABEL + "/res/ui";
+ private static final String PARAMETER_PID = "pid";
+ private static final String PARAMETER_FORMAT = "format";
+
+ // copied from org.apache.sling.installer.factories.configuration.impl.ConfigUtil
+ /**
+ * This property has been used in older versions to keep track where the
+ * configuration has been installed from.
+ */
+ private static final String CONFIG_PATH_KEY = "org.apache.sling.installer.osgi.path";
+
+ /**
+ * This property has been used in older versions to keep track of factory
+ * configurations.
+ */
+ private static final String ALIAS_KEY = "org.apache.sling.installer.osgi.factoryaliaspid";
+
+ /** Configuration properties to ignore when printing */
+ private static final Set<String> IGNORED_PROPERTIES = new HashSet<>();
+ static {
+ IGNORED_PROPERTIES.add(Constants.SERVICE_PID);
+ IGNORED_PROPERTIES.add(CONFIG_PATH_KEY);
+ IGNORED_PROPERTIES.add(ALIAS_KEY);
+ IGNORED_PROPERTIES.add(ConfigurationAdmin.SERVICE_FACTORYPID);
+ }
+
+ /** The logger */
+ private final Logger LOGGER = LoggerFactory.getLogger(ConfigurationSerializerWebConsolePlugin.class);
+
+ @Reference
+ ConfigurationAdmin configurationAdmin;
+
+ /**
+ * Method to retrieve static resources from this bundle.
+ */
+ @SuppressWarnings("unused")
+ private URL getResource(final String path) {
+ if (path.startsWith("/" + RES_LOC)) {
+ return this.getClass().getResource(path.substring(LABEL.length()+1));
+ }
+ return null;
+ }
+
+ @Override
+ public void service(final ServletRequest request, final ServletResponse response)
+ throws IOException {
+
+ final String pid = request.getParameter(PARAMETER_PID);
+ final String format = request.getParameter(PARAMETER_FORMAT);
+ ConfigurationSerializerFactory.Format serializationFormat = Format.JSON;
+ if (format != null && !format.trim().isEmpty()) {
+ try {
+ serializationFormat = ConfigurationSerializerFactory.Format.valueOf(format);
+ } catch (IllegalArgumentException e) {
+ LOGGER.warn("Illegal parameter 'format' given, falling back to default '{}'", serializationFormat, e);
+ }
+ }
+ final PrintWriter pw = response.getWriter();
+
+ pw.println("<script type=\"text/javascript\" src=\"" + RES_LOC + "/clipboard.js\"></script>");
+ pw.print("<form method='get'>");
+ pw.println("<table class='content' cellpadding='0' cellspacing='0' width='100%'>");
+
+ titleHtml(
+ pw,
+ "OSGi Installer Configuration Printer",
+ "To emit the configuration properties just enter the configuration PID, select a <a href='https://sling.apache.org/documentation/bundles/configuration-installer-factory.html'>serialization format</a> and click 'Print'");
+
+ tr(pw);
+ tdLabel(pw, "PID");
+ tdContent(pw);
+
+ pw.print("<input type='text' name='");
+ pw.print(PARAMETER_PID);
+ pw.print("' value='");
+ if ( pid != null ) {
+ pw.print(escapeXml(pid));
+ }
+
+ pw.println("' class='input' size='120'>");
+ closeTd(pw);
+ closeTr(pw);
+ closeTr(pw);
+
+ tr(pw);
+ tdLabel(pw, "Serialization Format");
+ tdContent(pw);
+ pw.print("<select name='");
+ pw.print(PARAMETER_FORMAT);
+ pw.println("'>");
+ option(pw, "JSON", "OSGi Configurator JSON", format);
+ option(pw, "CONFIG", "Apache Felix Config", format);
+ option(pw, "PROPERTIES", "Java Properties", format);
+ option(pw, "PROPERTIES_XML", "Java Properties (XML)", format);
+ pw.println("</select>");
+
+ pw.println(" <input type='submit' value='Print' class='submit'>");
+
+ closeTd(pw);
+ closeTr(pw);
+
+ if (pid != null && !pid.trim().isEmpty()) {
+ tr(pw);
+ tdLabel(pw, "Serialized Configuration Properties");
+ tdContent(pw);
+
+ Configuration configuration = configurationAdmin.getConfiguration(pid);
+ Dictionary<String, Object> properties = configuration.getProperties();
+ if (properties == null) {
+ pw.print("<p class='ui-state-error-text'>");
+ pw.print("No configuration properties for pid '" + escapeXml(pid) + "' found!");
+ pw.println("</p>");
+ } else {
+ properties = cleanConfiguration(properties);
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ConfigurationSerializerFactory.create(serializationFormat).serialize(properties, baos);
+ pw.println("<textarea rows=\"20\" cols=\"120\" id=\"output\" readonly>");
+ pw.print(new String(baos.toByteArray(), StandardCharsets.UTF_8));
+ pw.println("</textarea>");
+ pw.println("<button type='button' id='copy'>Copy to Clipboard</a>");
+ } catch (Throwable e) {
+ pw.print("<p class='ui-state-error-text'>");
+ pw.print("Error serializing pid '" + escapeXml(pid) + "': " + e.getMessage());
+ pw.println("</p>");
+ LOGGER.warn("Error serializing pid '{}'", pid, e);
+ }
+ }
+ closeTd(pw);
+ closeTr(pw);
+ }
+
+ pw.println("</table>");
+ pw.print("</form>");
+ }
+
+ /**
+ * Copied from org.apache.sling.api.request.ResponseUtil
+ * Escape XML text
+ * @param input The input text
+ * @return The escaped text
+ */
+ private String escapeXml(final String input) {
+ if (input == null) {
+ return null;
+ }
+
+ final StringBuilder b = new StringBuilder(input.length());
+ for(int i = 0;i < input.length(); i++) {
+ final char c = input.charAt(i);
+ if(c == '&') {
+ b.append("&");
+ } else if(c == '<') {
+ b.append("<");
+ } else if(c == '>') {
+ b.append(">");
+ } else if(c == '"') {
+ b.append(""");
+ } else if(c == '\'') {
+ b.append("'");
+ } else {
+ b.append(c);
+ }
+ }
+ return b.toString();
+ }
+
+ // copied from org.apache.sling.installer.factories.configuration.impl.ConfigUtil
+ /**
+ * Remove all ignored properties
+ */
+ public static Dictionary<String, Object> cleanConfiguration(final Dictionary<String, Object> config) {
+ final Dictionary<String, Object> cleanedConfig = new Hashtable<>();
+ final Enumeration<String> e = config.keys();
+ while(e.hasMoreElements()) {
+ final String key = e.nextElement();
+ if ( !IGNORED_PROPERTIES.contains(key) ) {
+ cleanedConfig.put(key, config.get(key));
+ }
+ }
+
+ return cleanedConfig;
+ }
+
+ private void tdContent(final PrintWriter pw) {
+ pw.print("<td class='content' colspan='2'>");
+ }
+
+ private void closeTd(final PrintWriter pw) {
+ pw.print("</td>");
+ }
+
+ private void closeTr(final PrintWriter pw) {
+ pw.println("</tr>");
+ }
+
+ private void tdLabel(final PrintWriter pw, final String label) {
+ pw.print("<td class='content'>");
+ pw.print(label);
+ pw.println("</td>");
+ }
+
+ private void tr(final PrintWriter pw) {
+ pw.println("<tr class='content'>");
+ }
+
+ private void option(final PrintWriter pw, String value, String label, String selectedValue) {
+ pw.print("<option value='");
+ pw.print(value);
+ pw.print("'");
+ if (value.equals(selectedValue)) {
+ pw.print(" selected");
+ }
+ pw.print(">");
+ pw.print(label);
+ pw.println("</option>");
+ }
+
+ private void titleHtml(final PrintWriter pw, final String title, final String description) {
+ tr(pw);
+ pw.print("<th colspan='3' class='content container'>");
+ pw.print(escapeXml(title));
+ pw.println("</th>");
+ closeTr(pw);
+
+ if (description != null) {
+ tr(pw);
+ pw.print("<td colspan='3' class='content'>");
+ pw.print(description);
+ pw.println("</th>");
+ closeTr(pw);
+ }
+ }
+
+}
diff --git a/src/main/resources/res/ui/clipboard.js b/src/main/resources/res/ui/clipboard.js
new file mode 100644
index 0000000..197f933
--- /dev/null
+++ b/src/main/resources/res/ui/clipboard.js
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+function copyToClipboard(inputElement) {
+ inputElement.select();
+ document.execCommand("copy");
+}
+
+window.onload = function() {
+ button = document.querySelector("#copy");
+ if (button != null) {
+ button.addEventListener("click", function() {
+ copyToClipboard(document.querySelector("#output"));
+ });
+ }
+}