org.apache.sling.maven.projectsupport.BundleListContentProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.sling.maven.projectsupport.BundleListContentProvider.java

Source

/*
 * 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.maven.projectsupport;

import static org.apache.sling.maven.projectsupport.AbstractUsingBundleListMojo.BUNDLE_PATH_PREFIX;
import static org.apache.sling.maven.projectsupport.AbstractUsingBundleListMojo.CONFIG_PATH_PREFIX;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.commons.io.FilenameUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.sling.launchpad.api.LaunchpadContentProvider;
import org.apache.sling.maven.projectsupport.bundlelist.v1_0_0.Bundle;
import org.apache.sling.maven.projectsupport.bundlelist.v1_0_0.BundleList;
import org.apache.sling.maven.projectsupport.bundlelist.v1_0_0.StartLevel;

/** LaunchpadContentProvider that provides resources based on a BundleList
 *  and other resources specific to this module.
 */
abstract class BundleListContentProvider implements LaunchpadContentProvider {

    public static final String INSTALL_PATH_PREFIX = "resources/install";
    public static final int BOOTSTRAP_DEF_START_LEVEL = -1;
    public static final int ACTUAL_BOOTSTRAP_START_LEVEL = 1;

    private final File resourceProviderRoot;
    private final static List<String> EMPTY_STRING_LIST = Collections.emptyList();

    BundleListContentProvider(File resourceProviderRoot) {
        this.resourceProviderRoot = resourceProviderRoot;
    }

    private Iterator<String> handleBundlePathRoot(String path) {
        final Set<String> levels = new HashSet<String>();
        for (final StartLevel level : getInitializedBundleList().getStartLevels()) {
            // Include only bootstrap bundles here, with start level 1.
            // Other bundles go under the install folder, to support run modes
            if (level.getStartLevel() == BOOTSTRAP_DEF_START_LEVEL) {
                levels.add(BUNDLE_PATH_PREFIX + "/" + ACTUAL_BOOTSTRAP_START_LEVEL + "/");
            }
        }
        return levels.iterator();
    }

    private Iterator<String> handleConfigPath() {
        if (getConfigDirectory().exists() && getConfigDirectory().isDirectory()) {
            File[] configFiles = getConfigDirectory().listFiles();

            List<String> fileNames = new ArrayList<String>();
            for (File cfgFile : configFiles) {
                fileNames.add(CONFIG_PATH_PREFIX + "/" + cfgFile.getName());
            }

            return fileNames.iterator();

        } else {
            return EMPTY_STRING_LIST.iterator();
        }
    }

    private Iterator<String> handleBundlesSubfolder(String path) {
        Iterator<String> result = null;
        final String startLevelInfo = path.substring(BUNDLE_PATH_PREFIX.length() + 1);
        try {
            final int startLevel = Integer.parseInt(startLevelInfo);

            // To be consistent with handleBundlePathRoot, consider only level 1 which
            // is assigned to bootstrap bundles
            if (startLevel == ACTUAL_BOOTSTRAP_START_LEVEL) {
                final List<String> bundles = new ArrayList<String>();
                addBundles(bundles, ACTUAL_BOOTSTRAP_START_LEVEL, null);
                addBundles(bundles, BOOTSTRAP_DEF_START_LEVEL, null);
                result = bundles.iterator();
            }

        } catch (NumberFormatException e) {
            getLog().warn("Invalid start level " + startLevelInfo + " in path " + path);
        }

        return result;
    }

    private void addBundles(Collection<String> bundles, int startLevel, String runMode) {
        for (final StartLevel level : getInitializedBundleList().getStartLevels()) {
            if (level.getStartLevel() == startLevel) {
                for (final Bundle bundle : level.getBundles()) {
                    if (!runModeMatches(bundle, runMode)) {
                        continue;
                    }
                    final ArtifactDefinition d = new ArtifactDefinition(bundle, startLevel);
                    try {
                        final Artifact artifact = getArtifact(d);
                        bundles.add(artifact.getFile().toURI().toURL().toExternalForm());
                    } catch (Exception e) {
                        getLog().error("Unable to resolve artifact ", e);
                    }
                }
            }
        }
    }

    private boolean runModeMatches(Bundle b, String runMode) {
        if (runMode == null || runMode.length() == 0) {
            return b.getRunModes() == null || b.getRunModes().length() == 0;
        } else {
            return b.getRunModes() != null && b.getRunModes().contains(runMode);
        }
    }

    private Iterator<String> handleResourcesRoot() {
        final Set<String> subDirs = new HashSet<String>();
        subDirs.add(BUNDLE_PATH_PREFIX);
        subDirs.add(CONFIG_PATH_PREFIX);
        subDirs.add("resources/corebundles");
        subDirs.add(INSTALL_PATH_PREFIX);

        // Compute the set of run modes in our bundles
        final Set<String> runModes = new HashSet<String>();
        for (final StartLevel level : getInitializedBundleList().getStartLevels()) {
            for (Bundle bundle : level.getBundles()) {
                final String modes = bundle.getRunModes();
                if (modes != null && modes.length() > 0) {
                    for (String m : modes.split(",")) {
                        runModes.add("." + m);
                    }
                }
            }
        }

        // Add one install subdir per run mode
        for (String m : runModes) {
            subDirs.add(INSTALL_PATH_PREFIX + m);
        }
        return subDirs.iterator();
    }

    /** Add one folder per child, using given path as prefix, for start
     *  levels which actually provide bundles for the given run mode.
     */
    private void addStartLevelSubdirs(Collection<String> children, String path, String runMode) {
        for (final StartLevel level : getInitializedBundleList().getStartLevels()) {
            final List<String> bundles = new ArrayList<String>();
            addBundles(bundles, level.getStartLevel(), runMode);
            if (!bundles.isEmpty()) {
                int folderLevel = level.getStartLevel();
                if (folderLevel == BOOTSTRAP_DEF_START_LEVEL) {
                    folderLevel = ACTUAL_BOOTSTRAP_START_LEVEL;
                }
                children.add(path + "/" + folderLevel);
            }
        }
    }

    private Iterator<String> handleInstallPath(String path) {
        // Path is like
        // bundles/install.runMode/12
        // or a subset of that.
        // Extract optional run mode and start level from that
        if (path.endsWith("/")) {
            path = path.substring(0, path.length() - 1);
        }
        final String[] parts = path.substring(INSTALL_PATH_PREFIX.length()).split("/");
        if (parts.length > 2) {
            throw new IllegalStateException("Cannot parse path " + path);
        }
        final String runMode = parts[0].length() == 0 ? null : parts[0].substring(1);
        final String startLevelInfo = parts.length > 1 ? parts[1] : null;
        Set<String> result = new HashSet<String>();

        if (runMode == null && startLevelInfo == null) {
            // Root folder: add one subdir per start level that provides bundles
            addStartLevelSubdirs(result, INSTALL_PATH_PREFIX, null);

        } else if (startLevelInfo == null) {
            // The root of a run mode folder - one subdir per start
            // level which actually provides bundles
            addStartLevelSubdirs(result, path, runMode);

        } else {
            // A folder that contains bundles
            try {
                addBundles(result, Integer.parseInt(startLevelInfo), runMode);
            } catch (NumberFormatException e) {
                getLog().warn("Invalid start level info " + startLevelInfo + " in path " + path);
            }
        }

        return result.iterator();
    }

    private Iterator<String> handleConfigSubpath(String path) {
        final File f = getConfigFile(path);
        if (!f.exists()) {
            getLog().warn("BundleListContentProvider cannot get children of config path: " + path);
            return EMPTY_STRING_LIST.iterator();
        }

        if (f.isFile()) {
            return EMPTY_STRING_LIST.iterator();
        }

        File[] configFiles = f.listFiles();
        List<String> fileNames = new ArrayList<String>();
        for (File cfgFile : configFiles) {
            fileNames.add(path + "/" + cfgFile.getName());
        }

        return fileNames.iterator();
    }

    private File getConfigFile(String path) {
        return new File(FilenameUtils.concat(getConfigDirectory().getAbsolutePath(),
                path.substring(CONFIG_PATH_PREFIX.length() + 1)));
    }

    public Iterator<String> getChildren(String path) {
        Iterator<String> result = null;
        if (path.equals(BUNDLE_PATH_PREFIX)) {
            result = handleBundlePathRoot(path);
        } else if (path.equals("resources/corebundles")) {
            result = EMPTY_STRING_LIST.iterator();
        } else if (path.equals(CONFIG_PATH_PREFIX)) {
            result = handleConfigPath();
        } else if (path.startsWith(CONFIG_PATH_PREFIX)) {
            result = handleConfigSubpath(path);
        } else if (path.startsWith(BUNDLE_PATH_PREFIX)) {
            result = handleBundlesSubfolder(path);
        } else if (path.startsWith(INSTALL_PATH_PREFIX)) {
            result = handleInstallPath(path);
        } else if (path.equals("resources")) {
            result = handleResourcesRoot();
        } else if (path.startsWith("file:")) {
            // Client looks for files under a file - we have none,
            // as our file URLs point to Maven artifacts
            result = EMPTY_STRING_LIST.iterator();
        } else {
            getLog().warn("BundleListContentProvider cannot get children of path: " + path);
        }

        return result;
    }

    public URL getResource(String path) {
        if (path.startsWith(CONFIG_PATH_PREFIX)) {
            final File configFile = getConfigFile(path);
            if (configFile.exists()) {
                try {
                    return configFile.toURI().toURL();
                } catch (MalformedURLException e) {
                    // ignore this one
                }
            }
        }

        File resourceFile = new File(resourceProviderRoot, path);
        if (resourceFile.exists()) {
            try {
                return resourceFile.toURI().toURL();
            } catch (MalformedURLException e) {
                getLog().error("Unable to create URL for file", e);
                return null;
            }
        } else {
            URL fromClasspath = getClass().getResource("/" + path);
            if (fromClasspath != null) {
                return fromClasspath;
            }

            try {
                return new URL(path);
            } catch (MalformedURLException e) {
                return null;
            }
        }

    }

    public InputStream getResourceAsStream(String path) {
        URL res = this.getResource(path);
        if (res != null) {
            try {
                return res.openStream();
            } catch (IOException ioe) {
                // ignore this one
            }
        }

        // no resource
        return null;
    }

    abstract BundleList getInitializedBundleList();

    abstract File getConfigDirectory();

    abstract Artifact getArtifact(ArtifactDefinition def) throws MojoExecutionException;

    abstract Log getLog();
}