/*
* 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;
}
}
}