Package org.apache.sling.crankstart.extensions.sling

Source Code of org.apache.sling.crankstart.extensions.sling.CrankstartInventoryPrinter

/*
* 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.extensions.sling;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;

import org.apache.commons.io.IOUtils;
import org.apache.felix.cm.file.ConfigurationHandler;
import org.apache.felix.inventory.Format;
import org.apache.felix.inventory.InventoryPrinter;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.startlevel.StartLevel;

@Component
@Service
@Properties({
    @Property(name = "felix.inventory.printer.name", value = "crankstart"),
    @Property(name = "felix.inventory.printer.title", value = "Sling Crankstart Exporter"),
    @Property(name = "felix.inventory.printer.format", value = "TEXT")
})
public class CrankstartInventoryPrinter implements InventoryPrinter {

    private BundleContext bundleContext;
    private static final String INDENT = "  ";
   
    @Reference
    private StartLevel startLevel;
   
    // Properties to ignore when dumping configs
    private static final String [] PROPS_TO_IGNORE = {
        Constants.SERVICE_PID,
        "service.factoryPid"
    };
   
    @Activate
    public void activate(ComponentContext ctx) {
        bundleContext = ctx.getBundleContext();
    }
   
    public void print(PrintWriter out, Format fmt, boolean isZip) {
        try {
            includeResource(out, "/crankstart-header.txt");
            header(out, "bundles");
            bundles(out);
            header(out, "configurations");
            configs(out);
            header(out, "end of " + getClass().getSimpleName() + " status dump");
        } catch(Exception e) {
            e.printStackTrace(out);
        }
    }
   
    private void configs(PrintWriter out) throws IOException {
        final ServiceReference ref = bundleContext.getServiceReference(ConfigurationAdmin.class.getName());
        if(ref == null) {
            out.println("WARN - ConfigurationAdmin service not available");
            return;
        }
       
        out.println("# The CRANKSTART_CONFIG_ID property that we add to configs is meant to detect which factory configs have already been created");
       
        final ConfigurationAdmin ca = (ConfigurationAdmin)bundleContext.getService(ref);
        try {
            final Configuration [] allCfg = ca.listConfigurations(null);
            int count = 0;
            if(allCfg != null) {
                for(Configuration cfg : allCfg) {
                    count++;
                    if(cfg.getFactoryPid() != null && cfg.getFactoryPid().length() > 0) {
                        out.print("config.factory ");
                        out.print(cfg.getFactoryPid());
                    } else {
                        out.print("config ");
                        out.print(cfg.getPid());
                    }
                    out.println(" FORMAT:felix.config");
                   
                    out.print(INDENT);
                    out.print("CRANKSTART_CONFIG_ID=\"");
                    out.print(UUID.randomUUID());
                    out.println("\"");
                   
                    // Need to indent the config properties
                    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    ConfigurationHandler.write(bos, cfg.getProperties());
                    final BufferedReader r = new BufferedReader(new StringReader(new String(bos.toString())));
                    String line = null;
                   
                    readingLines:
                    while((line = r.readLine()) != null) {
                        for(String p : PROPS_TO_IGNORE) {
                            if(line.startsWith(p)) {
                                continue readingLines;
                            }
                        }
                        out.print(INDENT);
                        out.println(line);
                    }
                    out.println();
                }
            }
            out.print("# ");
            out.print(count);
            out.println(" configurations processed");
        } catch(InvalidSyntaxException ise) {
            throw new RuntimeException("Unexpected InvalidSyntaxException", ise);
        } finally {
            bundleContext.ungetService(ref);
        }
    }
   
    private void bundles(PrintWriter out) throws IOException {
        for(int i=1; i<=startLevel.getStartLevel(); i++) {
            bundles(out, i);
        }
    }
   
    private void bundles(PrintWriter out, int level) throws IOException {
        int ok = 0;
        int errors = 0;
        int warnings = 0;
        int count = 0;
       
        // Get the list of Maven coordinates from any fragment bundles,
        // so that we can ignore their entries when returned by the
        // bundles that they are attached to
        final Set<String> fragmentCoords = new TreeSet<String>();
        for(Bundle b : bundleContext.getBundles()) {
            if(isFragment(b)) {
                final List<String> coords = getMavenCoordinates(b, null);
                if(coords.size() > 1) {
                    warnings++;
                    multipleWarning(out, b, coords);
                } else {
                    fragmentCoords.add(coords.get(0));
                }
            }
        }
       
        for(Bundle b : bundleContext.getBundles()) {
            if(startLevel.getBundleStartLevel(b) != level) {
                continue;
            }
           
            if(count==0) {
                out.println();
                out.print("# bundles for start level ");
                out.println(level);
            }
            count++;
           
            final List<String> coords = getMavenCoordinates(b, fragmentCoords);
            if(coords.isEmpty()) {
                errors++;
                out.print("# ERROR: Maven coordinates not found for ");
                out.print(getBundleInfo(b));
                out.println();
            } else if(coords.size() > 1){
                warnings++;
                multipleWarning(out, b, coords);
            } else {
                ok++;
                out.print("bundle ");
                out.println(coords.get(0));
            }
        }
       
        if(count > 0) {
            out.println();
            out.print("# ");
            out.print("start level ");
            out.print(level);
            out.print(": ");
            out.print(ok);
            out.print(" bundles processed sucessfully, ");
            out.print(errors);
            out.print(" errors, ");
            out.print(warnings);
            out.print(" warnings.");
            out.println();
            out.println("start.all.bundles");
        }
    }
   
    private void multipleWarning(PrintWriter out, Bundle b, List<String> coords) {
        out.print("# WARN: multiple Maven coordinates for ");
        out.print(getBundleInfo(b));
        out.print(": ");
        out.print(coords);
        out.println();
    }
   
    private static boolean isFragment(final Bundle bundle) {
        Dictionary<?, ?> headerMap = bundle.getHeaders();
        return headerMap.get(Constants.FRAGMENT_HOST) != null;
    }
   
    private List<String> getMavenCoordinates(Bundle b, Collection<String> fragmentCoordinates) throws IOException {
        final List<String> result = new ArrayList<String>();
       
        @SuppressWarnings("unchecked")
        final Enumeration<URL> entries = b.findEntries("META-INF/maven", "pom.properties", true);
       
        // Get the pom.properties from the bundle itself, ignoring any attached fragments
        while(entries != null && entries.hasMoreElements()) {
            final URL u = entries.nextElement();
            java.util.Properties props = new java.util.Properties();
            InputStream is = null;
            try {
                is = u.openStream();
                props.load(is);
                final StringBuilder thisBundle = new StringBuilder();
                thisBundle.append("mvn:")
                .append(props.get("groupId"))
                .append("/")
                .append(props.get("artifactId"))
                .append("/")
                .append(props.get("version"));
               
                if(fragmentCoordinates != null && !isFragment(b) && fragmentCoordinates.contains(thisBundle.toString())) {
                    // fragment bundle - ignore
                } else {
                    result.add(thisBundle.toString());
                }
            } finally {
                IOUtils.closeQuietly(is);
            }
        }
       
        return result;
    }
   
    private static String getBundleInfo(Bundle b) {
        final StringBuilder sb = new StringBuilder();
        sb.append("bundle ")
        .append(b.getSymbolicName())
        .append(" ")
        .append(b.getVersion())
        .append(" (")
        .append(b.getBundleId())
        .append(")");
        return sb.toString();
    }
   
    private void header(PrintWriter out, String title) {
        out.println();
        out.print("# ");
        out.println(title);
    }
   
    private void includeResource(PrintWriter out, String path) throws IOException {
        final InputStream resource = getClass().getResourceAsStream(path);
        if(resource == null) {
            throw new IOException("Resource not found: " + path);
        }
        try {
            IOUtils.copy(resource, out);
        } finally {
            resource.close();
        }
    }   
}
TOP

Related Classes of org.apache.sling.crankstart.extensions.sling.CrankstartInventoryPrinter

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.