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}