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.util.ArrayList; 019import java.util.Collection; 020import java.util.HashMap; 021import java.util.HashSet; 022import java.util.List; 023import java.util.Map; 024import java.util.Set; 025 026import org.apache.avalon.framework.parameters.Parameters; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.cocoon.ProcessingException; 030import org.apache.cocoon.acting.ServiceableAction; 031import org.apache.cocoon.environment.ObjectModelHelper; 032import org.apache.cocoon.environment.Redirector; 033import org.apache.cocoon.environment.Request; 034import org.apache.commons.lang.StringUtils; 035import org.apache.excalibur.source.Source; 036import org.apache.excalibur.source.SourceResolver; 037import org.apache.excalibur.source.TraversableSource; 038 039import org.ametys.core.cocoon.JSonReader; 040 041/** 042 * Generate a subDirectories list from a query and a list of root paths from the configuration 043 */ 044public class ServerDirectoryPathAction extends ServiceableAction 045{ 046 /** Excalibur's source resolver */ 047 private SourceResolver _sourceResolver; 048 049 @Override 050 public void service(ServiceManager smanager) throws ServiceException 051 { 052 _sourceResolver = (SourceResolver) smanager.lookup(SourceResolver.ROLE); 053 } 054 055 public Map act(Redirector redirector, org.apache.cocoon.environment.SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception 056 { 057 Request request = ObjectModelHelper.getRequest(objectModel); 058 Map<String, Object> result = new HashMap<> (); 059 060 List<Map<String, Object>> items = new ArrayList<> (); 061 boolean enableDynamicPaths = "true".equals(request.getParameter("enableDynamicPaths")); 062 063 Set<Source> sources = new HashSet<>(); 064 065 String queryPath = ServerDirectoryHelper.normalize(parameters.getParameter("query", "")); 066 067 Set<Source> rootSources = ServerDirectoryHelper.getRootServerSources(_sourceResolver); 068 for (Source rootSource : rootSources) 069 { 070 if (StringUtils.isEmpty(queryPath)) 071 { 072 sources.add(rootSource); 073 } 074 else 075 { 076 String rootURI = rootSource.getURI(); 077 String rootPath = StringUtils.substringAfter(rootURI, "file:/"); 078 079 if (queryPath.startsWith(rootPath) || queryPath.startsWith(rootURI)) 080 { 081 if (!enableDynamicPaths) 082 { 083 sources.addAll(_getValidServerDirectories(queryPath)); 084 } 085 } 086 else if (rootPath.startsWith(queryPath) || rootURI.startsWith(queryPath)) 087 { 088 sources.add(rootSource); 089 } 090 } 091 } 092 093 for (Source pathResult : sources) 094 { 095 Map<String, Object> item = new HashMap<> (); 096 item.put("displayText", StringUtils.substringAfter(pathResult.getURI(), pathResult.getScheme() + ":/")); 097 item.put("path", pathResult.getURI()); 098 099 items.add(item); 100 } 101 102 result.put("items", items); 103 104 request.setAttribute(JSonReader.OBJECT_TO_READ, result); 105 return EMPTY_MAP; 106 } 107 108 /** 109 * Look for valid directories inside of a path. 110 * @param path The path. It can be incomplete and a partial path will be used to match multiple folders. 111 * @return a set of matching directories paths 112 * @throws ProcessingException if an error occurs when retrieving the list of valid server directories 113 */ 114 private Set<Source> _getValidServerDirectories(String path) throws ProcessingException 115 { 116 Set<Source> validSources = new HashSet<>(); 117 118 String folderStartsWith = ""; 119 String rootPath = path.replace("\\", "/"); 120 121 if (!rootPath.endsWith("/")) 122 { 123 if (rootPath.contains("/")) 124 { 125 folderStartsWith = rootPath.substring(rootPath.lastIndexOf("/") + 1); 126 rootPath = rootPath.substring(0, rootPath.lastIndexOf("/")); 127 } 128 else 129 { 130 folderStartsWith = rootPath; 131 rootPath = ""; 132 } 133 } 134 135 Source root = null; 136 try 137 { 138 root = _sourceResolver.resolveURI(rootPath.trim(), "file://", null); 139 if (root.exists() && root instanceof TraversableSource && ((TraversableSource) root).isCollection()) 140 { 141 if (folderStartsWith.isEmpty()) 142 { 143 validSources.add(root); 144 } 145 146 TraversableSource tSource = (TraversableSource) root; 147 Collection<Source> childrenSources = tSource.getChildren(); 148 for (Source childSource : childrenSources) 149 { 150 if (childSource instanceof TraversableSource && ((TraversableSource) childSource).isCollection()) 151 { 152 String[] childPathSplit = childSource.getURI().split("/"); 153 if (childPathSplit.length > 0 && childPathSplit[childPathSplit.length - 1].startsWith(folderStartsWith)) 154 { 155 validSources.add(childSource); 156 } 157 } 158 159 } 160 } 161 } 162 catch (Exception e) 163 { 164 throw new ProcessingException("Unable to retrieve server directory to location: <" + rootPath + ">", e); 165 } 166 finally 167 { 168 _sourceResolver.release(root); 169 } 170 171 return validSources; 172 } 173 174 175}