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.repository.workspace; 017 018import java.io.IOException; 019import java.util.ArrayList; 020import java.util.Arrays; 021import java.util.Collection; 022import java.util.Collections; 023import java.util.Date; 024import java.util.Iterator; 025import java.util.List; 026 027import javax.jcr.Node; 028import javax.jcr.RepositoryException; 029 030import org.apache.avalon.framework.service.ServiceException; 031import org.apache.avalon.framework.service.ServiceManager; 032import org.apache.cocoon.ProcessingException; 033import org.apache.cocoon.generation.ServiceableGenerator; 034import org.apache.cocoon.xml.AttributesImpl; 035import org.apache.cocoon.xml.XMLUtils; 036import org.apache.commons.lang3.StringUtils; 037import org.xml.sax.Attributes; 038import org.xml.sax.SAXException; 039 040import org.ametys.plugins.repository.AmetysObject; 041import org.ametys.plugins.repository.AmetysObjectIterable; 042import org.ametys.plugins.repository.AmetysObjectResolver; 043import org.ametys.plugins.repository.ModifiableAmetysObject; 044import org.ametys.plugins.repository.ModifiableTraversableAmetysObject; 045import org.ametys.plugins.repository.TraversableAmetysObject; 046import org.ametys.plugins.repository.jcr.JCRAmetysObject; 047import org.ametys.plugins.repository.lock.LockAwareAmetysObject; 048import org.ametys.plugins.repository.lock.LockableAmetysObject; 049import org.ametys.plugins.repository.metadata.CompositeMetadata; 050import org.ametys.plugins.repository.metadata.CompositeMetadata.MetadataType; 051import org.ametys.plugins.repository.metadata.File; 052import org.ametys.plugins.repository.metadata.Folder; 053import org.ametys.plugins.repository.metadata.MetadataAwareAmetysObject; 054import org.ametys.plugins.repository.metadata.RichText; 055import org.ametys.runtime.parameter.ParameterHelper; 056import org.ametys.workspaces.repository.jcr.NodeGroupHelper; 057 058/** 059 * Generate the content of a logic node: 060 * <ul> 061 * <li>metadata 062 * <li>ametys object properties 063 * <li>children 064 * </ul> 065 */ 066public class RepositoryLogicNodeGenerator extends ServiceableGenerator 067{ 068 private AmetysObjectResolver _resolver; 069 070 @Override 071 public void service(ServiceManager serviceManager) throws ServiceException 072 { 073 super.service(serviceManager); 074 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 075 } 076 077 public void generate() throws IOException, SAXException, ProcessingException 078 { 079 if (getLogger().isInfoEnabled()) 080 { 081 getLogger().info("Trying to generate content for a node"); 082 } 083 084 String id = parameters.getParameter("id", ""); 085 086 contentHandler.startDocument(); 087 AttributesImpl repositoryAttributes = new AttributesImpl(); 088 089 XMLUtils.startElement(contentHandler, "repository", repositoryAttributes); 090 091 try 092 { 093 _saxObject(id); 094 } 095 catch (RepositoryException e) 096 { 097 throw new ProcessingException("Unable to retrieve node for path: '" + source + "'", e); 098 } 099 100 XMLUtils.endElement(contentHandler, "repository"); 101 102 contentHandler.endDocument(); 103 } 104 105 private void _saxObject(String id) throws SAXException, RepositoryException 106 { 107 AmetysObject ao = null; 108 109 if (StringUtils.isEmpty(id) || id.equals("/")) 110 { 111 ao = _resolver.resolveByPath("/"); 112 } 113 else 114 { 115 ao = _resolver.resolveById(id); 116 } 117 118 boolean isModifiable = ao instanceof ModifiableAmetysObject; 119 boolean isLocked = ao instanceof LockAwareAmetysObject && ((LockAwareAmetysObject) ao).isLocked(); 120 AttributesImpl nodeAttributes = new AttributesImpl(); 121 122 nodeAttributes.addCDATAAttribute("path", ao.getPath()); 123 nodeAttributes.addCDATAAttribute("name", ao.getName()); 124 nodeAttributes.addCDATAAttribute("id", ao.getId()); 125 126 XMLUtils.startElement(contentHandler, "ametysObject", nodeAttributes); 127 128 Attributes attrs = XMLUtils.EMPTY_ATTRIBUTES; 129 // MetaData 130 if (ao instanceof MetadataAwareAmetysObject) 131 { 132 XMLUtils.createElement(contentHandler, "isMetadataAware", attrs, "true"); 133 CompositeMetadata holder = ((MetadataAwareAmetysObject) ao).getMetadataHolder(); 134 _saxMetaData(holder, isLocked, isModifiable); 135 } 136 else 137 { 138 XMLUtils.createElement(contentHandler, "isMetadataAware", attrs, "false"); 139 } 140 141 // Children 142 if (ao instanceof TraversableAmetysObject) 143 { 144 _saxChildren((TraversableAmetysObject) ao); 145 } 146 147 if (ao instanceof JCRAmetysObject) 148 { 149 Node node = ((JCRAmetysObject) ao).getNode(); 150 XMLUtils.createElement(contentHandler, "isJCRAO", attrs, "true"); 151 XMLUtils.createElement(contentHandler, "JCRPath", attrs, node.getPath()); 152 XMLUtils.createElement(contentHandler, "JCRPathWithGroups", attrs, NodeGroupHelper.getPathWithGroups(node)); 153 } 154 else 155 { 156 XMLUtils.createElement(contentHandler, "isJCRAO", attrs, "false"); 157 } 158 159 XMLUtils.createElement(contentHandler, "isModifiable", attrs, Boolean.toString(isModifiable)); 160 XMLUtils.createElement(contentHandler, "isModifiableTraversable", attrs, Boolean.toString(ao instanceof ModifiableTraversableAmetysObject)); 161 162 if (ao instanceof LockAwareAmetysObject) 163 { 164 XMLUtils.createElement(contentHandler, "isLocked", attrs, Boolean.toString(isLocked)); 165 XMLUtils.createElement(contentHandler, "isLockable", attrs, Boolean.toString(ao instanceof LockableAmetysObject)); 166 } 167 else 168 { 169 XMLUtils.createElement(contentHandler, "isLocked", attrs, "not-applicable"); 170 XMLUtils.createElement(contentHandler, "isLockable", attrs, "false"); 171 } 172 173 174 XMLUtils.endElement(contentHandler, "ametysObject"); 175 } 176 177 private void _saxMetaData(CompositeMetadata holder, boolean isLocked, boolean isModifiable) throws SAXException, RepositoryException 178 { 179 String[] metadataNames = holder.getMetadataNames(); 180 181 List<String> metaNames = new ArrayList<>(Arrays.asList(metadataNames)); 182 Collections.sort(metaNames); 183 184 for (String name : metaNames) 185 { 186 AttributesImpl metadataAttributes = new AttributesImpl(); 187 188 MetadataType type = holder.getType(name); 189 Boolean isMultiple = holder.isMultiple(name); 190 191 metadataAttributes.addCDATAAttribute("name", name); 192 metadataAttributes.addCDATAAttribute("type", type.toString()); 193 metadataAttributes.addCDATAAttribute("multiple", Boolean.toString(isMultiple)); 194 metadataAttributes.addCDATAAttribute("editable", Boolean.toString(type != MetadataType.COMPOSITE && isModifiable && !isLocked)); 195 196 XMLUtils.startElement(contentHandler, "metadata", metadataAttributes); 197 198 _saxValues(holder, name, type, isMultiple, isLocked, isModifiable); 199 200 XMLUtils.endElement(contentHandler, "metadata"); 201 } 202 203 } 204 205 private void _saxChildren(TraversableAmetysObject ao) throws SAXException, RepositoryException 206 { 207 AmetysObjectIterable<AmetysObject> children = ao.getChildren(); 208 Iterator<AmetysObject> it = children.iterator(); 209 210 while (it.hasNext()) 211 { 212 AmetysObject child = it.next(); 213 214 String id = child.getId(); 215 String name = child.getName(); 216 217 AttributesImpl childAttributes = new AttributesImpl(); 218 childAttributes.addCDATAAttribute("name", name); 219 childAttributes.addCDATAAttribute("id", id); 220 childAttributes.addCDATAAttribute("path", child.getPath()); 221 222 if (child instanceof JCRAmetysObject) 223 { 224 Node node = ((JCRAmetysObject) child).getNode(); 225 childAttributes.addCDATAAttribute("isJCRAO", "true"); 226 childAttributes.addCDATAAttribute("JCRPath", node.getPath()); 227 childAttributes.addCDATAAttribute("JCRPathWithGroups", NodeGroupHelper.getPathWithGroups(node)); 228 } 229 230 // If not traversable or no child 231 if (!(child instanceof TraversableAmetysObject)) 232 { 233 childAttributes.addCDATAAttribute("noChild", "true"); 234 } 235 else if (!((TraversableAmetysObject) child).getChildren().iterator().hasNext()) 236 { 237 childAttributes.addCDATAAttribute("noChild", "true"); 238 } 239 240 XMLUtils.createElement(contentHandler, "ametysObject", childAttributes); 241 } 242 } 243 244 private void _saxValues(CompositeMetadata holder, String name, MetadataType type, Boolean isMultiple, boolean isLocked, boolean isModifiable) throws RepositoryException, SAXException 245 { 246 if (isMultiple) 247 { 248 _saxMultipleValues(holder, name, type, isLocked, isModifiable); 249 } 250 else 251 { 252 _saxSimpleValue(holder, name, type, isLocked, isModifiable); 253 } 254 } 255 256 private void _saxMultipleValues(CompositeMetadata holder, String name, MetadataType type, boolean isLocked, boolean isModifiable) throws RepositoryException, SAXException 257 { 258 Attributes attrs = XMLUtils.EMPTY_ATTRIBUTES; 259 String textValue = null; 260 261 switch (type) 262 { 263 case DATE: 264 Date[] dateValues = holder.getDateArray(name); 265 for (Date dVal : dateValues) 266 { 267 XMLUtils.createElement(contentHandler, "value", attrs, ParameterHelper.valueToString(dVal)); 268 } 269 break; 270 case STRING: 271 String[] stringValues = holder.getStringArray(name); 272 for (String sVal : stringValues) 273 { 274 textValue = sVal; 275 XMLUtils.createElement(contentHandler, "value", attrs, textValue); 276 } 277 break; 278 case LONG: 279 long[] longValues = holder.getLongArray(name); 280 for (long lVal : longValues) 281 { 282 textValue = Long.toString(lVal); 283 XMLUtils.createElement(contentHandler, "value", attrs, textValue); 284 } 285 break; 286 case DOUBLE: 287 double[] doubleValues = holder.getDoubleArray(name); 288 for (double dbVal : doubleValues) 289 { 290 textValue = Double.toString(dbVal); 291 XMLUtils.createElement(contentHandler, "value", attrs, textValue); 292 } 293 break; 294 case BOOLEAN: 295 boolean[] booleanValues = holder.getBooleanArray(name); 296 for (boolean bVal : booleanValues) 297 { 298 textValue = Boolean.toString(bVal); 299 XMLUtils.createElement(contentHandler, "value", attrs, textValue); 300 } 301 break; 302 case COMPOSITE: 303 CompositeMetadata cm = holder.getCompositeMetadata(name); 304 _saxMetaData(cm, isLocked, isModifiable); 305 break; 306 case BINARY: 307 String mimeType = holder.getBinaryMetadata(name).getMimeType(); 308 AttributesImpl attrsimpl = new AttributesImpl(); 309 attrsimpl.addCDATAAttribute("mime-type", mimeType); 310 XMLUtils.createElement(contentHandler, "value", attrsimpl); 311 break; 312 case RICHTEXT: 313 RichText rt = holder.getRichText(name); 314 _saxRichText(rt); 315 break; 316 case OBJECT_COLLECTION: 317 // TODO 318 break; 319 default: 320 textValue = ""; 321 XMLUtils.createElement(contentHandler, "value", attrs, textValue); 322 break; 323 } 324 325 } 326 327 private void _saxSimpleValue(CompositeMetadata holder, String name, MetadataType type, boolean isLocked, boolean isModifiable) throws RepositoryException, SAXException 328 { 329 Attributes attrs = XMLUtils.EMPTY_ATTRIBUTES; 330 String textValue = null; 331 332 switch (type) 333 { 334 case DATE: 335 XMLUtils.createElement(contentHandler, "value", attrs, ParameterHelper.valueToString(holder.getDate(name))); 336 break; 337 case STRING: 338 textValue = holder.getString(name); 339 XMLUtils.createElement(contentHandler, "value", attrs, textValue); 340 break; 341 case LONG: 342 textValue = Long.toString(holder.getLong(name)); 343 XMLUtils.createElement(contentHandler, "value", attrs, textValue); 344 break; 345 case DOUBLE: 346 textValue = Double.toString(holder.getDouble(name)); 347 XMLUtils.createElement(contentHandler, "value", attrs, textValue); 348 break; 349 case BOOLEAN: 350 textValue = Boolean.toString(holder.getBoolean(name)); 351 XMLUtils.createElement(contentHandler, "value", attrs, textValue); 352 break; 353 case COMPOSITE: 354 CompositeMetadata cm = holder.getCompositeMetadata(name); 355 _saxMetaData(cm, isLocked, isModifiable); 356 break; 357 case BINARY: 358 String mimeType = holder.getBinaryMetadata(name).getMimeType(); 359 AttributesImpl attrsimpl = new AttributesImpl(); 360 attrsimpl.addCDATAAttribute("mime-type", mimeType); 361 XMLUtils.createElement(contentHandler, "value", attrsimpl); 362 break; 363 case RICHTEXT: 364 RichText rt = holder.getRichText(name); 365 _saxRichText(rt); 366 break; 367 case OBJECT_COLLECTION: 368 // TODO 369 break; 370 default: 371 textValue = ""; 372 XMLUtils.createElement(contentHandler, "value", attrs, textValue); 373 break; 374 } 375 } 376 377 private void _saxRichText(RichText rt) throws RepositoryException, SAXException 378 { 379 //content 380 AttributesImpl contentAttributes = new AttributesImpl(); 381 contentAttributes.addCDATAAttribute("name", "data"); 382 contentAttributes.addCDATAAttribute("type", "RICHTEXT-CONTENT"); 383 contentAttributes.addCDATAAttribute("isMultiple", "false"); 384 XMLUtils.startElement(contentHandler, "metadata", contentAttributes); 385 386 AttributesImpl attrsimplRT = new AttributesImpl(); 387 attrsimplRT.addCDATAAttribute("mime-type", rt.getMimeType()); 388 XMLUtils.createElement(contentHandler, "value", attrsimplRT); 389 390 XMLUtils.endElement(contentHandler, "metadata"); 391 392 //encoding 393 if (rt.getEncoding() != null) 394 { 395 AttributesImpl encodingAttributes = new AttributesImpl(); 396 encodingAttributes.addCDATAAttribute("name", "encoding"); 397 encodingAttributes.addCDATAAttribute("type", "STRING"); 398 encodingAttributes.addCDATAAttribute("isMultiple", "false"); 399 XMLUtils.startElement(contentHandler, "metadata", encodingAttributes); 400 401 XMLUtils.createElement(contentHandler, "value", XMLUtils.EMPTY_ATTRIBUTES, rt.getEncoding()); 402 403 XMLUtils.endElement(contentHandler, "metadata"); 404 } 405 406 //mime-type 407 AttributesImpl mimeAttributes = new AttributesImpl(); 408 mimeAttributes.addCDATAAttribute("name", "mime-type"); 409 mimeAttributes.addCDATAAttribute("type", "STRING"); 410 mimeAttributes.addCDATAAttribute("isMultiple", "false"); 411 XMLUtils.startElement(contentHandler, "metadata", mimeAttributes); 412 413 XMLUtils.createElement(contentHandler, "value", XMLUtils.EMPTY_ATTRIBUTES, rt.getMimeType()); 414 415 XMLUtils.endElement(contentHandler, "metadata"); 416 417 //last modified 418 AttributesImpl lastmodAttributes = new AttributesImpl(); 419 lastmodAttributes.addCDATAAttribute("name", "last-modified-date"); 420 lastmodAttributes.addCDATAAttribute("type", "DATE"); 421 lastmodAttributes.addCDATAAttribute("isMultiple", "false"); 422 XMLUtils.startElement(contentHandler, "metadata", lastmodAttributes); 423 424 XMLUtils.createElement(contentHandler, "value", XMLUtils.EMPTY_ATTRIBUTES, ParameterHelper.valueToString(rt.getLastModified())); 425 426 XMLUtils.endElement(contentHandler, "metadata"); 427 428 //length 429 AttributesImpl lengthAttributes = new AttributesImpl(); 430 lengthAttributes.addCDATAAttribute("name", "length"); 431 lengthAttributes.addCDATAAttribute("type", "LONG"); 432 lengthAttributes.addCDATAAttribute("isMultiple", "false"); 433 XMLUtils.startElement(contentHandler, "metadata", lengthAttributes); 434 435 XMLUtils.createElement(contentHandler, "value", XMLUtils.EMPTY_ATTRIBUTES, Long.toString(rt.getLength())); 436 437 XMLUtils.endElement(contentHandler, "metadata"); 438 439 //sub folders 440 _saxFolder(rt.getAdditionalDataFolder()); 441 } 442 443 private void _saxFolder(Folder folder) throws RepositoryException, SAXException 444 { 445 AttributesImpl folderAttributes = new AttributesImpl(); 446 folderAttributes.addCDATAAttribute("name", folder.getName()); 447 folderAttributes.addCDATAAttribute("type", "FOLDER"); 448 folderAttributes.addCDATAAttribute("isMultiple", "false"); 449 XMLUtils.startElement(contentHandler, "metadata", folderAttributes); 450 451 Collection<? extends Folder> folders = folder.getFolders(); 452 Iterator itFolders = folders.iterator(); 453 while (itFolders.hasNext()) 454 { 455 Folder subfold = (Folder) itFolders.next(); 456 _saxFolder(subfold); 457 } 458 459 Collection<? extends File> files = folder.getFiles(); 460 Iterator itFiles = files.iterator(); 461 while (itFiles.hasNext()) 462 { 463 File file = (File) itFiles.next(); 464 _saxFile(file); 465 } 466 467 XMLUtils.endElement(contentHandler, "metadata"); 468 } 469 470 471 472 private void _saxFile(File file) throws SAXException 473 { 474 AttributesImpl fileAttributes = new AttributesImpl(); 475 fileAttributes.addCDATAAttribute("name", file.getName()); 476 fileAttributes.addCDATAAttribute("type", "FILE"); 477 fileAttributes.addCDATAAttribute("isMultiple", "false"); 478 XMLUtils.startElement(contentHandler, "metadata", fileAttributes); 479 480 //content 481 AttributesImpl contentAttributes = new AttributesImpl(); 482 contentAttributes.addCDATAAttribute("name", "data"); 483 contentAttributes.addCDATAAttribute("type", "FILE-CONTENT"); 484 contentAttributes.addCDATAAttribute("isMultiple", "false"); 485 XMLUtils.startElement(contentHandler, "metadata", contentAttributes); 486 487 AttributesImpl attrsimplF = new AttributesImpl(); 488 attrsimplF.addCDATAAttribute("mime-type", file.getResource().getMimeType()); 489 XMLUtils.createElement(contentHandler, "value", attrsimplF); 490 491 XMLUtils.endElement(contentHandler, "metadata"); 492 493 //encoding 494 if (file.getResource().getEncoding() != null) 495 { 496 AttributesImpl encodingAttributes = new AttributesImpl(); 497 encodingAttributes.addCDATAAttribute("name", "encoding"); 498 encodingAttributes.addCDATAAttribute("type", "STRING"); 499 encodingAttributes.addCDATAAttribute("isMultiple", "false"); 500 XMLUtils.startElement(contentHandler, "metadata", encodingAttributes); 501 502 XMLUtils.createElement(contentHandler, "value", XMLUtils.EMPTY_ATTRIBUTES, file.getResource().getEncoding()); 503 504 XMLUtils.endElement(contentHandler, "metadata"); 505 } 506 507 //mime-type 508 AttributesImpl mimeAttributes = new AttributesImpl(); 509 mimeAttributes.addCDATAAttribute("name", "mime-type"); 510 mimeAttributes.addCDATAAttribute("type", "STRING"); 511 mimeAttributes.addCDATAAttribute("isMultiple", "false"); 512 XMLUtils.startElement(contentHandler, "metadata", mimeAttributes); 513 514 XMLUtils.createElement(contentHandler, "value", XMLUtils.EMPTY_ATTRIBUTES, file.getResource().getMimeType()); 515 516 XMLUtils.endElement(contentHandler, "metadata"); 517 518 //last modified 519 AttributesImpl lastmodAttributes = new AttributesImpl(); 520 lastmodAttributes.addCDATAAttribute("name", "last-modified-date"); 521 lastmodAttributes.addCDATAAttribute("type", "DATE"); 522 lastmodAttributes.addCDATAAttribute("isMultiple", "false"); 523 XMLUtils.startElement(contentHandler, "metadata", lastmodAttributes); 524 525 XMLUtils.createElement(contentHandler, "value", XMLUtils.EMPTY_ATTRIBUTES, ParameterHelper.valueToString(file.getResource().getLastModified())); 526 527 XMLUtils.endElement(contentHandler, "metadata"); 528 529 //length 530 AttributesImpl lengthAttributes = new AttributesImpl(); 531 lengthAttributes.addCDATAAttribute("name", "length"); 532 lengthAttributes.addCDATAAttribute("type", "LONG"); 533 lengthAttributes.addCDATAAttribute("isMultiple", "false"); 534 XMLUtils.startElement(contentHandler, "metadata", lengthAttributes); 535 536 XMLUtils.createElement(contentHandler, "value", XMLUtils.EMPTY_ATTRIBUTES, Long.toString(file.getResource().getLength())); 537 538 XMLUtils.endElement(contentHandler, "metadata"); 539 540 XMLUtils.endElement(contentHandler, "metadata"); 541 } 542 543}