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