Package org.apache.sling.crankstart.core.commands

Source Code of org.apache.sling.crankstart.core.commands.Configure

/*
* 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.crankstart.core.commands;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;

import org.apache.felix.cm.file.ConfigurationHandler;
import org.apache.sling.crankstart.api.CrankstartCommand;
import org.apache.sling.crankstart.api.CrankstartCommandLine;
import org.apache.sling.crankstart.api.CrankstartContext;
import org.apache.sling.crankstart.api.CrankstartException;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.cm.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** CrankstartCommand that creates OSGi configurations */
public class Configure implements CrankstartCommand {
    public static final String I_CONFIGURE = "config";
    public static final String FACTORY_SUFFIX = ".factory";
    public static final String FELIX_FORMAT_SUFFIX = "FORMAT:felix.config";
    private final Logger log = LoggerFactory.getLogger(getClass());
   
    /** Config factory definitions can include this property to define a unique
     *  ID that avoids recreating them if the crankstart file runs several
     *  times.
     */
    public static final String CRANKSTART_CONFIG_ID = "CRANKSTART_CONFIG_ID";
   
    @Override
    public boolean appliesTo(CrankstartCommandLine commandLine) {
        return commandLine.getVerb().startsWith(I_CONFIGURE);
    }
   
    public String getDescription() {
        return I_CONFIGURE + " or " + I_CONFIGURE + FACTORY_SUFFIX + ": create OSGi configurations";
    }

    @Override
    @SuppressWarnings("rawtypes")
    public void execute(CrankstartContext crankstartContext, CrankstartCommandLine commandLine) throws Exception {
       
        // Configs can be in our plain format or in Felix .config format, which supports various data types
        String pid = null;
        boolean felixFormat = false;
        if(commandLine.getQualifier().endsWith(FELIX_FORMAT_SUFFIX)) {
            felixFormat = true;
            pid = commandLine.getQualifier().split(" ")[0].trim();
        } else {
            pid = commandLine.getQualifier();
        }
       
        Dictionary<String, Object> properties = commandLine.getProperties();
        if(felixFormat) {
            properties = parseFelixConfig(properties);
        }
        final BundleContext bundleContext = crankstartContext.getOsgiFramework().getBundleContext();
       
        // TODO: wait for configadmin service?
        final String CONFIG_ADMIN_CLASS = "org.osgi.service.cm.ConfigurationAdmin";
        final ServiceReference configAdminRef = bundleContext.getServiceReference(CONFIG_ADMIN_CLASS);
        if(configAdminRef == null) {
            throw new IllegalStateException("Required service is missing:" + CONFIG_ADMIN_CLASS);
        }
       
        @SuppressWarnings("unchecked")
        final Object configAdminService = bundleContext.getService(configAdminRef);
       
        // Use reflection to minimize coupling with the OSGi framework that we are talking to
        Object config = null;
        if(commandLine.getVerb().endsWith(FACTORY_SUFFIX)) {
            config = getExistingConfig(configAdminService, pid, properties);
            if(config == null) {
                config = configAdminService.getClass()
                        .getMethod("createFactoryConfiguration", String.class)
                        .invoke(configAdminService, pid);
            }
        } else {
            config = configAdminService.getClass()
                    .getMethod("getConfiguration", String.class)
                    .invoke(configAdminService, pid);
        }
        config.getClass()
            .getMethod("setBundleLocation", String.class)
            .invoke(config, (String)null);
        config.getClass()
            .getMethod("update", Dictionary.class)
            .invoke(config, properties);
        log.info("Updated configuration {}: {}", pid, properties);
    }
   
    /** Return existing config if we have one for the specified factory, which has the same
     *  CRANKSTART_CONFIG_ID as specified in properties.
     */
    Object getExistingConfig(Object configAdminService, String factoryPid, Dictionary<String, Object> properties) throws Exception {
        final Object o = properties.get(CRANKSTART_CONFIG_ID);
        if(o == null || !(o instanceof String)) {
            log.info("Factory config does not specify {}, might be created multiple times", CRANKSTART_CONFIG_ID);
            return null;
        }
       
        final String id = (String)o;
        final String filter = "(&(service.factoryPid=" + factoryPid + ")(" + CRANKSTART_CONFIG_ID + "=" + id + "))";
        final Object [] c = (Object [])configAdminService.getClass()
                .getMethod("listConfigurations", String.class)
                .invoke(configAdminService, filter);
        Object result = null;
        if(c!=null && c.length > 0) {
            if(c.length > 1) {
                // Shouldn't have more than one of those configs
                throw new CrankstartException("Found " + c.length + " configs with " + CRANKSTART_CONFIG_ID + "=" + id);
            }
            result = c[0];
        }
        return result;
    }
   
    @SuppressWarnings("unchecked")
    private Dictionary<String, Object> parseFelixConfig(Dictionary<String, Object> properties) {
        // Build a stream in Felix .config format and parse it
        if(properties == null) {
            return new Hashtable<String, Object>();
        }
       
        final StringBuilder sb = new StringBuilder();
        final Enumeration<String> keys = properties.keys();
        while(keys.hasMoreElements()) {
            final String key = keys.nextElement();
            final Object value = properties.get(key);
            sb.append(key).append("=").append(value).append("\n");
        }
       
        try {
            final InputStream is = new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
            try {
                return ConfigurationHandler.read(is);
            } finally {
                is.close();
            }
        } catch(IOException ioe) {
            throw new CrankstartException("Parsing error (Felix format config) for\n" + sb, ioe);
        }
    }
}
TOP

Related Classes of org.apache.sling.crankstart.core.commands.Configure

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.