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