org.apache.sling.provisioning.model.io.ModelReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
/*
* 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.provisioning.model.io;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.Reader;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.sling.provisioning.model.Artifact;
import org.apache.sling.provisioning.model.ArtifactGroup;
import org.apache.sling.provisioning.model.Commentable;
import org.apache.sling.provisioning.model.Configuration;
import org.apache.sling.provisioning.model.Feature;
import org.apache.sling.provisioning.model.Model;
import org.apache.sling.provisioning.model.ModelConstants;
import org.apache.sling.provisioning.model.RunMode;
import org.apache.sling.provisioning.model.Section;
/**
* This class offers a method to read a model using a {@code Reader} instance.
*/
public class ModelReader {
private enum CATEGORY {
NONE(null, null),
FEATURE("feature", new String[] {"name", "type", "version"}),
VARIABLES("variables", null),
ARTIFACTS("artifacts", new String[] {"runModes", "startLevel"}),
SETTINGS("settings", new String[] {"runModes"}),
CONFIGURATIONS("configurations", new String[] {"runModes"}),
CONFIG(null, null),
ADDITIONAL(null, null);
public final String name;
public final String[] parameters;
private CATEGORY(final String n, final String[] p) {
this.name = n;
this.parameters = p;
}
}
/**
* Reads the model file
* The reader is not closed. It is up to the caller to close the reader.
*
* @param reader The reader providing the model
* @param location Optional location string identifying the source of the model.
* @throws IOException If an error occurs
*/
public static Model read(final Reader reader, final String location)
throws IOException {
final ModelReader mr = new ModelReader(location);
return mr.readModel(reader);
}
private CATEGORY mode = CATEGORY.NONE;
private final Model model = new Model();
private Feature feature;
private RunMode runMode;
private ArtifactGroup artifactGroup;
private Configuration config;
private Section additionalSection;
private String comment;
private StringBuilder configBuilder;
private LineNumberReader lineNumberReader;
private final String exceptionPrefix;
private ModelReader(final String location) {
this.model.setLocation(location);
if ( location == null ) {
exceptionPrefix = "";
} else {
exceptionPrefix = location + " : ";
}
}
private Model readModel(final Reader reader)
throws IOException {
boolean global = true;
lineNumberReader = new LineNumberReader(reader);
String line;
while ( (line = lineNumberReader.readLine()) != null ) {
// trim the line
line = line.trim();
// ignore empty line
if ( line.isEmpty() ) {
if ( this.mode == CATEGORY.ADDITIONAL ) {
if ( this.additionalSection.getContents() == null ) {
this.additionalSection.setContents(line);
} else {
this.additionalSection.setContents(this.additionalSection.getContents() + '\n' + line);
}
continue;
}
checkConfig();
continue;
}
// comment?
if ( line.startsWith("#") ) {
if ( config != null ) {
configBuilder.append(line);
configBuilder.append('\n');
continue;
}
if ( this.mode == CATEGORY.ADDITIONAL ) {
if ( this.additionalSection.getContents() == null ) {
this.additionalSection.setContents(line);
} else {
this.additionalSection.setContents(this.additionalSection.getContents() + '\n' + line);
}
continue;
}
final String c = line.substring(1).trim();
if ( comment == null ) {
comment = c;
} else {
comment = comment + "\n" + c;
}
continue;
}
if ( global ) {
global = false;
if ( !line.startsWith("[feature ") ) {
throw new IOException(exceptionPrefix + " Model file must start with a feature category.");
}
}
if ( line.startsWith("[") ) {
additionalSection = null;
if ( !line.endsWith("]") ) {
throw new IOException(exceptionPrefix + "Illegal category definition in line " + this.lineNumberReader.getLineNumber() + ": " + line);
}
int pos = 1;
while ( line.charAt(pos) != ']' && !Character.isWhitespace(line.charAt(pos))) {
pos++;
}
final String category = line.substring(1, pos);
CATEGORY found = null;
for (CATEGORY c : CATEGORY.values()) {
if ( category.equals(c.name)) {
found = c;
break;
}
}
if ( found == null ) {
// additional section
if ( !category.startsWith(":") ) {
throw new IOException(exceptionPrefix + "Unknown category in line " + this.lineNumberReader.getLineNumber() + ": " + category);
}
found = CATEGORY.ADDITIONAL;
}
this.mode = found;
Map parameters = Collections.emptyMap();
if (line.charAt(pos) != ']') {
final String parameterLine = line.substring(pos + 1, line.length() - 1).trim();
parameters = parseParameters(parameterLine, this.mode.parameters);
}
switch ( this.mode ) {
case NONE : break; // this can never happen
case CONFIG : break; // this can never happen
case FEATURE : final String name = parameters.get("name");
if ( name == null ) {
throw new IOException(exceptionPrefix + "Feature name missing in line " + this.lineNumberReader.getLineNumber() + ": " + line);
}
if ( model.getFeature(name) != null ) {
throw new IOException(exceptionPrefix + "Duplicate feature in line " + this.lineNumberReader.getLineNumber() + ": " + line);
}
this.feature = model.getOrCreateFeature(name);
this.feature.setType(parameters.get("type"));
this.feature.setVersion(parameters.get("version"));
this.init(this.feature);
this.runMode = null;
this.artifactGroup = null;
break;
case VARIABLES : checkFeature();
this.init(this.feature.getVariables());
break;
case SETTINGS: checkFeature();
checkRunMode(parameters);
this.init(this.runMode.getSettings());
break;
case ARTIFACTS: checkFeature();
checkRunMode(parameters);
int startLevel = 0;
String level = parameters.get("startLevel");
if ( level != null ) {
try {
startLevel = Integer.valueOf(level);
} catch ( final NumberFormatException nfe) {
throw new IOException(exceptionPrefix + "Invalid start level in line " + this.lineNumberReader.getLineNumber() + ": " + line + ":" + level);
}
}
if ( this.runMode.getArtifactGroup(startLevel) != null ) {
throw new IOException(exceptionPrefix + "Duplicate artifact group in line " + this.lineNumberReader.getLineNumber() + ": " + line);
}
this.artifactGroup = this.runMode.getOrCreateArtifactGroup(startLevel);
this.init(this.artifactGroup);
break;
case CONFIGURATIONS: checkFeature();
checkRunMode(parameters);
this.init(this.runMode.getConfigurations());
break;
case ADDITIONAL: checkFeature();
this.runMode = null;
this.artifactGroup = null;
this.additionalSection = new Section(category.substring(1));
this.init(this.additionalSection);
this.feature.getAdditionalSections().add(this.additionalSection);
this.additionalSection.getAttributes().putAll(parameters);
}
} else {
switch ( this.mode ) {
case NONE : break;
case VARIABLES : final String[] vars = parseProperty(line);
feature.getVariables().put(vars[0], vars[1]);
break;
case SETTINGS : final String[] settings = parseProperty(line);
runMode.getSettings().put(settings[0], settings[1]);
break;
case FEATURE: this.runMode = this.feature.getOrCreateRunMode(null);
this.artifactGroup = this.runMode.getOrCreateArtifactGroup(0);
// no break, we continue with ARTIFACT
case ARTIFACTS : String artifactUrl = line;
Map parameters = Collections.emptyMap();
if ( line.endsWith("]") ) {
final int startPos = line.indexOf("[");
if ( startPos != -1 ) {
artifactUrl = line.substring(0, startPos).trim();
parameters = parseParameters(line.substring(startPos + 1, line.length() - 1).trim(), null);
}
}
try {
final Artifact artifact = Artifact.fromMvnUrl("mvn:" + artifactUrl);
this.init(artifact);
this.artifactGroup.add(artifact);
artifact.getMetadata().putAll(parameters);
} catch ( final IllegalArgumentException iae) {
throw new IOException(exceptionPrefix + iae.getMessage() + " in line " + this.lineNumberReader.getLineNumber(), iae);
}
break;
case CONFIGURATIONS : String configId = line;
Map cfgPars = Collections.emptyMap();
if ( line.endsWith("]") ) {
final int startPos = line.indexOf("[");
if ( startPos != -1 ) {
configId = line.substring(0, startPos).trim();
cfgPars = parseParameters(line.substring(startPos + 1, line.length() - 1).trim(), new String[] {"format", "mode"});
}
}
String format = cfgPars.get("format");
if ( format != null ) {
if ( !ModelConstants.CFG_FORMAT_FELIX_CA.equals(format)
&& !ModelConstants.CFG_FORMAT_PROPERTIES.equals(format) ) {
throw new IOException(exceptionPrefix + "Unknown format configuration parameter in line " + this.lineNumberReader.getLineNumber() + ": " + line);
}
} else {
format = ModelConstants.CFG_FORMAT_FELIX_CA;
}
String cfgMode= cfgPars.get("mode");
if ( cfgMode != null ) {
if ( !ModelConstants.CFG_MODE_OVERWRITE.equals(cfgMode)
&& !ModelConstants.CFG_MODE_MERGE.equals(cfgMode) ) {
throw new IOException(exceptionPrefix + "Unknown mode configuration parameter in line " + this.lineNumberReader.getLineNumber() + ": " + line);
}
} else {
cfgMode = ModelConstants.CFG_MODE_OVERWRITE;
}
final String pid;
final String factoryPid;
final int factoryPos = configId.indexOf('-');
if ( factoryPos == -1 ) {
pid = configId;
factoryPid = null;
} else {
pid = configId.substring(factoryPos + 1);
factoryPid = configId.substring(0, factoryPos);
}
if ( runMode.getConfiguration(pid, factoryPid) != null ) {
throw new IOException(exceptionPrefix + "Duplicate configuration in line " + this.lineNumberReader.getLineNumber());
}
config = runMode.getOrCreateConfiguration(pid, factoryPid);
this.init(config);
config.getProperties().put(ModelConstants.CFG_UNPROCESSED_FORMAT, format);
config.getProperties().put(ModelConstants.CFG_UNPROCESSED_MODE, cfgMode);
configBuilder = new StringBuilder();
mode = CATEGORY.CONFIG;
break;
case CONFIG : configBuilder.append(line);
configBuilder.append('\n');
break;
case ADDITIONAL : if ( this.additionalSection.getContents() == null ) {
this.additionalSection.setContents(line);
} else {
this.additionalSection.setContents(this.additionalSection.getContents() + '\n' + line);
}
break;
}
}
}
checkConfig();
if ( comment != null ) {
throw new IOException(exceptionPrefix + "Comment not allowed at the end of file");
}
return model;
}
/**
* Check for a feature object
*/
private void checkFeature() throws IOException {
if ( feature == null ) {
throw new IOException(exceptionPrefix + "No preceding feature definition in line " + this.lineNumberReader.getLineNumber());
}
}
/**
* Check for a run mode object
*/
private void checkRunMode(final Map parameters) throws IOException {
String[] runModes = null;
final String rmDef = parameters.get("runModes");
if ( rmDef != null ) {
runModes = rmDef.split(",");
for(int i=0; i parseParameters(final String line, final String[] allowedParameters) throws IOException {
final Mapparameters = new HashMap();
final String[] keyValuePairs = line.split(" ");
for(String kv : keyValuePairs) {
kv = kv.trim();
if ( !kv.isEmpty() ) {
final int sep = kv.indexOf('=');
if ( sep == -1 ) {
throw new IOException(exceptionPrefix + "Invalid parameter definition in line " + this.lineNumberReader.getLineNumber() + ": " + line);
}
final String key = kv.substring(0, sep).trim();
parameters.put(key, kv.substring(sep + 1).trim());
if ( allowedParameters != null ) {
boolean found = false;
for(final String allowed : allowedParameters) {
if ( key.equals(allowed) ) {
found = true;
break;
}
}
if ( !found ) {
throw new IOException(exceptionPrefix + "Invalid parameter " + key + " in line " + this.lineNumberReader.getLineNumber());
}
}
}
}
return parameters;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy