001/*
002 *  Copyright 2015 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.serverdirectory;
017
018import java.io.IOException;
019import java.net.URISyntaxException;
020import java.util.Base64;
021import java.util.Collection;
022import java.util.Set;
023
024import org.apache.avalon.framework.service.ServiceException;
025import org.apache.avalon.framework.service.ServiceManager;
026import org.apache.cocoon.ProcessingException;
027import org.apache.cocoon.environment.ObjectModelHelper;
028import org.apache.cocoon.environment.Request;
029import org.apache.cocoon.generation.ServiceableGenerator;
030import org.apache.cocoon.xml.AttributesImpl;
031import org.apache.cocoon.xml.XMLUtils;
032import org.apache.excalibur.source.Source;
033import org.apache.excalibur.source.SourceException;
034import org.apache.excalibur.source.SourceResolver;
035import org.apache.excalibur.source.TraversableSource;
036import org.xml.sax.SAXException;
037
038import org.ametys.core.user.CurrentUserProvider;
039import org.ametys.plugins.repository.AmetysRepositoryException;
040import org.ametys.runtime.authentication.AccessDeniedException;
041import org.ametys.runtime.authentication.AuthorizationRequiredException;
042import org.ametys.runtime.parameter.ParameterHelper;
043import org.ametys.web.repository.page.ZoneItem;
044
045/**
046 * Generate all subDirectory from a directory
047 */
048public class ServerDirectoryGenerator extends ServiceableGenerator
049{
050    /** Excalibur's source resolver */
051    protected SourceResolver _sourceResolver;
052    
053    /** The current user provider */
054    protected CurrentUserProvider _currentUserProvider;
055
056    @Override
057    public void service(ServiceManager smanager) throws ServiceException
058    {
059        _sourceResolver = (SourceResolver) smanager.lookup(SourceResolver.ROLE);
060        _currentUserProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE);
061    }
062    
063    public void generate() throws IOException, SAXException, ProcessingException
064    {
065        Request request = ObjectModelHelper.getRequest(objectModel);
066        
067        ZoneItem zoneItem = (ZoneItem) request.getAttribute(ZoneItem.class.getName());
068        
069        String folder = ServerDirectoryHelper.normalize(zoneItem.getServiceParameters().getString("folder", ""));
070        
071        try
072        {
073            contentHandler.startDocument();
074            
075            if (zoneItem.getServiceParameters().getBoolean("enableDynamicPaths", false))
076            {
077                folder = ServerDirectoryHelper.evaluateDynamicPath(folder, (String) request.getAttribute("site"), (String) request.getAttribute("sitemapLanguage"), _currentUserProvider.getUser());
078            }
079            
080            Set<Source> rootSources = ServerDirectoryHelper.getRootServerSources(_sourceResolver);
081            
082            if (!ServerDirectoryHelper.isValidPath(folder, rootSources))
083            {
084                throw new IllegalStateException("The server directory '" + folder + "' is not an authorized directory");
085            }
086            
087            Source sourceFolder = null;
088            try
089            {
090                sourceFolder = _sourceResolver.resolveURI(folder);
091                
092                if (!sourceFolder.exists())
093                {
094                    throw new IllegalArgumentException("The server directory '" + folder + "' does not exist");
095                }
096                
097                String zoneItemEncoded = new String(Base64.getUrlEncoder().encode(zoneItem.getId().getBytes("UTF-8")));
098                saxCollection(sourceFolder, zoneItemEncoded);
099            }
100            catch (SourceException | AmetysRepositoryException | URISyntaxException e)
101            {
102                throw new IllegalArgumentException("Cannot enumerate subdirectories for server location: <" + folder + ">", e);
103            }
104            finally
105            {
106                _sourceResolver.release(sourceFolder);
107            }
108            
109            contentHandler.endDocument();
110        }
111        catch (AccessDeniedException | AuthorizationRequiredException e)
112        {
113            throw new ProcessingException("No user is connected or the user has no required permissions to access to the server directory " + folder);
114        }
115    }
116    
117    /**
118     * SAX a {@link Source}
119     * @param sourceFolder The source to sax
120     * @param zoneItemId The zone item id
121     * @throws SAXException If an error occurred while saxing
122     * @throws SourceException If an error occurred while we get child from the source
123     * @throws URISyntaxException if an error occurred 
124     */
125    protected void saxCollection (Source sourceFolder, String zoneItemId) throws SAXException, SourceException, URISyntaxException
126    {
127        if (sourceFolder instanceof TraversableSource)
128        {            
129            TraversableSource tSource = (TraversableSource) sourceFolder;
130            
131            AttributesImpl childAtts = new AttributesImpl();
132            childAtts.addCDATAAttribute("id", tSource.getURI());
133            childAtts.addCDATAAttribute("name", tSource.getName());
134            childAtts.addCDATAAttribute("mimetype", tSource.getMimeType());
135            childAtts.addCDATAAttribute("lastModified", ParameterHelper.valueToString(tSource.getLastModified()));
136            childAtts.addCDATAAttribute("size", String.valueOf(tSource.getContentLength()));
137            childAtts.addCDATAAttribute("path", tSource.getURI());
138            
139            if (tSource.isCollection())
140            {
141                childAtts.addCDATAAttribute("type", "collection");
142                XMLUtils.startElement(contentHandler, "Node", childAtts);
143
144                Collection<Source> childrenSources = tSource.getChildren(); 
145                for (Source childSource : childrenSources)
146                {
147                    saxCollection(childSource, zoneItemId);
148                }
149                XMLUtils.endElement(contentHandler, "Node");
150            }
151            else
152            {
153                childAtts.addCDATAAttribute("type", "resource");
154                childAtts.addCDATAAttribute("zoneItem", zoneItemId);
155                XMLUtils.createElement(contentHandler, "Node", childAtts);
156            }
157            
158        }
159    }
160}