You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by dk...@apache.org on 2020/07/07 15:43:42 UTC
[sling-org-apache-sling-jcr-repoinit] 01/01: SLING-9572: Adding
OSGi WebConsole for executing Sling RepoInit scripts
This is an automated email from the ASF dual-hosted git repository.
dklco pushed a commit to branch feature/SLING-9572
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-repoinit.git
commit 987974473d92c2cd55f003cc25d8431b6cbd7631
Author: Dan Klco <dk...@apache.org>
AuthorDate: Tue Jul 7 11:43:18 2020 -0400
SLING-9572: Adding OSGi WebConsole for executing Sling RepoInit scripts
---
pom.xml | 83 +++++----
.../jcr/repoinit/impl/RepoInitWebConsole.java | 185 +++++++++++++++++++++
src/main/resources/console.html | 63 +++++++
3 files changed, 302 insertions(+), 29 deletions(-)
diff --git a/pom.xml b/pom.xml
index 87044d2..b10101d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,37 +18,37 @@
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">
- <modelVersion>4.0.0</modelVersion>
+ <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.apache.sling</groupId>
- <artifactId>sling-bundle-parent</artifactId>
- <version>38</version>
- <relativePath />
- </parent>
+ <parent>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>sling-bundle-parent</artifactId>
+ <version>38</version>
+ <relativePath />
+ </parent>
- <artifactId>org.apache.sling.jcr.repoinit</artifactId>
- <version>1.1.29-SNAPSHOT</version>
- <name>Apache Sling Repoinit JCR</name>
- <description>
+ <artifactId>org.apache.sling.jcr.repoinit</artifactId>
+ <version>1.1.29-SNAPSHOT</version>
+ <name>Apache Sling Repoinit JCR</name>
+ <description>
Initializes a JCR repository based on the output
of the RepoInit Language parser.
</description>
- <properties>
- <jackrabbit.version>2.18.2</jackrabbit.version>
- <oak.version>1.16.0</oak.version>
- <org.ops4j.pax.exam.version>4.13.3</org.ops4j.pax.exam.version>
- <!-- To debug the pax process, override this with -D -->
- <pax.vm.options>-Xmx512M</pax.vm.options>
- </properties>
+ <properties>
+ <jackrabbit.version>2.18.2</jackrabbit.version>
+ <oak.version>1.16.0</oak.version>
+ <org.ops4j.pax.exam.version>4.13.3</org.ops4j.pax.exam.version>
+ <!-- To debug the pax process, override this with -D -->
+ <pax.vm.options>-Xmx512M</pax.vm.options>
+ </properties>
- <scm>
- <connection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-repoinit.git</connection>
- <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-repoinit.git</developerConnection>
- <url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-jcr-repoinit.git</url>
- <tag>org.apache.sling.jcr.repoinit-1.1.24</tag>
- </scm>
+ <scm>
+ <connection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-repoinit.git</connection>
+ <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-repoinit.git</developerConnection>
+ <url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-jcr-repoinit.git</url>
+ <tag>org.apache.sling.jcr.repoinit-1.1.24</tag>
+ </scm>
<build>
<plugins>
@@ -56,7 +56,7 @@
<groupId>org.apache.servicemix.tooling</groupId>
<artifactId>depends-maven-plugin</artifactId>
</plugin>
- <plugin>
+ <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
@@ -88,12 +88,12 @@
<redirectTestOutputToFile>true</redirectTestOutputToFile>
<systemProperties>
<property>
- <name>bundle.filename</name>
- <value>${basedir}/target/${project.build.finalName}.jar</value>
+ <name>bundle.filename</name>
+ <value>${basedir}/target/${project.build.finalName}.jar</value>
</property>
<property>
- <name>pax.vm.options</name>
- <value>${pax.vm.options}</value>
+ <name>pax.vm.options</name>
+ <value>${pax.vm.options}</value>
</property>
</systemProperties>
</configuration>
@@ -298,5 +298,30 @@
<version>2.6</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.webconsole</artifactId>
+ <version>4.2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.3.2</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.xss</artifactId>
+ <version>2.2.2</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.api</artifactId>
+ <version>2.20.0</version>
+ <scope>provided</scope>
+ </dependency>
+
</dependencies>
</project>
diff --git a/src/main/java/org/apache/sling/jcr/repoinit/impl/RepoInitWebConsole.java b/src/main/java/org/apache/sling/jcr/repoinit/impl/RepoInitWebConsole.java
new file mode 100644
index 0000000..ac03410
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/repoinit/impl/RepoInitWebConsole.java
@@ -0,0 +1,185 @@
+/*
+ * 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.jcr.repoinit.impl;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import javax.jcr.Session;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.text.StrSubstitutor;
+import org.apache.felix.webconsole.AbstractWebConsolePlugin;
+import org.apache.felix.webconsole.WebConsoleConstants;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.jcr.repoinit.JcrRepoInitOpsProcessor;
+import org.apache.sling.repoinit.parser.RepoInitParser;
+import org.apache.sling.repoinit.parser.RepoInitParsingException;
+import org.apache.sling.repoinit.parser.operations.Operation;
+import org.apache.sling.xss.XSSAPI;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(service = Servlet.class, property = {
+ Constants.SERVICE_DESCRIPTION + "=Apache Sling Service User Manager Web Console Plugin",
+ WebConsoleConstants.PLUGIN_LABEL + "=" + RepoInitWebConsole.LABEL,
+ WebConsoleConstants.PLUGIN_TITLE + "=" + RepoInitWebConsole.TITLE,
+ WebConsoleConstants.PLUGIN_CATEGORY + "=Sling" })
+public class RepoInitWebConsole extends AbstractWebConsolePlugin {
+
+ private static final Logger log = LoggerFactory.getLogger(RepoInitWebConsole.class);
+
+ @Reference(policyOption = ReferencePolicyOption.GREEDY)
+ private XSSAPI xss;
+
+ @Reference
+ private RepoInitParser parser;
+
+ @Reference
+ private JcrRepoInitOpsProcessor processor;
+
+ @Reference(policyOption = ReferencePolicyOption.GREEDY)
+ private ResourceResolverFactory resolverFactory;
+
+ private static final long serialVersionUID = 1L;
+ public static final String LABEL = "repoinit";
+ public static final String TITLE = "RepoInit";
+
+ private static final String PN_STATEMENTS = "statements";
+ private static final String PN_EXECUTE = "execute";
+
+ @Override
+ public String getLabel() {
+ return LABEL;
+ }
+
+ @Override
+ public String getTitle() {
+ return TITLE;
+ }
+
+ @Override
+ protected void renderContent(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ Map<String, String> parameters = readRequest(request);
+ parameters.put("result", "");
+ writeResponse(response, parameters);
+
+ }
+
+ private Map<String, String> readRequest(HttpServletRequest request) {
+
+ Map<String, String> parameters = new HashMap<>();
+ String statements = Optional.ofNullable(request.getParameter(PN_STATEMENTS)).orElse("");
+ parameters.put(PN_STATEMENTS, xss.encodeForHTML(statements));
+ parameters.put(PN_EXECUTE, "true".equals(request.getParameter(PN_EXECUTE)) ? "checked" : "");
+ return parameters;
+ }
+
+ private void writeResponse(HttpServletResponse response, Map<String, String> parameters) throws IOException {
+ String consoleHtml = IOUtils.toString(this.getBundle().getEntry("console.html").openStream(),
+ StandardCharsets.UTF_8);
+ StrSubstitutor sub = new StrSubstitutor(parameters);
+ IOUtils.write(sub.replace(consoleHtml), response.getWriter());
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ Map<String, String> parameters = readRequest(request);
+
+ StringReader statements = Optional.ofNullable(request.getParameter(PN_STATEMENTS)).map(StringReader::new)
+ .orElse(new StringReader(""));
+ List<String> messages = new ArrayList<>();
+ List<Operation> operations = null;
+ try {
+ operations = parser.parse(statements);
+ messages.add("PARSING SUCCEEDED: ");
+ operations.stream().map(Operation::toString).forEach(messages::add);
+ } catch (RepoInitParsingException e) {
+ messages.add("PARSING FAILED: ");
+ messages.add(e.toString());
+ }
+
+ if (operations != null && "true".equals(request.getParameter(PN_EXECUTE))) {
+ messages.add("");
+ Session session;
+ try {
+ session = getResourceResolver(request).adaptTo(Session.class);
+ processor.apply(session, operations);
+ messages.add("EXECUTION SUCCEEDED!");
+ } catch (Exception e) {
+ messages.add("EXECUTION FAILED: ");
+ messages.add(e.toString());
+ }
+ }
+ parameters.put("result", messages.stream().collect(Collectors.joining("\n")));
+
+ PrintWriter pw = startResponse(request, response);
+
+ renderTopNavigation(request, pw);
+
+ pw.println("<div id='content'>");
+ writeResponse(response, parameters);
+ pw.println("</div>");
+
+ endResponse(pw);
+ }
+
+ private boolean needsAdministrativeResolver(HttpServletRequest request) {
+ Object resolver = request.getAttribute("org.apache.sling.auth.core.ResourceResolver");
+ return !(resolver instanceof ResourceResolver);
+ }
+
+ @SuppressWarnings("deprecation")
+ private ResourceResolver getResourceResolver(HttpServletRequest request) throws LoginException {
+ ResourceResolver resolver = null;
+ if (needsAdministrativeResolver(request)) {
+ try {
+ log.warn("Resource resolver not available in request, falling back to adminstrative resource resolver");
+ resolver = resolverFactory.getAdministrativeResourceResolver(null);
+ } catch (LoginException le) {
+ throw new LoginException(
+ "Unable to get Administrative Resource Resolver, add the bundle org.apache.sling.jcr.repoinit.parser.webconsole in the Apache Sling Login Admin Whitelist",
+ le);
+ }
+ } else {
+ resolver = (ResourceResolver) request.getAttribute("org.apache.sling.auth.core.ResourceResolver");
+ }
+
+ return resolver;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/resources/console.html b/src/main/resources/console.html
new file mode 100644
index 0000000..7df9b50
--- /dev/null
+++ b/src/main/resources/console.html
@@ -0,0 +1,63 @@
+<!--
+ * 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.
+-->
+<p class="statline ui-state-highlight">
+ RepoInits are statements used to initialize the Sling repository. Use this
+ tool to test these statements.<br/>
+ <a href="https://sling.apache.org/documentation/bundles/repository-initialization.html" target="_blank" rel="noopener noreferrer">
+ Sling RepoInit Documentation
+ </a>
+ </p>
+ <br />
+ <form method="post" action="/system/console/repoinit">
+ <table class="nicetable ui-widget">
+ <thead class="ui-widget-header">
+ <tr>
+ <th colspan="2" class="ui-widget-header">
+ Test RepoInit
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td style="width: 20%;">RepoInit Statements</td>
+ <td>
+ <textarea name="statements" rows="10" style="width: 100%">${statements}</textarea>
+ </td>
+ </tr>
+ <tr>
+ <td style="width: 20%;">Execute</td>
+ <td>
+ <input type="checkbox" name="execute" value="true" ${execute} />
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>
+ <input
+ type="submit"
+ value="Run"
+ class="ui-state-default ui-corner-all"
+ />
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </form>
+ <br/>
+ <div class="statline ui-state-highlight">
+ <pre>${result}</pre>
+ </div>
\ No newline at end of file