org.ops4j.pax.scanner.dir.internal.DirScanner.java Source code

Java tutorial

Introduction

Here is the source code for org.ops4j.pax.scanner.dir.internal.DirScanner.java

Source

/*
 * Copyright 2007 Alin Dreghiciu.
 *
 * Licensed  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.ops4j.pax.scanner.dir.internal;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.zip.ZipFile;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ops4j.io.DirectoryLister;
import org.ops4j.io.Lister;
import org.ops4j.io.ZipLister;
import org.ops4j.lang.NullArgumentException;
import org.ops4j.pax.scanner.MalformedSpecificationException;
import org.ops4j.pax.scanner.ProvisionSpec;
import org.ops4j.pax.scanner.ScannedBundle;
import org.ops4j.pax.scanner.Scanner;
import org.ops4j.pax.scanner.ScannerException;
import org.ops4j.pax.scanner.common.ScannedFileBundle;
import org.ops4j.pax.scanner.common.ScannerConfiguration;
import org.ops4j.pax.scanner.common.ScannerConfigurationImpl;
import org.ops4j.pax.scanner.dir.ServiceConstants;
import org.ops4j.util.property.PropertyResolver;

/**
 * A scanner that scans directory content for bundles.
 *
 * @author Alin Dreghiciu
 * @since September 04, 2007
 */
public class DirScanner implements Scanner {

    /**
     * Logger.
     */
    private static final Log LOGGER = LogFactory.getLog(DirScanner.class);
    /**
     * PropertyResolver used to resolve properties.
     */
    private PropertyResolver m_propertyResolver;

    /**
     * Creates a new file scanner.
     *
     * @param propertyResolver a propertyResolver; mandatory
     */
    public DirScanner(final PropertyResolver propertyResolver) {
        NullArgumentException.validateNotNull(propertyResolver, "PropertyResolver");
        m_propertyResolver = propertyResolver;
    }

    /**
     * Reads the bundles from the file specified by the urlSpec.
     * {@inheritDoc}
     */
    public List<ScannedBundle> scan(final ProvisionSpec provisionSpec)
            throws MalformedSpecificationException, ScannerException {
        NullArgumentException.validateNotNull(provisionSpec, "Provision spec");

        LOGGER.debug("Scanning [" + provisionSpec.getPath() + "]");
        final ScannerConfiguration config = createConfiguration();
        final Pattern filter = provisionSpec.getFilterPattern();
        final String spec = provisionSpec.getPath();
        final Integer defaultStartLevel = getDefaultStartLevel(provisionSpec, config);
        final Boolean defaultStart = getDefaultStart(provisionSpec, config);
        final Boolean defaultUpdate = getDefaultUpdate(provisionSpec, config);
        // try out an url
        LOGGER.trace("Searching for [" + spec + "]");
        URL url = null;
        try {
            url = new URL(spec);
        } catch (MalformedURLException ignore) {
            // ignore this as the spec may be resolved other way
            LOGGER.trace("Specification is not a valid url: " + ignore.getMessage() + ". Continue discovery...");
        }
        File file = null;
        if (url != null && "file".equals(url.getProtocol()))
        // if we have an url and it's a file url
        {
            try {
                final URI uri = new URI(url.toExternalForm().replaceAll(" ", "%20"));
                file = new File(uri);
            } catch (Exception ignore) {
                // ignore this as the spec may be resolved other way
                LOGGER.trace("Specification is not a valid file url: " + ignore.getMessage()
                        + ". Continue discovery...");
            }
        } else
        // if we don't have an url then let's try out a direct file
        {
            file = new File(spec);
        }
        if (file != null && file.exists())
        // if we have a directory
        {
            if (file.isDirectory()) {
                try {
                    return list(new DirectoryLister(file, filter), defaultStartLevel, defaultStart, defaultUpdate);
                } catch (MalformedURLException e) {
                    throw new MalformedSpecificationException(e);
                }
            } else {
                LOGGER.trace("Specification is not a directory. Continue discovery...");
            }
        } else {
            LOGGER.trace("Specification is not a valid file. Continue discovery...");
        }
        // on this point we may have a zip
        try {
            ZipFile zip = null;
            URL baseUrl = null;
            if (file != null && file.exists())
            // try out a zip from the file we have
            {
                zip = new ZipFile(file);
                baseUrl = file.toURL();
            } else if (url != null) {
                zip = new ZipFile(url.toExternalForm());
                baseUrl = url;
            }
            if (zip != null && baseUrl != null) {
                try {
                    return list(new ZipLister(baseUrl, zip.entries(), filter), defaultStartLevel, defaultStart,
                            defaultUpdate);
                } catch (MalformedURLException e) {
                    throw new MalformedSpecificationException(e);
                }
            }
        } catch (IOException ignore) {
            // ignore for the moment
            LOGGER.trace("Specification is not a valid zip: " + ignore.getMessage() + "Continue discovery...");
        }
        // finaly try with a zip protocol
        if (url != null && !url.toExternalForm().startsWith("jar")) {
            try {
                final URL jarUrl = new URL("jar:" + url.toURI().toASCIIString() + "!/");
                final JarURLConnection jar = (JarURLConnection) jarUrl.openConnection();
                return list(new ZipLister(url, jar.getJarFile().entries(), filter), defaultStartLevel, defaultStart,
                        defaultUpdate);
            } catch (Exception ignore) {
                LOGGER.trace("Specification is not a valid jar: " + ignore.getMessage());
            }
        }
        // if we got to this point then we cannot go further
        LOGGER.trace("Specification urlSpec cannot be used. Stopping.");
        throw new MalformedSpecificationException(
                "Specification [" + provisionSpec.getPath() + "] could not be used");
    }

    /**
     * Create scanned bundles based on the provided lister.
     *
     * @param lister      source of bundles
     * @param startLevel  default start level to use
     * @param shouldStart if by default should start
     * @param update      if by default should be updated
     *
     * @return a list of scanned bundles from the provided source
     *
     * @throws java.net.MalformedURLException re-thrown
     */
    private List<ScannedBundle> list(final Lister lister, final Integer startLevel, final Boolean shouldStart,
            final Boolean update) throws MalformedURLException {
        final List<ScannedBundle> scannedBundles = new ArrayList<ScannedBundle>();
        final List<URL> urls = lister.list();
        if (urls != null) {
            for (URL url : urls) {
                final ScannedFileBundle scannedFileBundle = new ScannedFileBundle(url.toExternalForm(), startLevel,
                        shouldStart, update);
                scannedBundles.add(scannedFileBundle);
                LOGGER.debug("Installing bundle [" + scannedFileBundle + "]");
            }
        }
        return scannedBundles;
    }

    /**
     * Returns the default start level by first looking at the parser and if not set fallback to configuration.
     *
     * @param provisionSpec provision spec
     * @param config        a configuration
     *
     * @return default start level or null if nos set.
     */
    private Integer getDefaultStartLevel(ProvisionSpec provisionSpec, ScannerConfiguration config) {
        Integer startLevel = provisionSpec.getStartLevel();
        if (startLevel == null) {
            startLevel = config.getStartLevel();
        }
        return startLevel;
    }

    /**
     * Returns the default start by first looking at the parser and if not set fallback to configuration.
     *
     * @param provisionSpec provision spec
     * @param config        a configuration
     *
     * @return default start level or null if not set.
     */
    private Boolean getDefaultStart(final ProvisionSpec provisionSpec, final ScannerConfiguration config) {
        Boolean start = provisionSpec.shouldStart();
        if (start == null) {
            start = config.shouldStart();
        }
        return start;
    }

    /**
     * Returns the default update by first looking at the parser and if not set fallback to configuration.
     *
     * @param provisionSpec provision spec
     * @param config        a configuration
     *
     * @return default update or null if not set.
     */
    private Boolean getDefaultUpdate(final ProvisionSpec provisionSpec, final ScannerConfiguration config) {
        Boolean update = provisionSpec.shouldUpdate();
        if (update == null) {
            update = config.shouldUpdate();
        }
        return update;
    }

    /**
     * Sets the propertyResolver to use.
     *
     * @param propertyResolver a propertyResolver
     */
    public void setResolver(final PropertyResolver propertyResolver) {
        NullArgumentException.validateNotNull(propertyResolver, "PropertyResolver");
        m_propertyResolver = propertyResolver;
    }

    /**
     * Configuration factory method.
     *
     * @return a configuration
     */
    ScannerConfiguration createConfiguration() {
        return new ScannerConfigurationImpl(m_propertyResolver, ServiceConstants.PID);
    }

}