当前位置: 首页 > 工具软件 > OpenCMIS > 使用案例 >

笔记:Apache Chemistry OpenCMIS Client端开发2

逄宁
2023-12-01
CMIS对象类型
  1. Repository必须支持的: cmis:document, cmis:folder
  2. Repository可能支持的: cmis:relationship, cmis:policy
  3. 可以从上述四个基本类型中扩展出子类型
  4. CMIS1.0不支持创建子类型,但可以读取子类型结构和定义


如何获取Document对象的类型定义
System.out.println("Getting type definition for doc type");
ObjectType objectType = session.getTypeDefinition(doc.getType().getId());
System.out.println("isBaseType() returns " + (objectType.isBaseType() ? "true" : "false"));


ObjectType baseType = objectType.getBaseType();
if (baseType == null) {
    System.out.println("getBaseType() returns null");
} else {
    System.out.println("getBaseType() returns " + baseType.getDisplayName());
}


ObjectType parentType = objectType.getParentType();
if (parentType == null) {
    System.out.println("getParentType() returns null");
} else {
    System.out.println("getParentType() returns " + parentType.getDisplayName());
}


System.out.println("Listing child types of " + objectType.getDisplayName());
for (ObjectType o : objectType.getChildren()) {
    System.out.println("\t" + o.getDisplayName());
}


System.out.println("Getting immediate descendant types of " + objectType.getDisplayName());
for (Tree<ObjectType> o : objectType.getDescendants(1)) {
    System.out.println("\t" + o.getItem().getDisplayName());
}

执行结果
Getting type definition for doc type
isBaseType() returns true
getBaseType() returns null
getParentType() returns null
Listing child types of CMIS Document
    My Type 1 Level 1
    My Type 2 Level 1
    Complex type with properties, Level 1
    Document type with properties, Level 1
    VersionedType
Getting immediate descendant types of CMIS Document
    My Type 1 Level 1
    My Type 2 Level 1
    Complex type with properties, Level 1
    Document type with properties, Level 1
    VersionedType


如何获取Document对象的属性
List<Property<?>> props = doc.getProperties();
for (Property<?> p : props) {
    System.out.println(p.getDefinition().getDisplayName() + "=" + p.getValuesAsString());
}

执行结果
Is Latest Major Version=[false]
Content Stream Length=[26]
Content Stream Id=[store://2011/5/20/12/54/0d69ee48-ef03-4715-ae23-b84b4342315c.bin]
Version Series Checked Out By=[]
Object Type Id=[cmis:document]
Version Series Checked Out Id=[]
Name=[test.txt]
Content Stream MIME Type=[text/plain; charset=UTF-8]
Version series id=[workspace://SpacesStore/3cd2cbbf-1a00-4653-8ea8-1e91515c6092]
Creation Date=[Fri May 20 12:54:47 BST 2011]
Change token=[]
Version Label=[0.0]
Is Latest Version=[true]
Is Version Series Checked Out=[false]
Last Modified By=[admin]
Created by=[admin]
Checkin Comment=[]
Object Id=[workspace://SpacesStore/3cd2cbbf-1a00-4653-8ea8-1e91515c6092]
Is Immutable=[false]
Is Major Version=[false]
Base Type Id=[cmis:document]
Content Stream Filename=[test.txt]
Last Modified Date=[Fri May 20 12:54:47 BST 2011]


如何显式获取对象属性值
System.out.println("VersionLabel property on " + doc.getName() + " is "
        + doc.getVersionLabel());
System.out.println("Is this the latest version of " + doc.getName() + " ?:  "
        + (doc.isLatestVersion() ? "yes" : "no"));
GregorianCalendar calendar = doc.getCreationDate();
String DATE_FORMAT = "yyyyMMdd";
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
System.out.println("Creation date of " + doc.getName() + " is  " + sdf.format(calendar.getTime()));


如何根据属性ID获取属性对象
List<Property<?>> props = doc.getProperties();
Property<?> someProperty = props.get(0);
System.out.println(someProperty.getDisplayName() + " property on " + doc.getName()
    + " (by getPropertValue()) is "
    + doc.getPropertyValue(someProperty.getId()));


如何基于SQL-92语法查询CMIS对象
String query = "SELECT * FROM cmis:document WHERE cmis:name LIKE 'test%'";
ItemIterable<QueryResult> q = session.query(query, false);


// Did it work?
System.out.println("***results from query " + query);


int i = 1;
for (QueryResult qr : q) {
    System.out.println("--------------------------------------------\n" + i + " , "
            + qr.getPropertyByQueryName("cmis:objectTypeId").getFirstValue() + " , "
            + qr.getPropertyByQueryName("cmis:name").getFirstValue() + " , "
            + qr.getPropertyByQueryName("cmis:createdBy").getFirstValue() + " , "
            + qr.getPropertyByQueryName("cmis:objectId").getFirstValue() + " , "
            + qr.getPropertyByQueryName("cmis:contentStreamFileName").getFirstValue() + " , "
            + qr.getPropertyByQueryName("cmis:contentStreamMimeType").getFirstValue() + " , "
            + qr.getPropertyByQueryName("cmis:contentStreamLength").getFirstValue());
    i++;
} 


cmis:document被称为虚拟表,cmis:name被称为虚拟列。


如何处理CMIS中的异常
Folder root = session.getRootFolder();
HashMap<String, String> newFolderProps = new HashMap<String, String>();
newFolderProps.put(PropertyIds.OBJECT_TYPE_ID, "cmis:folder");
newFolderProps.put(PropertyIds.NAME, "ADGFolderTest");
Folder folderTest = root.createFolder(newFolderProps);


Map<String, String> newFileProps = new HashMap<String, String>();
newFileProps.put(PropertyIds.OBJECT_TYPE_ID, "cmis:badtype");
newFileProps.put(PropertyIds.NAME, "ADGFileTest");


try {
    folderTest.createDocument(newFileProps, null, VersioningState.MAJOR);
} catch (CmisObjectNotFoundException e) {
    System.err.println("server error page :\n" + e.getErrorContent());
    System.err.println("\nClient stack trace :\n");
    e1.printStackTrace();
}


如果使用ATOMPUB绑定,可以从CmisBaseException.getErrorContent()得到服务器端的异常详情。


执行结果
server error page :
Apache Chemistry OpenCMIS - objectNotFound error
HTTP Status 404 - objectNotFound
[...]
Client stack trace :
org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException: Not Found
    [...]
    at org.apache.chemistry.opencmis.client.runtime.SessionImpl.createDocument(SessionImpl.java:651)
    at org.apache.chemistry.opencmis.client.runtime.FolderImpl.createDocument(FolderImpl.java:87)
    at org.apache.chemistry.opencmis.client.runtime.FolderImpl.createDocument(FolderImpl.java:409)
    at org.apache.chemistry.opencmis.doc.TestingException.main(TestingException.java:104)


如何禁用对象缓存
OperationContext operationContext = session.createOperationContext();
operationContext.setCacheEnabled(false);
CmisObject object = session.getObject(id, operationContext);


如何获取Document对象的变体(Rendition)
OperationContext operationContext = session.createOperationContext();
operationContext.setRenditionFilterString("cmis:thumbnail");
CmisObject oo = session.getObject(o.getId(), operationContext);
List<Rendition> rl = oo.getRenditions();


如何获取从第5个元素开始的下一页CmisObject对象
OperationContext operationContext = session.createOperationContext();
operationContext.setMaxItemsPerPage(3);
ItemIterable<CmisObject> children1 = folderPaging.getChildren(operationContext);
int count = 0;
for (CmisObject child : children1.skipTo(5).getPage()) {
    System.out.println("object " + count + " in page of " + children1.getPageNumItems()  + " is " + child.getName());
    count++;
}

如何实现翻页查看
System.out.println("Getting complete result set in pages of 3");
OperationContext operationContext = session.createOperationContext();
operationContext.setMaxItemsPerPage(3);
children1 = folderPaging.getChildren(operationContext);
int pageNumber = 0;
boolean finished = false;
count= 0;
while (!finished) {
    ItemIterable<CmisObject> currentPage = children1.skipTo(count).getPage();
    System.out.println("page " + pageNumber + " has " + currentPage.getPageNumItems() + " items");
    for (CmisObject item : currentPage) {
        System.out.println("object " + count +  " is " + item.getName());
        count++;
    }
    pageNumber++;
    if (!currentPage.getHasMoreItems())
        finished = true;
}


如何检测Repository支持CMIS规范的哪些能力(capabilities)
System.out.println("Printing repository capabilities...");
final RepositoryInfo repInfo = session.getRepositoryInfo();
RepositoryCapabilities cap = repInfo.getCapabilities();
System.out.println("\nNavigation Capabilities");
System.out.println("-----------------------");
System.out.println("Get descendants supported: " + (cap.isGetDescendantsSupported()?"true":"false"));
System.out.println("Get folder tree supported: " + (cap.isGetFolderTreeSupported()?"true":"false"));
System.out.println("\nObject Capabilities");
System.out.println("-----------------------");
System.out.println("Content Stream: " + cap.getContentStreamUpdatesCapability().value());
System.out.println("Changes: " + cap.getChangesCapability().value());
System.out.println("Renditions: " + cap.getRenditionsCapability().value()); 
System.out.println("\nFiling Capabilities");
System.out.println("-----------------------");        
System.out.println("Multifiling supported: " + (cap.isMultifilingSupported()?"true":"false"));
System.out.println("Unfiling supported: " + (cap.isUnfilingSupported()?"true":"false"));
System.out.println("Version specific filing supported: " + (cap.isVersionSpecificFilingSupported()?"true":"false"));
System.out.println("\nVersioning Capabilities");
System.out.println("-----------------------");        
System.out.println("PWC searchable: " + (cap.isPwcSearchableSupported()?"true":"false"));
System.out.println("PWC updatable: " + (cap.isPwcUpdatableSupported()?"true":"false"));
System.out.println("All versions searchable: " + (cap.isAllVersionsSearchableSupported()?"true":"false"));
System.out.println("\nQuery Capabilities");
System.out.println("-----------------------");        
System.out.println("Query: " + cap.getQueryCapability().value());
System.out.println("Join: " + cap.getJoinCapability().value());
System.out.println("\nACL Capabilities");
System.out.println("-----------------------");        
System.out.println("ACL: " + cap.getAclCapability().value()); 
System.out.println("End of  repository capabilities");


如何检测Document对象上有哪些可执行Action
System.out.println("Getting the current allowable actions for the " + doc.getName() + " document object...");
for (Action a: doc.getAllowableActions().getAllowableActions()) {
   System.out.println("\t" + a.value());
}
if (doc.getAllowableActions().getAllowableActions().contains(Action.CAN_CHECK_OUT)) {
    System.out.println("can check out " + doc.getName());
} else {
    System.out.println("can not check out " + doc.getName());
}


如何实现多档(Multi-filing)
if (!(cap.isMultifilingSupported())) {
    System.out.println("Multifiling not supported by this repository");
} else {
    // Add a new folder to the root folder
    System.out.println("Creating 'ADGNewFolder 2' in the root folder");
    Map<String, Object> newFolderProps = new HashMap<String, Object>();
    newFolderProps.put(PropertyIds.OBJECT_TYPE_ID, "cmis:folder");
    newFolderProps.put(PropertyIds.NAME, "ADGNewFolder 2");
    newFolder2 = root.createFolder(newFolderProps);


    System.out.println("Adding " + textFileName + "to 'ADGNewFolder 2' in the root folder");
    doc.addToFolder(newFolder2, true);


    // Did it work?
    ItemIterable<CmisObject>children = newFolder.getChildren();
    System.out.println("Now finding the following objects in the 'ADGNewFolder' folder:-");
    for (CmisObject o : children) {
        System.out.println(o.getName());
    }


    children = newFolder2.getChildren();
    System.out.println("Now finding the following objects in the 'ADGNewFolder 2' folder:-");
    for (CmisObject o : children) {
        System.out.println(o.getName());
    }
}


如何实现反多档(Unfiling)
if (!(cap.isUnfilingSupported())) {
    System.out.println("Unfiling not supported by this repository");
} else {
    // remove our document from both folders
    System.out.println("removing :" + doc.getName() + "from 'ADGNewFolder':-");
    doc.removeFromFolder(newFolder);


    System.out.println("removing :" + doc.getName() + "from 'ADGNewFolder 2':-");
    doc.removeFromFolder(newFolder2);


    // Did it work?
    Document docTest = (Document) session.getObject(id);
    if (docTest != null) {
        System.out.println(docTest.getName() + " still exists");
    }
}

版本
  • 只有文档对象才有版本特性
  • 目录(Folder)和关系(Relationship)不支持版本


版本术语
  1. 版本序列(Version Series) - 每套版本序列拥有一个唯一的序列号
  2. 最新版本(Latest Version)
  3. 主版本(Major Version)


如何对文档进行check-out和check-in操作
  • PWC(Private Working copy)
  • Repositories可以只允许最新版本的Document被check-out,也可以允许所有版本check-out
  • 支持服务器端PWC的Repository可以允许其他用户从服务端工作区中查看文档或搜索文档
  • 只支持客户端PWC的Repository则不允许其他用户访问
if (versionable) {
    Document pwc = (Document) session.getObject(doc.checkOut());


    // default values if the document has no content
    String filename = "version.txt";
    String mimetype = "text/plain; charset=UTF-8";
    String content = "";


    // get the orginal content
    ContentStream contentStream = doc.getContentStream();
    if (contentStream != null) {
        filename = contentStream.getFileName();
        mimetype = contentStream.getMimeType();
        content = getContentAsString(contentStream);
    }


    String updatedContents = content + "\nLine added in new version";


    byte[] buf = updatedContents.getBytes("UTF-8");
    ByteArrayInputStream input = new ByteArrayInputStream(buf);


    contentStream = session.getObjectFactory().createContentStream(
            filename, buf.length, mimetype, input);


    // Check in the pwc
    try {
        pwc.checkIn(false, null, contentStream, "minor version");
    } catch (CmisBaseException e) {
        e.printStackTrace();
        System.out.println("checkin failed, trying to cancel the checkout");
        pwc.cancelCheckOut();
    }


    System.out.println("Document version history");
    {
        List<Document> versions = doc.getAllVersions();
        for (Document version : versions) {
            System.out.println("\tname: " + version.getName());
            System.out.println("\tversion label: " + version.getVersionLabel());
            System.out.println("\tversion series id: " + version.getVersionSeriesId());
            System.out.println("\tchecked out by: "
                    + version.getVersionSeriesCheckedOutBy());
            System.out.println("\tchecked out id: "
                    + version.getVersionSeriesCheckedOutId());
            System.out.println("\tmajor version: " + version.isMajorVersion());
            System.out.println("\tlatest version: " + version.isLatestVersion());
            System.out.println("\tlatest major version: " + version.isLatestMajorVersion());
            System.out.println("\tcheckin comment: " + version.getCheckinComment());
            System.out.println("\tcontent length: " + version.getContentStreamLength()
                    + "\n");
        }
    }
}


如何查询一棵文档树中的所有变体(Rendition)
if (session.getRepositoryInfo().getCapabilities().getRenditionsCapability()
        .equals(CapabilityRenditions.NONE)) {
    System.out.println("Repository does not support renditions");
} else {
    System.out.println("Finding first object in repository with thumbnail renditions - start");
    Folder node = root;
    Stack<Folder> stack = new Stack<Folder>();
    while (node != null) {
        children = node.getChildren();
        for (CmisObject o : children) {
            if ((o.getType().isBaseType() && o.getType().getId().equals("cmis:folder"))
                    || o.getBaseType().getId().equals("cmis:folder")) {
                stack.push((Folder) o);
            } else {
                OperationContext context = session.createOperationContext();
                context.setRenditionFilterString("cmis:thumbnail");
                CmisObject oo = session.getObject(o.getId(), context);
                List<Rendition> rl = oo.getRenditions();
                if (!rl.isEmpty()) {
                    System.out.println("found  " + o.getName() + " of type "
                            + o.getType().getDisplayName() + "that has renditions...");
                    for (Rendition rendition : rl) {
                        System.out.print("kind: " + rendition.getKind());
                        System.out.print("\tmimetype: " + rendition.getMimeType());
                        System.out.print("\twidth: " + rendition.getWidth());
                        System.out.print("\theight: " + rendition.getHeight());
                        System.out.println("\tstream id: " + rendition.getStreamId());
                    }
                    break; // Just show the first object with
                           // renditions. Remove this
                           // Break to show them all
                }
            }
        }
        if (stack.isEmpty()) {
            node = null;
        } else {
            node = (Folder) stack.pop();
        }
    }
    System.out.println("Finding first object in repository with thumbnail renditions - end");
}



如何查询自定义子类型对象
if (session.getRepositoryInfo().getCapabilities().getQueryCapability()
        .equals(CapabilityQuery.METADATAONLY)) {
    System.out.println("Full search not supported");
} else {
    String query = "SELECT * FROM ia:calendarEvent";
    ItemIterable<QueryResult> queryResult = session.query(query, false);
    for (QueryResult item : queryResult) {
        System.out.println("Found "
                + item.getPropertyByQueryName("cmis:name").getFirstValue() + " of type "
                + item.getPropertyByQueryName("cmis:objectTypeId").getFirstValue());
        System.out.println("property ia:descriptionEvent is "
                + item.getPropertyByQueryName("ia:descriptionEvent").getFirstValue());
        System.out.println("property ia:toDate is "
                + item.getPropertyByQueryName("ia:toDate").getFirstValue());
        System.out.println("property ia:fromDate is "
                + item.getPropertyByQueryName("ia:fromDate").getFirstValue());
    }
}

关系Relationship
  • 关系是有方向的,从source到target
  • 非侵入式的,它并不修改source和target
  • 关系也是有类型的,cmis:relationship
  • 可以建立关系对象的有:document, folder, policy
  • 关系自身不含有内容流(content stream)
  • Repository对关系的支持不是必须的

如何创建关系
 // Check if the repo supports relationships
ObjectType relationshipType = null;
try {
    relationshipType = session.getTypeDefinition("cmis:relationship");
} catch (CmisObjectNotFoundException e) {
    relationshipType = null;
}


if (relationshipType == null) {
    System.out.println("Repository does not support cmis:relationship objects");
} else {
    ObjectType cmiscustomRelationshipType = null;
    try {
        cmiscustomRelationshipType = session.getTypeDefinition("R:cmiscustom:assoc");
    } catch (CmisObjectNotFoundException e) {
        cmiscustomRelationshipType = null;
    }


    if (cmiscustomRelationshipType == null) {
        System.out.println("Repository does not support R:cmiscustom:assoc objects");
    } else {
        System.out.println("Creating folders for relationships example");


        newFolderProps = new HashMap<String, String>();
        newFolderProps.put(PropertyIds.OBJECT_TYPE_ID, "cmis:folder");
        newFolderProps.put(PropertyIds.NAME, "ADGFolderAssociations");
        Folder folderAssociations = root.createFolder(newFolderProps);


        newFileProps = new HashMap<String, String>();
        newFileProps.put(PropertyIds.OBJECT_TYPE_ID, "D:cmiscustom:document");
        newFileProps.put(PropertyIds.NAME, "ADGFileSource");
        Document sourceDoc = folderAssociations.createDocument(newFileProps, null, VersioningState.MAJOR);


        newFileProps.put(PropertyIds.OBJECT_TYPE_ID, "cmis:document");
        newFileProps.put(PropertyIds.NAME, "ADGFileTarget");
        Document targetDoc = folderAssociations.createDocument(newFileProps, null, VersioningState.MAJOR);


        Map<String, String> relProps = new HashMap<String, String>();
        relProps.put("cmis:sourceId", sourceDoc.getId());
        relProps.put("cmis:targetId", targetDoc.getId());
        relProps.put("cmis:objectTypeId", "R:cmiscustom:assoc");
        ObjectId relId = session.createRelationship(relProps, null, null, null);
        System.out.println("created relationship");
    }
}

如何检测关系适用的源对象和目标对象
RelationshipType relType = (RelationshipType) relationship.getType();


System.out.println(relType.getDisplayName()
        + "has the following allowed source types:");
for (ObjectType objectType : relType.getAllowedSourceTypes()) {
    System.out.println("\t" + objectType.getDisplayName());
}


System.out.println(relType.getDisplayName()
        + "has the following allowed target types:");
for (ObjectType objectType : relType.getAllowedTargetTypes()) {
    System.out.println("\t" + objectType.getDisplayName());
}




访问控制列表(Access Control List)
  • Document对象的访问可以由ACL或者Policy进行控制
  • ACL由ACE(Access Control Entry)构成
  • CMIS预定义3种基本权限: [cmis:read, cmis:write, cmis:all]


每个ACE的构成有三部分
  • 一个成员:包括用户、组、角色
  • 一个或多个权限字段
  • direct标志:true表示直接赋予,false表示经由继承得到


对于direct=false的ACE,你可以通过设置传播方式PROPOGATION来告知Repository如何处理子对象
OBJECTONLY
PROPOGATE
REPOSITORYDETERMINED


如何获取权限
System.out.println("getting ACL capabilities");
AclCapabilities aclCapabilities = session.getRepositoryInfo().getAclCapabilities();


System.out.println("Propogation for this repository is " + aclCapabilities.getAclPropagation().toString());


System.out.println("permissions for this repository are: ");
for (PermissionDefinition definition : aclCapabilities.getPermissions()) {
    System.out.println(definition.toString());                
}


System.out.println("\npermission mappings for this repository are: ");
Map<String, PermissionMapping> repoMapping = aclCapabilities.getPermissionMapping();
for (String key: repoMapping.keySet()) {
    System.out.println(key + " maps to " + repoMapping.get(key).getPermissions());                
}


如何给文档对象添加ACL
// Check if the repo supports ACLs
if (!session.getRepositoryInfo().getCapabilities().getAclCapability()
        .equals(CapabilityAcl.MANAGE)) {
    System.out.println("Repository does not allow ACL management");
} else {
    System.out.println("Repository allows ACL management");


    System.out.println("Creating folders for permissions example");


    HashMap<String, String> newFolderProps = new HashMap<String, String>();
    newFolderProps.put(PropertyIds.OBJECT_TYPE_ID, "cmis:folder");
    newFolderProps.put(PropertyIds.NAME, "ADGFolderPermissions");
    Folder folderAssociations = session.getRootFolder().createFolder(newFolderProps);


    HashMap<String, String> newFileProps = new HashMap<String, String>();
    ContentStream contentStream = new ContentStreamImpl("permissions.txt", null,
            "plain/text", new ByteArrayInputStream("some content".getBytes()));


    newFileProps.put(PropertyIds.OBJECT_TYPE_ID, "cmis:document");
    newFileProps.put(PropertyIds.NAME, "ADGFilePermissions");
    Document testDoc = folderAssociations.createDocument(newFileProps, contentStream,
            VersioningState.MAJOR);


    OperationContext operationContext = new OperationContextImpl();
    operationContext.setIncludeAcls(true);
    testDoc = (Document) session.getObject(testDoc, operationContext);


    System.out.println("ACL before adding an ace...");
    for (Ace ace : testDoc.getAcl().getAces()) {
      System.out.println("Found ace: " + ace.getPrincipalId() + " toString "+ ace.toString());   
    }


    List<String> permissions = new ArrayList<String>();
    permissions.add("cmis:write");
    String principal = "admin";
    Ace aceIn = session.getObjectFactory().createAce(principal, permissions);
    List<Ace> aceListIn = new ArrayList<Ace>();
    aceListIn.add(aceIn);
    testDoc.addAcl(aceListIn, AclPropagation.REPOSITORYDETERMINED);
    testDoc = (Document) session.getObject(testDoc, operationContext);


    System.out.println("ACL after adding an ace...");
    for (Ace ace : testDoc.getAcl().getAces()) {
      System.out.println("Found ace: " + ace.getPrincipalId() + " toString "+ ace.toString());   
    }            
}


 类似资料: