Package org.apache.sling.fsprovider.internal

Source Code of org.apache.sling.fsprovider.internal.FsResourceProvider

/*
* 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.fsprovider.internal;

import java.io.File;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;

import javax.servlet.http.HttpServletRequest;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.ConfigurationPolicy;
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.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceProvider;
import org.apache.sling.api.resource.ResourceResolver;
import org.osgi.framework.BundleContext;
import org.osgi.service.event.EventAdmin;

/**
* The <code>FsResourceProvider</code> is a resource provider which maps
* filesystem files and folders into the virtual resource tree. The provider is
* implemented in terms of a component factory, that is multiple instances of
* this provider may be created by creating respective configuration.
* <p>
* Each provider instance is configured with two properties: The location in the
* resource tree where resources are provided ({@link ResourceProvider#ROOTS})
* and the file system path from where files and folders are mapped into the
* resource ({@link #PROP_PROVIDER_FILE}).
*/
@Component(
        name="org.apache.sling.fsprovider.internal.FsResourceProvider",
        label="%resource.resolver.name",
        description="%resource.resolver.description",
        configurationFactory=true,
        policy=ConfigurationPolicy.REQUIRE,
        metatype=true
        )
@Service(ResourceProvider.class)
@Properties({
    @Property(name="service.description", value="Sling Filesystem Resource Provider"),
    @Property(name="service.vendor", value="The Apache Software Foundation"),
    @Property(name=ResourceProvider.ROOTS)
})
public class FsResourceProvider implements ResourceProvider {

    /**
     * The name of the configuration property providing file system path of
     * files and folders mapped into the resource tree (value is
     * "provider.file").
     */
    @Property
    public static final String PROP_PROVIDER_FILE = "provider.file";

    /**
     * The name of the configuration property providing the check interval
     * for file changes (value is "provider.checkinterval").
     */
    @Property(longValue=FsResourceProvider.DEFAULT_CHECKINTERVAL)
    public static final String PROP_PROVIDER_CHECKINTERVAL = "provider.checkinterval";

    public static final long DEFAULT_CHECKINTERVAL = 1000;

    // The location in the resource tree where the resources are mapped
    private String providerRoot;

    // providerRoot + "/" to be used for prefix matching of paths
    private String providerRootPrefix;

    // The "root" file or folder in the file system
    private File providerFile;

    /** The monitor to detect file changes. */
    private FileMonitor monitor;

    @Reference(cardinality=ReferenceCardinality.OPTIONAL_UNARY, policy=ReferencePolicy.DYNAMIC)
    private volatile EventAdmin eventAdmin;

    /**
     * Same as {@link #getResource(ResourceResolver, String)}, i.e. the
     * <code>request</code> parameter is ignored.
     *
     * @see #getResource(ResourceResolver, String)
     */
    public Resource getResource(ResourceResolver resourceResolver,
            HttpServletRequest request, String path) {
        return getResource(resourceResolver, path);
    }

    /**
     * Returns a resource wrapping a filesystem file or folder for the given
     * path. If the <code>path</code> is equal to the configured resource tree
     * location of this provider, the configured file system file or folder is
     * used for the resource. Otherwise the configured resource tree location
     * prefix is removed from the path and the remaining relative path is used
     * to access the file or folder. If no such file or folder exists, this
     * method returns <code>null</code>.
     */
    public Resource getResource(ResourceResolver resourceResolver, String path) {
        return getResource(resourceResolver, path, getFile(path));
    }

    /**
     * Returns an iterator of resources.
     */
    public Iterator<Resource> listChildren(Resource parent) {
        File parentFile = parent.adaptTo(File.class);

        // not a FsResource, try to create one from the resource
        if (parentFile == null) {
            // if the parent path is at or below the provider root, get
            // the respective file
            parentFile = getFile(parent.getPath());

            // if the parent path is actually the parent of the provider
            // root, return a single element iterator just containing the
            // provider file, unless the provider file is a directory and
            // a repository item with the same path actually exists
            if (parentFile == null) {

                String parentPath = parent.getPath().concat("/");
                if (providerRoot.startsWith(parentPath)) {
                    String relPath = providerRoot.substring(parentPath.length());
                    if (relPath.indexOf('/') < 0) {
                        Resource res = getResource(
                                parent.getResourceResolver(), providerRoot,
                                providerFile);
                        if (res != null) {
                            return Collections.singletonList(res).iterator();
                        }
                    }
                }

                // no children here
                return null;
            }
        }

        final File[] children = parentFile.listFiles();

        if (children != null && children.length > 0) {
            final ResourceResolver resolver = parent.getResourceResolver();
            final String parentPath = parent.getPath();
            return new Iterator<Resource>() {
                int index = 0;

                Resource next = seek();

                public boolean hasNext() {
                    return next != null;
                }

                public Resource next() {
                    if (!hasNext()) {
                        throw new NoSuchElementException();
                    }

                    Resource result = next;
                    next = seek();
                    return result;
                }

                public void remove() {
                    throw new UnsupportedOperationException("remove");
                }

                private Resource seek() {
                    while (index < children.length) {
                        File file = children[index++];
                        String path = parentPath + "/" + file.getName();
                        Resource result = getResource(resolver, path, file);
                        if (result != null) {
                            return result;
                        }
                    }

                    // nothing found any more
                    return null;
                }
            };
        }

        // no children
        return null;
    }

    // ---------- SCR Integration

    protected void activate(BundleContext bundleContext, Map<?, ?> props) {
        String providerRoot = (String) props.get(ROOTS);
        if (providerRoot == null || providerRoot.length() == 0) {
            throw new IllegalArgumentException(ROOTS + " property must be set");
        }

        String providerFileName = (String) props.get(PROP_PROVIDER_FILE);
        if (providerFileName == null || providerFileName.length() == 0) {
            throw new IllegalArgumentException(PROP_PROVIDER_FILE
                    + " property must be set");
        }

        this.providerRoot = providerRoot;
        this.providerRootPrefix = providerRoot.concat("/");
        this.providerFile = getProviderFile(providerFileName, bundleContext);
        // start background monitor if check interval is higher than 100
        long checkInterval = DEFAULT_CHECKINTERVAL;
        final Object interval = props.get(PROP_PROVIDER_CHECKINTERVAL);
        if ( interval != null && interval instanceof Long ) {
            checkInterval = (Long)interval;
        }
        if ( checkInterval > 100 ) {
            this.monitor = new FileMonitor(this, checkInterval);
        }
    }

    protected void deactivate() {
        if ( this.monitor != null ) {
            this.monitor.stop();
            this.monitor = null;
        }
        this.providerRoot = null;
        this.providerRootPrefix = null;
        this.providerFile = null;
    }

    EventAdmin getEventAdmin() {
        return this.eventAdmin;
    }

    File getRootFile() {
        return this.providerFile;
    }

    String getProviderRoot() {
        return this.providerRoot;
    }

    // ---------- internal

    private File getProviderFile(String providerFileName,
            BundleContext bundleContext) {

        // the file object from the plain name
        File providerFile = new File(providerFileName);

        // resolve relative file name against sling.home or current
        // working directory
        if (!providerFile.isAbsolute()) {
            String home = bundleContext.getProperty("sling.home");
            if (home != null && home.length() > 0) {
                providerFile = new File(home, providerFileName);
            }
        }

        // resolve the path
        providerFile = providerFile.getAbsoluteFile();

        // if the provider file does not exist, create an empty new folder
        if (!providerFile.exists() && !providerFile.mkdirs()) {
            throw new IllegalArgumentException(
                    "Cannot create provider file root " + providerFile);
        }

        return providerFile;
    }

    /**
     * Returns a file corresponding to the given absolute resource tree path. If
     * the path equals the configured provider root, the provider root file is
     * returned. If the path starts with the configured provider root, a file is
     * returned relative to the provider root file whose relative path is the
     * remains of the resource tree path without the provider root path.
     * Otherwise <code>null</code> is returned.
     */
    private File getFile(String path) {
        if (path.equals(providerRoot)) {
            return providerFile;
        }

        if (path.startsWith(providerRootPrefix)) {
            String relPath = path.substring(providerRootPrefix.length());
            return new File(providerFile, relPath);
        }

        return null;
    }

    private Resource getResource(ResourceResolver resourceResolver,
            String resourcePath, File file) {

        if (file != null) {

            // if the file exists, but is not a directory or no repository entry
            // exists, return it as a resource
            if (file.exists()) {
                return new FsResource(resourceResolver, resourcePath, file);
            }

        }

        // not applicable or not an existing file path
        return null;
    }
}
TOP

Related Classes of org.apache.sling.fsprovider.internal.FsResourceProvider

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.