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.operations;
018
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.Iterator;
022
023import org.apache.commons.vfs2.FileObject;
024import org.apache.commons.vfs2.FileSystemException;
025
026/**
027 *
028 * @since 0.1
029 */
030public abstract class AbstractFileOperationProvider implements FileOperationProvider {
031
032    /**
033     * Available operations. Operations could be registered for different schemes. Some operations can work only for
034     * "file" scheme, other - for "svnhttp(s)", "svn", "svnssh", but not for "file", etc. The Map has scheme as a key
035     * and Collection of operations that are available for that scheme.
036     */
037    private final Collection<Class<? extends FileOperation>> operations = new ArrayList<>();
038
039    /**
040     * Gather available operations for the specified FileObject and put them into specified operationsList.
041     *
042     * @param operationsList the list of available operations for the specified FileObject. The operationList contains
043     *            classes of available operations, e.g. Class objects.
044     * @param file the FileObject for which we want to get the list of available operations.
045     * @throws FileSystemException if list of operations cannot be retrieved.
046     */
047    @Override
048    public final void collectOperations(final Collection<Class<? extends FileOperation>> operationsList,
049            final FileObject file) throws FileSystemException {
050        doCollectOperations(operations, operationsList, file);
051    }
052
053    /**
054     * Gather available operations for the specified FileObject and put them into specified operationsList.
055     *
056     * @param availableOperations the list of available operations for the specified FileObject.
057     * @param resultList List to be filled with applicable operations.
058     * @param file the FileObject for which we want to get the list of available operations.
059     * @throws FileSystemException if list of operations cannot be retrieved.
060     * @see #collectOperations(Collection operationsList, FileObject file)
061     */
062    protected abstract void doCollectOperations(final Collection<Class<? extends FileOperation>> availableOperations,
063            final Collection<Class<? extends FileOperation>> resultList, final FileObject file)
064            throws FileSystemException;
065
066    /**
067     * @param file the FileObject for which we need a operation.
068     * @param operationClass the Class which instance we are needed.
069     * @return the required operation instance.
070     * @throws FileSystemException if operation cannot be retrieved.
071     */
072    @Override
073    public final FileOperation getOperation(final FileObject file, final Class<? extends FileOperation> operationClass)
074            throws FileSystemException {
075        final Class<? extends FileOperation> implementation = lookupOperation(operationClass);
076
077        final FileOperation operationInstance = instantiateOperation(file, implementation);
078
079        return operationInstance;
080    }
081
082    /**
083     * Get operation instance for specified FileOperation subclass.
084     *
085     * @param file the file this operation should act on.
086     * @param operationClass the class of an file operation interface to instantiate.
087     * @return a new file operation
088     * @throws FileSystemException if operation cannot be instantiated.
089     */
090    protected abstract FileOperation instantiateOperation(final FileObject file,
091            final Class<? extends FileOperation> operationClass) throws FileSystemException;
092
093    /**
094     * Find class implementing a specific operation interface.
095     *
096     * @param operationClass the interface which is requested.
097     * @return never returns null
098     * @throws FileSystemException if operationClass is not a known FileOperation interface.
099     */
100    protected final Class<? extends FileOperation> lookupOperation(final Class<? extends FileOperation> operationClass)
101            throws FileSystemException {
102        // check validity of passed class
103        if (!FileOperation.class.isAssignableFrom(operationClass)) {
104            throw new FileSystemException("vfs.operation/wrong-type.error", operationClass);
105        }
106
107        // find appropriate class
108        Class<? extends FileOperation> foundClass = null;
109        final Iterator<Class<? extends FileOperation>> iterator = operations.iterator();
110        while (iterator.hasNext()) {
111            final Class<? extends FileOperation> operation = iterator.next();
112            if (operationClass.isAssignableFrom(operation)) {
113                foundClass = operation;
114                break;
115            }
116        }
117
118        if (foundClass == null) {
119            throw new FileSystemException("vfs.operation/not-found.error", operationClass);
120        }
121
122        return foundClass;
123    }
124
125    /**
126     * Add new FileOperation to list of known operations.
127     *
128     * @param operationClass a class implementing FileOperation.
129     * @throws FileSystemException if instances of the class cannot be assigned to FileOperation.
130     */
131    protected final void addOperation(final Class<? extends FileOperation> operationClass) throws FileSystemException {
132        // check validity of passed class
133        if (!FileOperation.class.isAssignableFrom(operationClass)) {
134            throw new FileSystemException("vfs.operation/cant-register.error", operationClass);
135        }
136
137        // ok, lets add it to the list
138        operations.add(operationClass);
139    }
140}