001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.vfs2.provider;
018
019import org.apache.commons.vfs2.FileName;
020import org.apache.commons.vfs2.FileObject;
021import org.apache.commons.vfs2.FileSystem;
022import org.apache.commons.vfs2.FileSystemException;
023import org.apache.commons.vfs2.FileSystemOptions;
024
025/**
026 * A {@link FileProvider} that is layered on top of another, such as the contents of a ZIP or tar file.
027 */
028public abstract class AbstractLayeredFileProvider extends AbstractFileProvider {
029
030    /**
031     * Constructs a new instance for subclasses.
032     */
033    public AbstractLayeredFileProvider() {
034        setFileNameParser(LayeredFileNameParser.getInstance());
035    }
036
037    /**
038     * Creates a layered file system.
039     *
040     * @param scheme The protocol to use.
041     * @param file a FileObject.
042     * @param fileSystemOptions Options to access the FileSystem.
043     * @return A FileObject associated with the new FileSystem.
044     * @throws FileSystemException if an error occurs.
045     */
046    @Override
047    public synchronized FileObject createFileSystem(final String scheme, final FileObject file,
048            final FileSystemOptions fileSystemOptions) throws FileSystemException {
049        // Check if cached
050        final FileName rootName = file.getName();
051        FileSystem fs = findFileSystem(rootName, fileSystemOptions);
052        if (fs == null) {
053            // Create the file system
054            fs = doCreateFileSystem(scheme, file, fileSystemOptions);
055            addFileSystem(rootName, fs);
056        }
057        return fs.getRoot();
058    }
059
060    /**
061     * Creates a layered file system.
062     * <p>
063     * This method is called if the file system is not cached.
064     * </p>
065     *
066     * @param scheme The URI scheme.
067     * @param file The file to create the file system on top of.
068     * @param fileSystemOptions options for new and underlying file systems.
069     * @return The file system, never null. Might implement {@link VfsComponent}.
070     * @throws FileSystemException if the file system cannot be created.
071     */
072    protected abstract FileSystem doCreateFileSystem(String scheme, FileObject file, FileSystemOptions fileSystemOptions) throws FileSystemException;
073
074    /**
075     * Locates a file object, by absolute URI.
076     *
077     * @param baseFile The base FileObject.
078     * @param uri The name of the file to locate.
079     * @param fileSystemOptions The FileSystemOptions.
080     * @return The FileObject if it is located, null otherwise.
081     * @throws FileSystemException if an error occurs.
082     */
083    @Override
084    public FileObject findFile(final FileObject baseFile, final String uri, final FileSystemOptions fileSystemOptions)
085            throws FileSystemException {
086        // Split the URI up into its parts
087        final LayeredFileName name = (LayeredFileName) parseUri(baseFile != null ? baseFile.getName() : null, uri);
088
089        // Make the URI canonical
090
091        // Resolve the outer file name
092        final FileName fileName = name.getOuterName();
093        final FileObject file = getContext().resolveFile(baseFile, fileName.getURI(), fileSystemOptions);
094
095        // Create the file system
096        final FileObject rootFile = createFileSystem(name.getScheme(), file, fileSystemOptions);
097
098        // Resolve the file
099        return rootFile.resolveFile(name.getPath());
100    }
101
102}