/* * 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 2010 Pentaho Corporation. All rights reserved. * * @created Jan, 2010 * @author James Dixon * */ package org.pentaho.platform.util.client; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.StringTokenizer; 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.repository.ISolutionRepository; import org.pentaho.platform.util.StringUtil; 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 ) ); if( depth > 0 ) { // add child objects } 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(ISolutionRepository.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, ""+ISolutionRepository.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, ""+ISolutionRepository.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( ISolutionRepository.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; } } }