org.eclipse.gemini.blueprint.extender.support.internal.ConfigUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.gemini.blueprint.extender.support.internal.ConfigUtils.java

Source

/******************************************************************************
 * Copyright (c) 2006, 2010 VMware Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Apache License v2.0 which accompanies this distribution. 
 * The Eclipse Public License is available at 
 * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
 * is available at http://www.opensource.org/licenses/apache2.0.php.
 * You may elect to redistribute this code under either of these licenses. 
 * 
 * Contributors:
 *   VMware Inc.
 *****************************************************************************/

package org.eclipse.gemini.blueprint.extender.support.internal;

import java.util.Dictionary;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.Bundle;
import org.osgi.framework.Version;
import org.eclipse.gemini.blueprint.context.support.OsgiBundleXmlApplicationContext;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

/**
 * Utility class for dealing with the extender configuration and OSGi bundle
 * manifest headers.
 * 
 * Defines Spring/OSGi constants and methods for configuring Spring application
 * context.
 * 
 * @author Costin Leau
 * 
 */
public abstract class ConfigUtils {

    private static final Log log = LogFactory.getLog(ConfigUtils.class);

    public static final String EXTENDER_VERSION = "SpringExtender-Version";

    private static final String LEFT_CLOSED_INTERVAL = "[";

    private static final String LEFT_OPEN_INTERVAL = "(";

    private static final String RIGHT_CLOSED_INTERVAL = "]";

    private static final String RIGHT_OPEN_INTERVAL = ")";

    private static final String COMMA = ",";

    public static final String CONFIG_WILDCARD = "*";

    /**
     * Manifest entry name for configuring Spring application context.
     */
    public static final String SPRING_CONTEXT_HEADER = "Spring-Context";

    /**
     * Directive for publishing Spring application context as a service.
     */
    public static final String DIRECTIVE_PUBLISH_CONTEXT = "publish-context";

    /**
     * Directive for indicating wait-for time when satisfying mandatory
     * dependencies defined in seconds
     */
    public static final String DIRECTIVE_TIMEOUT = "timeout";

    public static final String DIRECTIVE_TIMEOUT_VALUE_NONE = "none";

    /**
     * Create asynchronously directive.
     */
    public static final String DIRECTIVE_CREATE_ASYNCHRONOUSLY = "create-asynchronously";

    /**
     * Wait for dependencies or directly start the context.
     */
    public static final String DIRECTIVE_WAIT_FOR_DEPS = "wait-for-dependencies";

    /**
     * {@link #DIRECTIVE_WAIT_FOR_DEPS} default.
     */
    public static final boolean DIRECTIVE_WAIT_FOR_DEPS_DEFAULT = true;

    public static final String EQUALS = ":=";

    /**
     * Token used for separating directives inside a header.
     */
    public static final String DIRECTIVE_SEPARATOR = ";";

    public static final String CONTEXT_LOCATION_SEPARATOR = ",";

    public static final boolean DIRECTIVE_PUBLISH_CONTEXT_DEFAULT = true;

    public static final boolean DIRECTIVE_CREATE_ASYNCHRONOUSLY_DEFAULT = true;

    public static final long DIRECTIVE_TIMEOUT_DEFAULT = 5 * 60; // 5 minutes

    public static final long DIRECTIVE_NO_TIMEOUT = -2L; // Indicates wait forever

    public static boolean matchExtenderVersionRange(Bundle bundle, String header, Version versionToMatch) {
        Assert.notNull(bundle);
        // get version range
        String range = bundle.getHeaders().get(header);

        boolean trace = log.isTraceEnabled();

        // empty value = empty version = *
        if (!StringUtils.hasText(range))
            return true;

        if (trace)
            log.trace("discovered " + header + " header w/ value=" + range);

        // do we have a range or not ?
        range = StringUtils.trimWhitespace(range);

        // a range means one comma
        int commaNr = StringUtils.countOccurrencesOf(range, COMMA);

        // no comma, no intervals
        if (commaNr == 0) {
            Version version = Version.parseVersion(range);

            return versionToMatch.equals(version);
        }

        if (commaNr == 1) {

            // sanity check
            if (!((range.startsWith(LEFT_CLOSED_INTERVAL) || range.startsWith(LEFT_OPEN_INTERVAL))
                    && (range.endsWith(RIGHT_CLOSED_INTERVAL) || range.endsWith(RIGHT_OPEN_INTERVAL)))) {
                throw new IllegalArgumentException("range [" + range + "] is invalid");
            }

            boolean equalMin = range.startsWith(LEFT_CLOSED_INTERVAL);
            boolean equalMax = range.endsWith(RIGHT_CLOSED_INTERVAL);

            // remove interval brackets
            range = range.substring(1, range.length() - 1);

            // split the remaining string in two pieces
            String[] pieces = StringUtils.split(range, COMMA);

            if (trace)
                log.trace("discovered low/high versions : " + ObjectUtils.nullSafeToString(pieces));

            Version minVer = Version.parseVersion(pieces[0]);
            Version maxVer = Version.parseVersion(pieces[1]);

            if (trace)
                log.trace("comparing version " + versionToMatch + " w/ min=" + minVer + " and max=" + maxVer);

            boolean result = true;

            int compareMin = versionToMatch.compareTo(minVer);

            if (equalMin)
                result = (result && (compareMin >= 0));
            else
                result = (result && (compareMin > 0));

            int compareMax = versionToMatch.compareTo(maxVer);

            if (equalMax)
                result = (result && (compareMax <= 0));
            else
                result = (result && (compareMax < 0));

            return result;
        }

        // more then one comma means incorrect range

        throw new IllegalArgumentException("range [" + range + "] is invalid");
    }

    /**
     * Return the {@value #SPRING_CONTEXT_HEADER} if present from the given
     * dictionary.
     * 
     * @param headers
     * @return
     */
    public static String getSpringContextHeader(Dictionary headers) {
        Object header = null;
        if (headers != null)
            header = headers.get(SPRING_CONTEXT_HEADER);
        return (header != null ? header.toString().trim() : null);
    }

    /**
     * Return the directive value as a String. If the directive does not exist
     * or is invalid (wrong format) a null string will be returned.
     * 
     * @param header
     * @param directive
     * @return
     */
    public static String getDirectiveValue(String header, String directive) {
        Assert.notNull(header, "not-null header required");
        Assert.notNull(directive, "not-null directive required");
        String[] directives = StringUtils.tokenizeToStringArray(header, DIRECTIVE_SEPARATOR);

        for (int i = 0; i < directives.length; i++) {
            String[] splittedDirective = StringUtils.delimitedListToStringArray(directives[i].trim(), EQUALS);
            if (splittedDirective.length == 2 && splittedDirective[0].equals(directive))
                return splittedDirective[1];
        }

        return null;
    }

    /**
     * Shortcut method to retrieve directive values. Used internally by the
     * dedicated getXXX.
     * 
     * @param directiveName
     * @return
     */
    private static String getDirectiveValue(Dictionary headers, String directiveName) {
        String header = getSpringContextHeader(headers);
        if (header != null) {
            String directive = getDirectiveValue(header, directiveName);
            if (directive != null)
                return directive;
        }
        return null;
    }

    /**
     * Returns true if the given directive is present or false otherwise.
     * 
     * @param headers
     * @param directiveName
     * @return
     */
    public static boolean isDirectiveDefined(Dictionary headers, String directiveName) {
        String header = getSpringContextHeader(headers);
        if (header != null) {
            String directive = getDirectiveValue(header, directiveName);
            return (directive != null);
        }
        return false;
    }

    /**
     * Shortcut for finding the boolean value for
     * {@link #DIRECTIVE_PUBLISH_CONTEXT} directive using the given headers.
     * Assumes the headers belong to a Spring powered bundle.
     * 
     * @param headers
     * @return
     */
    public static boolean getPublishContext(Dictionary headers) {
        String value = getDirectiveValue(headers, DIRECTIVE_PUBLISH_CONTEXT);
        return (value != null ? Boolean.valueOf(value) : DIRECTIVE_PUBLISH_CONTEXT_DEFAULT);
    }

    /**
     * Shortcut for finding the boolean value for
     * {@link #DIRECTIVE_CREATE_ASYNCHRONOUSLY} directive using the given
     * headers.
     * 
     * Assumes the headers belong to a Spring powered bundle.
     * 
     * @param headers
     * @return
     */
    public static boolean getCreateAsync(Dictionary headers) {
        String value = getDirectiveValue(headers, DIRECTIVE_CREATE_ASYNCHRONOUSLY);
        return (value != null ? Boolean.valueOf(value) : DIRECTIVE_CREATE_ASYNCHRONOUSLY_DEFAULT);
    }

    /**
     * Shortcut for finding the boolean value for {@link #DIRECTIVE_TIMEOUT}
     * directive using the given headers.
     * 
     * Assumes the headers belong to a Spring powered bundle. Returns the
     * timeout (in seconds) for which the application context should wait to
     * have its dependencies satisfied.
     * 
     * @param headers
     * @return
     */
    public static long getTimeOut(Dictionary headers) {
        String value = getDirectiveValue(headers, DIRECTIVE_TIMEOUT);

        if (value != null) {
            if (DIRECTIVE_TIMEOUT_VALUE_NONE.equalsIgnoreCase(value)) {
                return DIRECTIVE_NO_TIMEOUT;
            }
            return Long.valueOf(value);
        }

        return DIRECTIVE_TIMEOUT_DEFAULT;
    }

    /**
     * Shortcut for finding the boolean value for
     * {@link #DIRECTIVE_WAIT_FOR_DEPS} directive using the given headers.
     * Assumes the headers belong to a Spring powered bundle.
     * 
     * @param headers
     * @return
     */
    public static boolean getWaitForDependencies(Dictionary headers) {
        String value = getDirectiveValue(headers, DIRECTIVE_WAIT_FOR_DEPS);

        return (value != null ? Boolean.valueOf(value) : DIRECTIVE_WAIT_FOR_DEPS_DEFAULT);
    }

    /**
     * Returns the location headers (if any) specified by the Spring-Context
     * header (if available). The returned Strings can be sent to a
     * {@link org.springframework.core.io.ResourceLoader} for loading the
     * configurations.
     * 
     * @param headers bundle headers
     * @return array of locations specified (if any)
     */
    public static String[] getHeaderLocations(Dictionary headers) {
        return getLocationsFromHeader(getSpringContextHeader(headers),
                OsgiBundleXmlApplicationContext.DEFAULT_CONFIG_LOCATION);

    }

    /**
     * Similar to {@link #getHeaderLocations(Dictionary)} but looks at a
     * specified header directly.
     * 
     * @param header header to look at
     * @param defaultValue default locations if none is specified
     * @return
     */
    public static String[] getLocationsFromHeader(String header, String defaultValue) {

        String[] ctxEntries;
        if (StringUtils.hasText(header) && !(';' == header.charAt(0))) {
            // get the config locations
            String locations = StringUtils.tokenizeToStringArray(header, DIRECTIVE_SEPARATOR)[0];
            // parse it into individual token
            ctxEntries = StringUtils.tokenizeToStringArray(locations, CONTEXT_LOCATION_SEPARATOR);

            // replace * with a 'digestable' location
            for (int i = 0; i < ctxEntries.length; i++) {
                if (CONFIG_WILDCARD.equals(ctxEntries[i]))
                    ctxEntries[i] = defaultValue;
            }
        } else {
            ctxEntries = new String[0];
        }

        return ctxEntries;
    }
}