001/*
002 *  Copyright 2014 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.core.impl.checker;
017
018import java.io.IOException;
019import java.net.MalformedURLException;
020import java.util.List;
021
022import org.apache.avalon.framework.configuration.Configurable;
023import org.apache.avalon.framework.configuration.Configuration;
024import org.apache.avalon.framework.configuration.ConfigurationException;
025import org.apache.avalon.framework.logger.AbstractLogEnabled;
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028import org.apache.avalon.framework.service.Serviceable;
029import org.apache.excalibur.source.ModifiableTraversableSource;
030import org.apache.excalibur.source.Source;
031import org.apache.excalibur.source.SourceException;
032import org.apache.excalibur.source.SourceResolver;
033import org.apache.excalibur.source.TraversableSource;
034import org.apache.excalibur.source.impl.FileSource;
035
036import org.ametys.runtime.model.checker.ItemChecker;
037import org.ametys.runtime.model.checker.ItemCheckerTestFailureException;
038
039/**
040 * Checks if the specified repository exists and optionally if the user has the writing rights
041 */
042public class DirectoryChecker extends AbstractLogEnabled implements Configurable, ItemChecker, Serviceable
043{
044    /** Equals true if the directory has to be writable */
045    private boolean _checkWrite;
046    
047    /** The source resolver */
048    private SourceResolver _sourceResolver;
049
050    /** Creates the directory if it does not exist already */
051    private boolean _createsIfRequired;
052
053    private ServiceManager _sManager;
054    
055    @Override
056    public void configure(Configuration configuration) throws ConfigurationException
057    {
058        _createsIfRequired = configuration.getChild("configuration").getChild("creates-if-required", false) != null;
059        _checkWrite = configuration.getChild("configuration").getChild("check-write", false) != null;
060        
061        if (configuration.getChild("linked-params").getChildren().length != 1)
062        {
063            throw new ConfigurationException("The Directory Checker should have exactly 1 linked parameter: the directory");
064        }
065    }
066    
067    @Override
068    public void service(ServiceManager sManager) throws ServiceException
069    {
070        _sManager = sManager;
071    }
072    
073    @Override
074    public void check(List<String> values) throws ItemCheckerTestFailureException
075    {
076        if (_sourceResolver == null)
077        {
078            try
079            {
080                _sourceResolver = (SourceResolver) _sManager.lookup(SourceResolver.ROLE);
081            }
082            catch (ServiceException e)
083            {
084                throw new ItemCheckerTestFailureException("The test cannot be tested now", e);
085            }
086        }
087        
088        _checkDirectory(values.get(0));
089    }
090    
091    /**
092     * Checks if the source exists and optionally checks if it is writable
093     * @param path The path of the source to check
094     * @throws ItemCheckerTestFailureException if an error occurred 
095     */
096    private void _checkDirectory(String path) throws ItemCheckerTestFailureException
097    {
098        Source source = null;
099        try
100        {
101            source = _sourceResolver.resolveURI(path, "context://", null); 
102            
103            boolean removeIt = false;
104
105            if (!source.exists())
106            {
107                if (!_createsIfRequired)
108                {
109                    throw new ItemCheckerTestFailureException("The specified directory at '" + source.getURI() + "' does not exist");
110                }
111                if (!(source instanceof ModifiableTraversableSource))
112                {
113                    throw new ItemCheckerTestFailureException("The specified directory at '" + source.getURI() + "' does not exist and cannot be created");
114                }
115                
116                try
117                {
118                    ((ModifiableTraversableSource) source).makeCollection();
119                    removeIt = true;
120                }
121                catch (SourceException e)
122                {
123                    throw new ItemCheckerTestFailureException("The specified directory at '" + source.getURI() + "' does not exist and cannot be created", e);
124                }
125            }
126            
127            if (!(source instanceof TraversableSource) && ((TraversableSource) source).isCollection())
128            {
129                throw new ItemCheckerTestFailureException("The specified directory at '" + source.getURI() + "' is not a directory");
130            }
131            
132            if (_checkWrite 
133                    && (!(source instanceof ModifiableTraversableSource)
134                            || !(source instanceof FileSource)
135                            || !((FileSource) source).getFile().canWrite()))
136            {
137                throw new ItemCheckerTestFailureException("The specified directory at '" + source.getURI() + "' is not writable");
138            }
139            
140            if (removeIt)
141            {
142                try
143                {
144                    ((ModifiableTraversableSource) source).delete();
145                }
146                catch (SourceException e)
147                {
148                    getLogger().warn("The specified directory '" + source.getURI() + "' was created for tests purposes but could not be removed", e);
149                }
150            }
151        }
152        catch (MalformedURLException e)
153        {
154            throw new ItemCheckerTestFailureException("An error occurred while trying to resolve the following path '" + path + "'." , e);
155        }
156        catch (IOException e)
157        {
158            throw new ItemCheckerTestFailureException("An error occurred while trying to resolve the following path '" + path + "'." , e);
159        }
160    }
161}