/* * 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; } }