/*! * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved. */ package org.pentaho.platform.util.client; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.Element; import org.pentaho.commons.util.repository.GetCheckedoutDocsResponse; import org.pentaho.commons.util.repository.INavigationService; import org.pentaho.commons.util.repository.exception.ConstraintViolationException; import org.pentaho.commons.util.repository.exception.FilterNotValidException; import org.pentaho.commons.util.repository.exception.FolderNotValidException; import org.pentaho.commons.util.repository.exception.InvalidArgumentException; import org.pentaho.commons.util.repository.exception.ObjectNotFoundException; import org.pentaho.commons.util.repository.exception.OperationNotSupportedException; import org.pentaho.commons.util.repository.exception.PermissionDeniedException; import org.pentaho.commons.util.repository.exception.RuntimeException; import org.pentaho.commons.util.repository.exception.UpdateConflictException; import org.pentaho.commons.util.repository.type.CmisObject; import org.pentaho.commons.util.repository.type.CmisObjectImpl; import org.pentaho.commons.util.repository.type.CmisProperties; import org.pentaho.commons.util.repository.type.CmisProperty; import org.pentaho.commons.util.repository.type.PropertiesBase; import org.pentaho.commons.util.repository.type.PropertiesDocument; import org.pentaho.commons.util.repository.type.PropertyBoolean; import org.pentaho.commons.util.repository.type.PropertyDateTime; import org.pentaho.commons.util.repository.type.PropertyId; import org.pentaho.commons.util.repository.type.PropertyString; import org.pentaho.commons.util.repository.type.TypesOfFileableObjects; import org.pentaho.platform.api.repository2.unified.RepositoryFile; import org.pentaho.platform.util.StringUtil; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.StringTokenizer; public class BiPlatformRepositoryClientNavigationService implements INavigationService { private Document doc; public Document getDoc() { return doc; } public void setDoc( Document doc ) { this.doc = doc; } public List<CmisObject> getObjectParent( String repositoryId, String objectId, String filter, boolean includeAllowableActions, boolean includeRelationships ) throws InvalidArgumentException, ConstraintViolationException, FilterNotValidException, RuntimeException, UpdateConflictException, ObjectNotFoundException, OperationNotSupportedException, PermissionDeniedException, FolderNotValidException { // TODO add support for filters if ( !repositoryId.equals( BiPlatformRepositoryClient.PLATFORMORIG ) ) { throw new InvalidArgumentException(); } List<CmisObject> objects = new ArrayList<CmisObject>(); // get the element for the specified object Element objectElement = getObjectElement( objectId ); if ( objectElement == null ) { return objects; } // get the parent node Element parentElement = objectElement.getParent(); if ( parentElement == null ) { return objects; } CmisObject parent = createCmisObjectFromElement( parentElement, 0 ); objects.add( parent ); return objects; } private CmisObject createCmisObjectFromElement( Element element, int depth ) { CmisObject object = new CmisObjectImpl(); CmisProperties properties = new CmisProperties(); List<CmisProperty> propList = properties.getProperties(); // is this a folder or a file? boolean isDirectory = false; Attribute attr = element.attribute( "isDirectory" ); //$NON-NLS-1$ if ( attr != null ) { isDirectory = "true".equalsIgnoreCase( attr.getText() ); //$NON-NLS-1$ } // set the base properties String objectId = getObjectId( element ); Calendar lastModifiedDate = getLastModifiedDate( element ); String name = getName( element ); String localizedName = getLocalizedName( element ); String extension = getExtension( element ); boolean visible = getVisible( element ); propList.add( new PropertyId( PropertiesBase.OBJECTID, objectId ) ); propList.add( new PropertyDateTime( PropertiesBase.LASTMODIFICATIONDATE, lastModifiedDate ) ); if ( isDirectory ) { propList.add( new PropertyString( PropertiesBase.OBJECTTYPEID, CmisObject.OBJECT_TYPE_FOLDER ) ); } else { propList.add( new PropertyString( PropertiesBase.OBJECTTYPEID, extension ) ); propList.add( new PropertyBoolean( PropertiesDocument.CONTENTSTREAMALLOWED, true ) ); } propList.add( new PropertyString( CmisObject.NAME, name ) ); propList.add( new PropertyString( CmisObject.LOCALIZEDNAME, localizedName ) ); propList.add( new PropertyBoolean( CmisObject.VISIBLE, visible ) ); object.setProperties( properties ); return object; } private String getObjectId( Element element ) { // get a list of the ancestors List<Element> pathElements = new ArrayList<Element>(); Element current = element; while ( current != null ) { pathElements.add( 0, current ); current = current.getParent(); } // now create a path string StringBuilder sb = new StringBuilder(); int idx = 0; for ( Element pathElement : pathElements ) { if ( idx > 1 ) { sb.append( RepositoryFile.SEPARATOR ); } if ( idx > 0 ) { // ignore the first element sb.append( pathElement.attribute( "name" ).getText() ); //$NON-NLS-1$ } idx++; } String objectId = sb.toString(); return objectId; } private Calendar getLastModifiedDate( Element element ) { String lastModifiedDateStr = ""; //$NON-NLS-1$ Attribute attr = element.attribute( "lastModifiedDate" ); //$NON-NLS-1$ if ( attr != null ) { lastModifiedDateStr = attr.getText(); long millis = new Long( lastModifiedDateStr ); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis( millis ); return calendar; } return null; } private String getLocalizedName( Element element ) { String name = ""; //$NON-NLS-1$ Attribute attr = element.attribute( "localized-name" ); //$NON-NLS-1$ if ( attr != null ) { name = attr.getText(); } return name; } private String getName( Element element ) { String name = ""; //$NON-NLS-1$ Attribute attr = element.attribute( "name" ); //$NON-NLS-1$ if ( attr != null ) { name = attr.getText(); } return name; } private boolean getVisible( Element element ) { boolean visible = true; Attribute attr = element.attribute( "visible" ); //$NON-NLS-1$ if ( attr != null ) { visible = "true".equalsIgnoreCase( attr.getText() ); //$NON-NLS-1$ } return visible; } private String getExtension( Element element ) { String name = ""; //$NON-NLS-1$ Attribute attr = element.attribute( "name" ); //$NON-NLS-1$ if ( attr != null ) { name = attr.getText(); } int idx = name.indexOf( '.' ); String extension = ""; //$NON-NLS-1$ if ( idx != -1 ) { extension = name.substring( idx + 1 ); } return extension; } private Element getObjectElement( String path ) throws ObjectNotFoundException { // parse out the path StringTokenizer tokenizer = new StringTokenizer( path, RepositoryFile.SEPARATOR ); //$NON-NLS-1$ StringBuilder sb = new StringBuilder(); sb.append( "/repository" ); //$NON-NLS-1$ String folderName; int tokenCount = tokenizer.countTokens(); for ( int idx = 0; idx < tokenCount - 1; idx++ ) { folderName = tokenizer.nextToken(); sb.append( "/file[@isDirectory='true' and @name='" ) //$NON-NLS-1$ .append( folderName ).append( "']" ); //$NON-NLS-1$ } if ( tokenizer.hasMoreTokens() ) { folderName = tokenizer.nextToken(); sb.append( "/file[@name='" ) //$NON-NLS-1$ .append( folderName ).append( "']" ); //$NON-NLS-1$ } String xPath = sb.toString(); Element element = (Element) doc.selectSingleNode( xPath ); if ( element == null ) { throw new ObjectNotFoundException(); } return element; } private Element getFolderElement( String path ) throws FolderNotValidException { // parse out the path StringTokenizer tokenizer = new StringTokenizer( path, "" + RepositoryFile.SEPARATOR ); //$NON-NLS-1$ StringBuilder sb = new StringBuilder(); sb.append( "/repository" ); //$NON-NLS-1$ String folderName; while ( tokenizer.hasMoreTokens() ) { folderName = tokenizer.nextToken(); sb.append( "/file[@isDirectory='true' and @name='" ) //$NON-NLS-1$ .append( folderName ).append( "']" ); //$NON-NLS-1$ } String xPath = sb.toString(); Element element = (Element) doc.selectSingleNode( xPath ); if ( element == null ) { throw new FolderNotValidException(); } return element; } public List<CmisObject> getFolderParent( String repositoryId, String folderId, String filter, boolean includeAllowableActions, boolean includeRelationships, boolean returnToRoot ) throws InvalidArgumentException, ConstraintViolationException, FilterNotValidException, RuntimeException, UpdateConflictException, ObjectNotFoundException, OperationNotSupportedException, PermissionDeniedException, FolderNotValidException { // TODO add support for filters if ( !repositoryId.equals( BiPlatformRepositoryClient.PLATFORMORIG ) ) { throw new InvalidArgumentException(); } List<CmisObject> objects = new ArrayList<CmisObject>(); // get the element for the specified object Element objectElement = getFolderElement( folderId ); // get the parent node Element parentElement = objectElement.getParent(); if ( parentElement == null ) { return objects; } CmisObject parent = createCmisObjectFromElement( parentElement, 0 ); objects.add( parent ); return objects; } public List<CmisObject> getDescendants( String repositoryId, String folderId, TypesOfFileableObjects type, int depth, String filter, boolean includeAllowableActions, boolean includeRelationships ) throws InvalidArgumentException, ConstraintViolationException, FilterNotValidException, RuntimeException, UpdateConflictException, ObjectNotFoundException, OperationNotSupportedException, PermissionDeniedException, FolderNotValidException { Collection filters = null; if ( !StringUtil.isEmpty( filter ) ) { filters = getFilterCollection( filter ); } if ( !repositoryId.equals( BiPlatformRepositoryClient.PLATFORMORIG ) ) { throw new InvalidArgumentException(); } List<CmisObject> objects = new ArrayList<CmisObject>(); // get the element for the specified object Element objectElement = getFolderElement( folderId ); addChildren( objects, objectElement, type, filters, 0, 0, depth, 1 ); return objects; } protected void addChildren( List<CmisObject> objects, Element objectElement, TypesOfFileableObjects type, Collection filters, int maxItems, int skipCount, int depth, int level ) { if ( objectElement == null ) { return; } CmisObject object; int skipped = 0; boolean ok = false; for ( Object element : objectElement.elements() ) { ok = false; object = createCmisObjectFromElement( (Element) element, 0 ); if ( type == null || type.getValue().equals( TypesOfFileableObjects.ANY ) ) { ok = true; } else if ( TypesOfFileableObjects.FOLDERS.equals( type.getValue() ) && CmisObject.OBJECT_TYPE_FOLDER.equals( object.findStringProperty( PropertiesBase.OBJECTTYPEID, null ) ) ) { ok = true; } else if ( TypesOfFileableObjects.DOCUMENTS.equals( type.getValue() ) && !CmisObject.OBJECT_TYPE_FOLDER.equals( object.findStringProperty( PropertiesBase.OBJECTTYPEID, null ) ) ) { // TODO support policies ok = true; } if ( ok && filters != null ) { String objectType = object.findStringProperty( PropertiesBase.OBJECTTYPEID, null ); if ( !filters.contains( objectType ) ) { ok = false; } } if ( ok && skipCount > 0 ) { if ( skipped < skipCount ) { ok = false; skipped++; } } if ( ok && maxItems > 0 ) { if ( objects.size() >= maxItems ) { break; } } if ( ok ) { objects.add( object ); // see if we have to recurse } if ( depth > 0 && level < depth && CmisObject.OBJECT_TYPE_FOLDER.equals( object.findStringProperty( PropertiesBase.OBJECTTYPEID, null ) ) ) { addChildren( objects, (Element) element, type, filters, maxItems, skipCount, depth, level + 1 ); } } } public List<CmisObject> getChildren( String repositoryId, String folderId, TypesOfFileableObjects type, String filter, boolean includeAllowableActions, boolean includeRelationships, int maxItems, int skipCount ) throws InvalidArgumentException, ConstraintViolationException, FilterNotValidException, RuntimeException, UpdateConflictException, ObjectNotFoundException, OperationNotSupportedException, PermissionDeniedException, FolderNotValidException { Collection filters = null; if ( !StringUtil.isEmpty( filter ) ) { filters = getFilterCollection( filter ); } if ( !repositoryId.equals( BiPlatformRepositoryClient.PLATFORMORIG ) ) { throw new InvalidArgumentException(); } List<CmisObject> objects = new ArrayList<CmisObject>(); // get the element for the specified object Element objectElement = getFolderElement( folderId ); addChildren( objects, objectElement, type, filters, maxItems, skipCount, 1, 1 ); return objects; } private Collection getFilterCollection( String filterstr ) { StringTokenizer tokenizer = new StringTokenizer( filterstr, "," ); //$NON-NLS-1$ HashSet<String> set = new HashSet<String>(); int tokenCount = tokenizer.countTokens(); for ( int idx = 0; idx < tokenCount; idx++ ) { set.add( tokenizer.nextToken() ); } return set; } public GetCheckedoutDocsResponse getCheckedoutDocs( String repositoryId, String folderId, String filter, boolean includeAllowableActions, boolean includeRelationships, int maxItems, int skipCount ) throws InvalidArgumentException, ConstraintViolationException, FilterNotValidException, RuntimeException, UpdateConflictException, ObjectNotFoundException, OperationNotSupportedException, PermissionDeniedException, FolderNotValidException { throw new OperationNotSupportedException(); } public String getRepositoryPath( CmisObject object ) { // the id is the path and file name String id = object.findIdProperty( PropertiesBase.OBJECTID, null ); String typeId = object.findStringProperty( PropertiesBase.OBJECTTYPEID, null ); if ( CmisObject.OBJECT_TYPE_FOLDER.equals( typeId ) ) { return id; } else { int idx = id.lastIndexOf( RepositoryFile.SEPARATOR ); if ( idx != -1 ) { return id.substring( 0, idx ); } else { return ""; //$NON-NLS-1$ } } } public String getRepositoryFilename( CmisObject object ) { String typeId = object.findStringProperty( PropertiesBase.OBJECTTYPEID, null ); if ( CmisObject.OBJECT_TYPE_FOLDER.equals( typeId ) ) { return ""; //$NON-NLS-1$ } else { String name = object.findStringProperty( CmisObject.NAME, null ); return name; } } }