All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.sling.provisioning.model.ModelResolveUtility Maven / Gradle / Ivy

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

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.StringReader;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Properties;

import org.apache.felix.cm.file.ConfigurationHandler;
import org.apache.sling.provisioning.model.ModelUtility.ArtifactVersionResolver;
import org.apache.sling.provisioning.model.ModelUtility.VariableResolver;

/**
 * Helper methods for resolving variables and artifact versions in models.
 */
class ModelResolveUtility {

    /**
     * Replace properties in the string.
     *
     * @param feature The feature
     * @param v The variable name
     * @param resolver Optional resolver
     * @result The value of the variable
     * @throws IllegalArgumentException If variable can't be found.
     */
    static String replace(final Feature feature, final String v, final VariableResolver resolver) {
        if ( v == null ) {
            return null;
        }
        String msg = v;
        // check for variables
        int pos = -1;
        int start = 0;
        while ( ( pos = msg.indexOf('$', start) ) != -1 ) {
            boolean escapedVariable = (pos > 0 && msg.charAt(pos - 1) == '\\');
            if ( msg.length() > pos && msg.charAt(pos + 1) == '{' && (pos == 0 || msg.charAt(pos - 1) != '$') ) {
                final int endPos = msg.indexOf('}', pos);
                if ( endPos != -1 ) {
                    final String name = msg.substring(pos + 2, endPos);
                    final String value;
                    if (escapedVariable) {
                        value = "\\${" + name + "}";
                    } else if ( resolver != null ) {
                        value = resolver.resolve(feature, name);
                    } else {
                        value = feature.getVariables().get(name);
                    }
                    if ( value == null ) {
                        throw new IllegalArgumentException("Unknown variable: " + name);
                    }
                    int startPos = escapedVariable ? pos - 1 : pos;
                    msg = msg.substring(0, startPos) + value + msg.substring(endPos + 1);
                }
            }
            start = pos + 1;
        }
        return msg;
    }
    
    /**
     * Tries to resolves artifact version via {@link ArtifactVersionResolver} if no version was defined in provisioning file.
     * @param groupId Group ID
     * @param artifactId Artifact ID
     * @param version Version
     * @param classifier Classifier
     * @param type Type
     * @param artifactVersionResolver Artifact Version Resolver (may be null)
     * @return Version to use for this artifact
     */
    static String resolveArtifactVersion(final String groupId, final String artifactId, final String version,
            final String classifier, final String type, ArtifactVersionResolver artifactVersionResolver) {
        if (artifactVersionResolver != null && (version == null || "LATEST".equals(version))) {
            String newVersion = artifactVersionResolver.resolve(new Artifact(groupId, artifactId, version, classifier, type));
            if (newVersion != null) {
                return newVersion;
            }
        }
        return version;       
    }
    
    /**
     * Replaces variables in configuration.
     * @param feature Feature
     * @param newConfig New configuration with replaced variables
     * @param config Source configuration which may contain variable placeholders
     * @param replaceVariables If set to true variables are resolved in the config before processing it.
     * @param resolver Variable resolver Optional variable resolver which is used. If not given only the feature's variables are used.
     */
    static void getProcessedConfiguration(
            final Feature feature,
            final Configuration newConfig,
            final Configuration config,
            final boolean replaceVariables,
            final VariableResolver resolver) {
        newConfig.setComment(config.getComment());
        newConfig.setLocation(config.getLocation());

        // check for raw configuration
        String rawConfig = (String)config.getProperties().get(ModelConstants.CFG_UNPROCESSED);
        if ( rawConfig != null ) {
            if ( replaceVariables ) {
                rawConfig = replace(feature, rawConfig, resolver);
            }
            if ( config.isSpecial() ) {
                newConfig.getProperties().put(config.getPid(), rawConfig);
            } else {
                final String format = (String)config.getProperties().get(ModelConstants.CFG_UNPROCESSED_FORMAT);

                if ( ModelConstants.CFG_FORMAT_PROPERTIES.equals(format) ) {
                    // properties
                    final Properties props = new Properties();
                    try {
                        props.load(new StringReader(rawConfig));
                    } catch ( final IOException ioe) {
                        throw new IllegalArgumentException("Unable to read configuration properties.", ioe);
                    }
                    final Enumeration i = props.keys();
                    while ( i.hasMoreElements() ) {
                        final String key = (String)i.nextElement();
                        newConfig.getProperties().put(key, props.get(key));
                    }
                } else {
                    // Apache Felix CA format
                    // the raw format might have comments, we have to remove them first
                    final StringBuilder sb = new StringBuilder();
                    try {
                        final LineNumberReader lnr = new LineNumberReader(new StringReader(rawConfig));
                        String line = null;
                        while ((line = lnr.readLine()) != null ) {
                            line = line.trim();
                            if ( line.isEmpty() || line.startsWith("#")) {
                                continue;
                            }
                            sb.append(line);
                            sb.append('\n');
                        }
                    } catch ( final IOException ioe) {
                        throw new IllegalArgumentException("Unable to read configuration properties: " + config, ioe);
                    }

                    ByteArrayInputStream bais = null;
                    try {
                        bais = new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
                        @SuppressWarnings("unchecked")
                        final Dictionary props = ConfigurationHandler.read(bais);
                        final Enumeration i = props.keys();
                        while ( i.hasMoreElements() ) {
                            final String key = i.nextElement();
                            newConfig.getProperties().put(key, props.get(key));
                        }
                    } catch ( final IOException ioe) {
                        throw new IllegalArgumentException("Unable to read configuration properties: " + config, ioe);
                    } finally {
                        if ( bais != null ) {
                            try {
                                bais.close();
                            } catch ( final IOException ignore ) {
                                // ignore
                            }
                        }
                    }
                }
            }
        } else {
            // simply copy
            final Enumeration i = config.getProperties().keys();
            while ( i.hasMoreElements() ) {
                final String key = i.nextElement();
                newConfig.getProperties().put(key, config.getProperties().get(key));
            }
        }
    }
    
}