001/* 002 * Copyright 2010 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.explorer.resources.generators; 017 018import java.io.IOException; 019 020import org.apache.avalon.framework.service.ServiceException; 021import org.apache.avalon.framework.service.ServiceManager; 022import org.apache.cocoon.ProcessingException; 023import org.apache.cocoon.environment.ObjectModelHelper; 024import org.apache.cocoon.environment.Request; 025import org.apache.cocoon.generation.ServiceableGenerator; 026import org.apache.cocoon.xml.AttributesImpl; 027import org.apache.cocoon.xml.XMLUtils; 028import org.apache.commons.lang3.ArrayUtils; 029import org.xml.sax.SAXException; 030 031import org.ametys.core.user.User; 032import org.ametys.core.user.UserIdentity; 033import org.ametys.core.user.UserManager; 034import org.ametys.core.util.DateUtils; 035import org.ametys.plugins.explorer.ExplorerNode; 036import org.ametys.plugins.explorer.ModifiableExplorerNode; 037import org.ametys.plugins.explorer.resources.Resource; 038import org.ametys.plugins.explorer.resources.ResourceCollection; 039import org.ametys.plugins.repository.AmetysObject; 040import org.ametys.plugins.repository.AmetysObjectResolver; 041import org.ametys.plugins.repository.ModifiableAmetysObject; 042import org.ametys.plugins.repository.TraversableAmetysObject; 043 044/** 045 * Generates a subtree of {@link ExplorerNode}.<br>The subnodes are SAXed to a depth of 0 by default. 046 * <ul> 047 * <li>Depth of -1 means generate all</li> 048 * <li>0 means only the given node and its children (resources and folders)</li> 049 * <li>1 means the given node, its children and their children, and so on.</li> 050 * </ul> 051 */ 052public class ResourcesExplorerGenerator extends ServiceableGenerator 053{ 054 /** Constant for resource collection */ 055 public static final String RESOURCE_COLLECTION = "collection"; 056 /** Constant for resource */ 057 public static final String RESOURCE = "resource"; 058 059 /** The resolver for ametys object */ 060 protected AmetysObjectResolver _resolver; 061 /** The user manager */ 062 protected UserManager _userManager; 063 064 @Override 065 public void service(ServiceManager sManager) throws ServiceException 066 { 067 super.service(sManager); 068 069 _resolver = (AmetysObjectResolver) sManager.lookup(AmetysObjectResolver.ROLE); 070 _userManager = (UserManager) sManager.lookup(UserManager.ROLE); 071 } 072 073 @Override 074 public void generate() throws IOException, SAXException, ProcessingException 075 { 076 Request request = ObjectModelHelper.getRequest(objectModel); 077 078 String id = parameters.getParameter("node", request.getParameter("node")); 079 int depth = parameters.getParameterAsInteger("depth", 0); 080 if (depth == -1) 081 { 082 // -1 means no limit 083 depth = Integer.MAX_VALUE; 084 } 085 086 String[] allowedExtensions = request.getParameterValues("allowedExtensions"); 087 088 ExplorerNode node = _resolver.resolveById(id); 089 090 contentHandler.startDocument(); 091 092 long t0 = System.currentTimeMillis(); 093 094 XMLUtils.startElement(contentHandler, "Nodes"); 095 saxCollection(node, depth, allowedExtensions); 096 XMLUtils.endElement(contentHandler, "Nodes"); 097 098 if (getLogger().isDebugEnabled()) 099 { 100 getLogger().debug("SAXed collection " + node.getExplorerPath() + " in " + (System.currentTimeMillis() - t0) + " ms"); 101 } 102 103 contentHandler.endDocument(); 104 } 105 106 /** 107 * SAX a {@link ExplorerNode} 108 * @param node The node to sax 109 * @throws SAXException If an error occurred while saxing 110 */ 111 protected void saxCollection (ExplorerNode node) throws SAXException 112 { 113 saxCollection(node, 0, null); 114 } 115 116 /** 117 * SAX a {@link ExplorerNode} 118 * @param node The node to sax 119 * @param saxNode True to wrap the collection with an XML node representing the current node. 120 * @throws SAXException If an error occurred while saxing 121 */ 122 protected void saxCollection (ExplorerNode node, boolean saxNode) throws SAXException 123 { 124 saxCollection(node, 0, saxNode, "Node"); 125 } 126 127 /** 128 * SAX a {@link ExplorerNode} 129 * @param node The node to sax 130 * @param saxNode True to wrap the collection with an XML node representing the current node. 131 * @param nodeTag The tag to use 132 * @throws SAXException If an error occurred while saxing 133 */ 134 protected void saxCollection (ExplorerNode node, boolean saxNode, String nodeTag) throws SAXException 135 { 136 saxCollection(node, 0, saxNode, nodeTag); 137 } 138 139 /** 140 * SAX a {@link ExplorerNode} 141 * @param node The node to sax 142 * @param depth The recursive depth to sax 143 * @param saxNode True to wrap the collection with an XML node representing the current node. 144 * @param nodeTag The tag to use 145 * @throws SAXException If an error occurred while saxing 146 */ 147 protected void saxCollection(ExplorerNode node, int depth, boolean saxNode, String nodeTag) throws SAXException 148 { 149 if (saxNode) 150 { 151 AttributesImpl childAtts = getExplorerNodeAttributes(node); 152 153 XMLUtils.startElement(contentHandler, nodeTag, childAtts); 154 saxCollection(node, depth, null); 155 XMLUtils.endElement(contentHandler, nodeTag); 156 } 157 158 } 159 160 /** 161 * SAX a {@link ExplorerNode} 162 * @param node The node to sax 163 * @param depth The recursive depth to sax 164 * @param allowedExtensions The allowed file extensions (lower-case). Can be null or empty to not filter on file extensions 165 * @throws SAXException If an error occurred while saxing 166 */ 167 protected void saxCollection (ExplorerNode node, int depth, String[] allowedExtensions) throws SAXException 168 { 169 // Traverse the child nodes depth >= 0 (we're not in the last level). 170 if (depth >= 0) 171 { 172 for (AmetysObject child : ((TraversableAmetysObject) node).getChildren()) 173 { 174 if (child instanceof Resource) 175 { 176 if (_matchFilter((Resource) child, allowedExtensions)) 177 { 178 saxResource((Resource) child); 179 } 180 } 181 else if (child instanceof ExplorerNode) 182 { 183 saxExplorerNode((ExplorerNode) child, depth); 184 } 185 } 186 } 187 } 188 189 /** 190 * Determines if the resource matches the allowed extensions 191 * @param resource The resource 192 * @param allowedExtensions allowed file extensions 193 * @return true if the allowed extensions are empty or null, or if the resource's name matches the allowed extensions 194 */ 195 protected boolean _matchFilter(Resource resource, String[] allowedExtensions) 196 { 197 if (allowedExtensions == null || allowedExtensions.length == 0) 198 { 199 // No filter 200 return true; 201 } 202 203 String filename = resource.getName(); 204 String extension = filename.lastIndexOf(".") > 0 ? filename.substring(filename.lastIndexOf(".") + 1) : ""; 205 206 return ArrayUtils.contains(allowedExtensions, extension.toLowerCase()); 207 } 208 209 /** 210 * SAX a {@link ExplorerNode} 211 * @param node The explorer node to SAX. 212 * @param depth The recursive depth to sax 213 * @throws SAXException If an error occurred while SAXing 214 */ 215 protected void saxExplorerNode(ExplorerNode node, int depth) throws SAXException 216 { 217 saxExplorerNode(node, depth, null); 218 } 219 220 /** 221 * SAX a {@link ExplorerNode} 222 * @param node The explorer node to SAX. 223 * @param depth The recursive depth to sax 224 * @param allowedExtensions allowed file extensions 225 * @throws SAXException If an error occurred while SAXing 226 */ 227 protected void saxExplorerNode(ExplorerNode node, int depth, String[] allowedExtensions) throws SAXException 228 { 229 AttributesImpl childAtts = getExplorerNodeAttributes(node); 230 231 XMLUtils.startElement(contentHandler, "Node", childAtts); 232 saxCollection(node, depth - 1, allowedExtensions); 233 XMLUtils.endElement(contentHandler, "Node"); 234 } 235 236 /** 237 * Returns the attributes corresponding to an Explorer node. 238 * @param node The explorer node to SAX. 239 * @return the attributes 240 */ 241 protected AttributesImpl getExplorerNodeAttributes(ExplorerNode node) 242 { 243 AttributesImpl childAtts = new AttributesImpl(); 244 245 childAtts.addCDATAAttribute("id", node.getId()); 246 childAtts.addCDATAAttribute("name", node.getName()); 247 248 String iconCls = node.getIconCls(); 249 if (iconCls != null) 250 { 251 childAtts.addCDATAAttribute("iconCls", iconCls); 252 } 253 childAtts.addCDATAAttribute("applicationId", node.getApplicationId()); 254 255 String relPath = node.getExplorerPath(); 256 childAtts.addCDATAAttribute("path", relPath.startsWith("/") ? relPath.substring(1) : relPath); 257 childAtts.addCDATAAttribute("type", RESOURCE_COLLECTION); 258 259 boolean hasResources = false; 260 if (node instanceof ResourceCollection) 261 { 262 hasResources = ((ResourceCollection) node).hasChildResources(); 263 } 264 boolean hasChildNodes = node.hasChildExplorerNodes(); 265 266 if (hasChildNodes) 267 { 268 childAtts.addCDATAAttribute("hasChildNodes", "true"); 269 } 270 271 if (hasResources) 272 { 273 childAtts.addCDATAAttribute("hasResources", "true"); 274 } 275 276 if (node instanceof ModifiableAmetysObject) 277 { 278 childAtts.addCDATAAttribute("isModifiable", "true"); 279 } 280 281 if (node instanceof ModifiableExplorerNode) 282 { 283 childAtts.addCDATAAttribute("canCreateChild", "true"); 284 } 285 286 return childAtts; 287 } 288 289 /** 290 * SAX a {@link Resource} 291 * @param resource The resource to SAX 292 * @throws SAXException If an error occurred while SAXing 293 */ 294 protected void saxResource (Resource resource) throws SAXException 295 { 296 AttributesImpl childAtts = getResourceAttributes(resource); 297 298 XMLUtils.createElement(contentHandler, "Node", childAtts); 299 } 300 301 /** 302 * Returns the attributes corresponding to a Resource. 303 * @param resource The resource to SAX 304 * @return the attributes 305 */ 306 protected AttributesImpl getResourceAttributes(Resource resource) 307 { 308 UserIdentity userIdentity = resource.getCreator(); 309 User user = _userManager.getUser(userIdentity.getPopulationId(), userIdentity.getLogin()); 310 String name = user == null ? userIdentity.getLogin() : user.getFullName() + " (" + userIdentity.getLogin() + ")"; 311 312 AttributesImpl childAtts = new AttributesImpl(); 313 childAtts.addCDATAAttribute("id", resource.getId()); 314 String iconCls = getResourcesIconCls(resource); 315 if (iconCls != null) 316 { 317 childAtts.addCDATAAttribute("iconCls", getResourcesIconCls(resource)); 318 } 319 childAtts.addCDATAAttribute("name", resource.getName()); 320 childAtts.addCDATAAttribute("mimetype", resource.getMimeType()); 321 childAtts.addCDATAAttribute("lastModified", DateUtils.dateToString(resource.getLastModified())); 322 childAtts.addCDATAAttribute("size", String.valueOf(resource.getLength())); 323 childAtts.addCDATAAttribute("author", name); 324 childAtts.addCDATAAttribute("keywords", resource.getKeywordsAsString()); 325 childAtts.addCDATAAttribute("type", RESOURCE); 326 327 if (resource instanceof ModifiableAmetysObject) 328 { 329 childAtts.addCDATAAttribute("isModifiable", "true"); 330 } 331 332 getAdditionalAttributes(childAtts, resource); 333 334 String relPath = resource.getResourcePath(); 335 childAtts.addCDATAAttribute("path", relPath.startsWith("/") ? relPath.substring(1) : relPath); 336 337 return childAtts; 338 } 339 340 /** 341 * CSS suffix class name getter for the icon resource. 342 * @param resource The resource 343 * @return The suffix of the css class for the icon of this resource. 344 */ 345 protected String getResourcesIconCls(Resource resource) 346 { 347 // let the js do its job 348 return null; 349 } 350 351 /** 352 * Get the additional attributes 353 * @param attrs The attributes 354 * @param resource The resource 355 */ 356 protected void getAdditionalAttributes (AttributesImpl attrs, Resource resource) 357 { 358 // Nothing 359 } 360}