You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:49:41 UTC
[sling-org-apache-sling-jcr-repoinit] 14/17: SLING-5943 - support
multiple model/raw references in RepositoryInitializer configuration
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to annotated tag org.apache.sling.jcr.repoinit-1.0.2
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-repoinit.git
commit 3fa0bab78247d746e44f8ccbc081732e13e764ad
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Tue Aug 16 14:28:28 2016 +0000
SLING-5943 - support multiple model/raw references in RepositoryInitializer configuration
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/jcr/repoinit@1756518 13f79535-47bb-0310-9956-ffa450edef68
---
.../jcr/repoinit/impl/RepoinitTextProvider.java | 141 +++++++++++++++++
.../jcr/repoinit/impl/RepositoryInitializer.java | 170 +++++----------------
.../jcr/repoinit/RepositoryInitializerTest.java | 38 +++--
.../jcr/repoinit/impl/RepoinitReferenceTest.java | 91 +++++++++++
4 files changed, 294 insertions(+), 146 deletions(-)
diff --git a/src/main/java/org/apache/sling/jcr/repoinit/impl/RepoinitTextProvider.java b/src/main/java/org/apache/sling/jcr/repoinit/impl/RepoinitTextProvider.java
new file mode 100644
index 0000000..7b07636
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/repoinit/impl/RepoinitTextProvider.java
@@ -0,0 +1,141 @@
+/*
+ * 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.InputStream;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.sling.provisioning.model.Feature;
+import org.apache.sling.provisioning.model.Model;
+import org.apache.sling.provisioning.model.Section;
+import org.apache.sling.provisioning.model.io.ModelReader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Retrieves repoinit statements from URLs that return either
+ * raw repoinit text or Sling provisioning models that are parsed
+ * to extract the repoinit text.
+ *
+ * Uses references like
+ *
+ * <code>model@repoinit:context:/resources/provisioning/model</code>,
+ *
+ * meaning that the supplied context:/ URI returns a provisioning model
+ * containing repoinit statements in its "repoinit" additional section, or
+ *
+ *
+ * <code>raw:classpath://com.example.sling.repoinit/repoinit.txt</code>
+ *
+ * meaning that the supplied classpath: URI returns raw repoinit statements.
+ */
+public class RepoinitTextProvider {
+ public static enum TextFormat { raw, model };
+ private static final String DEFAULT_MODEL_SECTION = "repoinit";
+
+ public static final Pattern REF_PATTERN = Pattern.compile("([a-z]+)(@([a-zA-Z0-9_-]+))?:(.*)");
+
+ private Logger log = LoggerFactory.getLogger(getClass());
+
+ static class Reference {
+ final TextFormat format;
+ final String modelSection;
+ final String url;
+
+ Reference(String ref) {
+ if(ref == null) {
+ throw new IllegalArgumentException("Null reference");
+ }
+ final Matcher m = REF_PATTERN.matcher(ref);
+ if(!m.matches()) {
+ throw new IllegalArgumentException("Invalid reference '" + ref + "', should match " + REF_PATTERN);
+ }
+ format = TextFormat.valueOf(m.group(1));
+ if(format.equals(TextFormat.raw)) {
+ modelSection = null;
+ } else if(format.equals(TextFormat.model) && m.group(3) == null) {
+ modelSection = DEFAULT_MODEL_SECTION;
+ } else {
+ modelSection = m.group(3);
+ }
+ url = m.group(4);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getSimpleName()).append(":");
+ sb.append("format=").append(format);
+ if(modelSection != null) {
+ sb.append(", model section=").append(modelSection);
+ }
+ sb.append(", URL=").append(url);
+ return sb.toString();
+ }
+ }
+
+ public String getRepoinitText(String referenceString) throws IOException {
+ final Reference ref = new Reference(referenceString);
+ log.info("Reading repoinit statements from {}", ref);
+ final String rawText = getRawText(ref.url);
+ log.debug("Raw text from {}: \n{}", ref.url, rawText);
+ if(TextFormat.model.equals(ref.format)) {
+ log.debug("Extracting provisioning model section {}", ref.modelSection);
+ return extractFromModel(ref.url, rawText, ref.modelSection);
+ } else {
+ return rawText;
+ }
+ }
+
+ private String extractFromModel(String sourceInfo, String rawText, String modelSection) throws IOException {
+ final StringReader reader = new StringReader(rawText);
+ final Model model = ModelReader.read(reader, sourceInfo);
+ final StringBuilder sb = new StringBuilder();
+ if(modelSection == null) {
+ throw new IllegalStateException("Model section name is null, cannot read model");
+ }
+ for (final Feature feature : model.getFeatures()) {
+ for (final Section section : feature.getAdditionalSections(modelSection)) {
+ sb.append("# ").append(modelSection).append(" from ").append(feature.getName()).append("\n");
+ sb.append("# ").append(section.getComment()).append("\n");
+ sb.append(section.getContents()).append("\n");
+ }
+ }
+ return sb.toString();
+ }
+
+ private String getRawText(String urlString) throws IOException {
+ String result = "";
+ final URL url = new URL(urlString);
+ final URLConnection c = url.openConnection();
+ final InputStream is = c.getInputStream();
+ if(is == null) {
+ log.warn("Cannot get InputStream for {}", url);
+ } else {
+ final StringWriter w = new StringWriter();
+ IOUtils.copy(is, w, "UTF-8");
+ result = w.toString();
+ }
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/jcr/repoinit/impl/RepositoryInitializer.java b/src/main/java/org/apache/sling/jcr/repoinit/impl/RepositoryInitializer.java
index 9b5c686..9dbab2c 100644
--- a/src/main/java/org/apache/sling/jcr/repoinit/impl/RepositoryInitializer.java
+++ b/src/main/java/org/apache/sling/jcr/repoinit/impl/RepositoryInitializer.java
@@ -16,34 +16,23 @@
*/
package org.apache.sling.jcr.repoinit.impl;
-import java.io.IOException;
-import java.io.InputStream;
import java.io.StringReader;
-import java.io.StringWriter;
-import java.net.URL;
-import java.net.URLConnection;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.jcr.Session;
-import org.apache.commons.io.IOUtils;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.PropertyOption;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.jcr.api.SlingRepositoryInitializer;
import org.apache.sling.jcr.repoinit.JcrRepoInitOpsProcessor;
-import org.apache.sling.provisioning.model.Feature;
-import org.apache.sling.provisioning.model.Model;
-import org.apache.sling.provisioning.model.Section;
-import org.apache.sling.provisioning.model.io.ModelReader;
import org.apache.sling.repoinit.parser.RepoInitParser;
import org.apache.sling.repoinit.parser.operations.Operation;
import org.osgi.framework.Constants;
@@ -66,40 +55,18 @@ import org.slf4j.LoggerFactory;
public class RepositoryInitializer implements SlingRepositoryInitializer {
private final Logger log = LoggerFactory.getLogger(getClass());
- public static final String DEFAULT_TEXT_URL = "context:/resources/provisioning/model.txt";
+ public static final String DEFAULT_REFERENCE = "model@repoinit:context:/resources/provisioning/model.txt";
@Property(
- label="Text URL",
- description="URL of the source text that provides repoinit statements.",
- value=DEFAULT_TEXT_URL)
- public static final String PROP_TEXT_URL = "text.url";
- private String textURL;
-
- public static final String DEFAULT_MODEL_SECTION_NAME = "repoinit";
-
- @Property(
- label="Model section name",
- description=
- "If using the provisioning model format, this specifies the additional section name (without leading colon) used to extract"
- + " repoinit statements from the raw text provided by the configured source text URL.",
- value=DEFAULT_MODEL_SECTION_NAME)
- public static final String PROP_MODEL_SECTION_NAME = "model.section.name";
- private String modelSectionName;
-
- @Property(
- label="Text format",
+ label="Repoinit references",
description=
- "The format to use to interpret the text provided by the configured source text URL. "
- + "That text can be either a Sling provisioning model with repoinit statements embedded in additional sections,"
- + " or raw repoinit statements",
- options = {
- @PropertyOption(name = "MODEL", value = "Provisioning Model (MODEL)"),
- @PropertyOption(name = "RAW", value = "Raw Repoinit statements (RAW)")
- },
- value="MODEL")
- public static final String PROP_TEXT_FORMAT = "text.format";
- public static enum TextFormat { RAW, MODEL };
- private TextFormat textFormat;
+ "References to the source text that provides repoinit statements."
+ + " format is either model@repoinit:<provisioning model URL> or raw:<raw URL>"
+ ,
+ cardinality=Integer.MAX_VALUE,
+ value={ DEFAULT_REFERENCE })
+ public static final String PROP_REFERENCES = "references";
+ private String [] references;
@Reference
private RepoInitParser parser;
@@ -109,106 +76,47 @@ public class RepositoryInitializer implements SlingRepositoryInitializer {
@Activate
public void activate(Map<String, Object> config) {
- textURL = PropertiesUtil.toString(config.get(PROP_TEXT_URL), DEFAULT_TEXT_URL);
-
- final String fmt = PropertiesUtil.toString(config.get(PROP_TEXT_FORMAT), TextFormat.MODEL.toString());
- try {
- textFormat = TextFormat.valueOf(fmt);
- } catch(Exception e) {
- throw new IllegalArgumentException("Invalid text format '" + fmt + "',"
- + " valid values are " + Arrays.asList(TextFormat.values()));
- }
-
- modelSectionName = PropertiesUtil.toString(config.get(PROP_MODEL_SECTION_NAME), DEFAULT_MODEL_SECTION_NAME);
-
+ warnForOldConfigParameters(config);
+ references = PropertiesUtil.toStringArray(config.get(PROP_REFERENCES));
log.debug("Activated: {}", this.toString());
}
+ /** Some config parameters are not used anymore as of V1.0.2, this logs
+ * warnings if they are still used.
+ */
+ private void warnForOldConfigParameters(Map<String, Object> config) {
+ final String [] names = {
+ "text.url",
+ "text.format",
+ "model.section.name"
+ };
+ for(String name : names) {
+ if(config.containsKey(name)) {
+ log.warn("Configuration parameter '{}' is not used anymore, will be ignored", name);
+ }
+ }
+ }
+
@Override
public String toString() {
- final StringBuilder sb = new StringBuilder();
- sb.append(getClass().getSimpleName()).append(": ");
- sb.append(PROP_TEXT_URL).append("=").append(textURL).append(", ");
- sb.append(PROP_TEXT_FORMAT).append("=").append(textFormat).append(", ");
- sb.append(PROP_MODEL_SECTION_NAME).append("=").append(modelSectionName);
- return sb.toString();
+ return getClass().getSimpleName() + ", references=" + Arrays.asList(references);
}
-
+
@Override
public void processRepository(SlingRepository repo) throws Exception {
- final String repoinit = getRepoInitText();
-
- if(TextFormat.MODEL.equals(textFormat)) {
- if(modelSectionName == null) {
- throw new IllegalStateException("Section name is null, cannot read model");
- }
- if(modelSectionName.trim().length() == 0) {
- throw new IllegalStateException("Empty " + PROP_MODEL_SECTION_NAME + " is not supported anymore, please use "
- + PROP_TEXT_FORMAT + " to specify the input text format");
- }
- }
-
// loginAdministrative is ok here, definitely an admin operation
final Session s = repo.loginAdministrative(null);
try {
- final List<Operation> ops = parser.parse(new StringReader(repoinit));
- log.info("Executing {} repoinit operations", ops.size());
- processor.apply(s, ops);
- s.save();
+ final RepoinitTextProvider p = new RepoinitTextProvider();
+ for(String reference : references) {
+ final String repoinitText = p.getRepoinitText(reference);
+ final List<Operation> ops = parser.parse(new StringReader(repoinitText));
+ log.info("Executing {} repoinit operations", ops.size());
+ processor.apply(s, ops);
+ s.save();
+ }
} finally {
s.logout();
}
- }
-
- /** Get the repoinit statements to execute */
- private String getRawRepoInitText() {
- String result = "";
- try {
- final URL url = new URL(textURL);
- final URLConnection c = url.openConnection();
- final InputStream is = c.getInputStream();
- if(is == null) {
- log.warn("Cannot get InputStream for {}", url);
- } else {
- final StringWriter w = new StringWriter();
- IOUtils.copy(is, w, "UTF-8");
- result = w.toString();
- }
- } catch(Exception e) {
- log.warn("Error reading repoinit statements from " + textURL, e);
- }
- return result;
- }
-
- private String getRepoInitText() {
- final String rawText = getRawRepoInitText();
- log.debug("Raw text from {}: \n{}", textURL, rawText);
- log.info("Got {} characters from {}", rawText.length(), textURL);
- if(TextFormat.RAW.equals(textFormat)) {
- log.info("Parsing raw repoinit statements from {}", textURL);
- return rawText;
- } else {
- log.info("Extracting repoinit statements from section ':{}' of provisioning model {}", modelSectionName, textURL);
- final StringReader reader = new StringReader(rawText);
- try {
- final Model model = ModelReader.read(reader, textURL);
- final StringBuilder sb = new StringBuilder();
- if(modelSectionName == null) {
- throw new IllegalStateException("Model section name is null, cannot read model");
- }
- for (final Feature feature : model.getFeatures()) {
- for (final Section section : feature.getAdditionalSections(modelSectionName)) {
- sb.append("# ").append(modelSectionName).append(" from ").append(feature.getName()).append("\n");
- sb.append("# ").append(section.getComment()).append("\n");
- sb.append(section.getContents()).append("\n");
- }
- }
- return sb.toString();
- } catch (IOException e) {
- log.warn("Error parsing provisioning model from " + textURL, e);
- return "";
- }
- }
- }
-
-}
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/jcr/repoinit/RepositoryInitializerTest.java b/src/test/java/org/apache/sling/jcr/repoinit/RepositoryInitializerTest.java
index 4081050..7167385 100644
--- a/src/test/java/org/apache/sling/jcr/repoinit/RepositoryInitializerTest.java
+++ b/src/test/java/org/apache/sling/jcr/repoinit/RepositoryInitializerTest.java
@@ -31,9 +31,10 @@ import java.util.UUID;
import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.jcr.repoinit.impl.JcrRepoInitOpsProcessorImpl;
+import org.apache.sling.jcr.repoinit.impl.RepoinitTextProvider.TextFormat;
import org.apache.sling.jcr.repoinit.impl.RepositoryInitializer;
-import org.apache.sling.jcr.repoinit.impl.RepositoryInitializer.TextFormat;
import org.apache.sling.jcr.repoinit.impl.TestUtil;
+import org.apache.sling.repoinit.parser.RepoInitParsingException;
import org.apache.sling.repoinit.parser.impl.RepoInitParserService;
import org.apache.sling.testing.mock.sling.ResourceResolverType;
import org.apache.sling.testing.mock.sling.junit.SlingContext;
@@ -70,18 +71,19 @@ public class RepositoryInitializerTest {
final List<Object []> result = new ArrayList<Object[]>();
// Realistic cases
- result.add(new Object[] { "Using provisioning model", "SECTION_" + UUID.randomUUID(), TextFormat.MODEL.toString(), true, true, null });
- result.add(new Object[] { "Default value of model section config", null, TextFormat.MODEL.toString(), true, true, null });
- result.add(new Object[] { "Raw repoinit/empty section", "", TextFormat.RAW.toString(), false, true, null });
- result.add(new Object[] { "Raw repoinit/ignored section name", "IGNORED_SectionName", TextFormat.RAW.toString(), false, true, null });
+ result.add(new Object[] { "Using provisioning model", "SECTION_" + UUID.randomUUID(), TextFormat.model.toString(), true, true, null });
+ result.add(new Object[] { "Default value of model section config", null, TextFormat.model.toString(), true, true, null });
+ result.add(new Object[] { "Raw repoinit/empty section", "", TextFormat.raw.toString(), false, true, null });
+ result.add(new Object[] { "Raw repoinit/ignored section name", "IGNORED_SectionName", TextFormat.raw.toString(), false, true, null });
// Edge and failure cases
- result.add(new Object[] { "All empty, just setup + parsing", "", TextFormat.RAW.toString(), false, false, null });
- result.add(new Object[] { "Raw repoinit/null format", null, null, true, false, RuntimeException.class });
+ result.add(new Object[] { "All empty, just setup + parsing", "", TextFormat.raw.toString(), false, false, null });
+ result.add(new Object[] { "Raw repoinit/null format", null, null, true, false, RepoInitParsingException.class });
result.add(new Object[] { "With model/null format", null, null, false, false, RuntimeException.class });
result.add(new Object[] { "Invalid format", null, "invalidFormat", false, false, RuntimeException.class });
- result.add(new Object[] { "Empty model section", "", TextFormat.MODEL.toString(), false, false, IllegalStateException.class });
- result.add(new Object[] { "Null model section", null, TextFormat.MODEL.toString(), false, false, IllegalStateException.class });
+ result.add(new Object[] { "Empty model section", "", TextFormat.model.toString(), false, false, IllegalArgumentException.class });
+ result.add(new Object[] { "Null model section", null, TextFormat.model.toString(), false, false, IOException.class });
+
return result;
}
@@ -109,14 +111,20 @@ public class RepositoryInitializerTest {
initializer = new RepositoryInitializer();
config = new HashMap<String, Object>();
- config.put(RepositoryInitializer.PROP_TEXT_URL, url);
- if(modelSection != null) {
- config.put(RepositoryInitializer.PROP_MODEL_SECTION_NAME, modelSection);
- }
- if(textFormat != null) {
- config.put(RepositoryInitializer.PROP_TEXT_FORMAT, textFormat);
+
+ String ref = null;
+ if(TextFormat.model.toString().equals(textFormat)) {
+ if(modelSection != null) {
+ ref = "model@" + modelSection + ":" + url;
+ } else {
+ ref = "model:" + url;
+ }
+ } else {
+ ref = "raw:" + url;
}
+ config.put(RepositoryInitializer.PROP_REFERENCES, new String[] { ref });
+
context.registerInjectActivateService(new RepoInitParserService());
context.registerInjectActivateService(new JcrRepoInitOpsProcessorImpl());
diff --git a/src/test/java/org/apache/sling/jcr/repoinit/impl/RepoinitReferenceTest.java b/src/test/java/org/apache/sling/jcr/repoinit/impl/RepoinitReferenceTest.java
new file mode 100644
index 0000000..5b6b775
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/repoinit/impl/RepoinitReferenceTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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 static org.junit.Assert.fail;
+import static org.junit.Assert.assertEquals;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.sling.jcr.repoinit.impl.RepoinitTextProvider.Reference;
+import org.apache.sling.jcr.repoinit.impl.RepoinitTextProvider.TextFormat;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/** Test the RepoinitTextProvider references parsing */
+@RunWith(Parameterized.class)
+public class RepoinitReferenceTest {
+
+ @Parameters(name="{0}")
+ public static Collection<Object[]> data() {
+ final List<Object []> result = new ArrayList<Object[]>();
+
+ // Valid references
+ result.add(new Object[] { "model@foo:uri:1234", TextFormat.model, "foo", "uri:1234", null });
+ result.add(new Object[] { "model:uri:2345", TextFormat.model, "repoinit", "uri:2345", null });
+ result.add(new Object[] { "raw:uri:4567", TextFormat.raw , null, "uri:4567", null });
+ result.add(new Object[] { "raw:uri@5678", TextFormat.raw, null, "uri@5678", null });
+
+ // Invalid references
+ result.add(new Object[] { "model@foo", null, null, null, IllegalArgumentException.class });
+ result.add(new Object[] { "model#foo:url", TextFormat.model, "repoinit", "url", IllegalArgumentException.class });
+ result.add(new Object[] { "", null, null, null, IllegalArgumentException.class });
+ result.add(new Object[] { null, null, null, null, IllegalArgumentException.class });
+ result.add(new Object[] { "foo:url", null, null, null, IllegalArgumentException.class });
+
+ // foo is ignored, by design
+ result.add(new Object[] { "raw@foo:url", TextFormat.raw, null, "url", null });
+
+ return result;
+ }
+
+ private final String input;
+ private final RepoinitTextProvider.TextFormat format;
+ private final String modelSection;
+ private final String url;
+ private final Class<?> expectedException;
+
+ public RepoinitReferenceTest(String input, TextFormat format, String modelSection, String url, Class<? >expectedException) {
+ this.input = input;
+ this.format = format;
+ this.modelSection = modelSection;
+ this.url = url;
+ this.expectedException = expectedException;
+ }
+
+ @Test
+ public void testParsing() {
+ try {
+ final Reference ref = new Reference(input);
+ if(expectedException != null) {
+ fail("Expected a " + expectedException.getName());
+ }
+ assertEquals(format, ref.format);
+ assertEquals(modelSection, ref.modelSection);
+ assertEquals(url, ref.url);
+ } catch(Exception e) {
+ if(expectedException != null) {
+ assertEquals(expectedException, e.getClass());
+ } else {
+ fail("Unexpected " + e);
+ }
+ }
+ }
+}
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.