/*BEGINPROLOGUE****************************************************************
* @copyright(disclaimer) *
* *
* DISCLAIMER OF WARRANTIES. *
* *
* The following IBM Content Manager Enterprise Edition code is sample code *
* created by IBM Corporation. IBM grants you a nonexclusive copyright *
* license to use this sample code example to generate similar function *
* tailored to your own specific needs. This sample code is not part of any *
* standard IBM product and is provided to you solely for the purpose of *
* assisting you in the development of your applications. This example has *
* not been thoroughly tested under all conditions. IBM, therefore cannot *
* guarantee nor may you imply reliability, serviceability, or function of *
* these programs. The code is provided "AS IS", without warranty of any *
* kind. IBM shall not be liable for any damages arising out of your or any *
* other parties use of the sample code, even if IBM has been advised of the *
* possibility of such damages. If you do not agree with these terms, do not *
* use the sample code. *
* *
* Licensed Materials - Property of IBM *
* 5724-B19, 5697-H60 *
* © Copyright IBM Corp. 1994, 2013 All Rights Reserved. *
* *
* US Government Users Restricted Rights - Use, duplication or disclosure *
* restricted by GSA ADP Schedule Contract with IBM Corp. *
* *
* @endCopyright *
******************************************************************************
Prerequisite Information:
Doc Model Items are an extension of non-resource items. Doc Model Parts
are resource items. Therefore, both the standard item & resource item
samples are pre-requisite knowledge. Please review the SItem... samples
and the SResourceItem... samples.
Document Model - Documents Modeled by Parts
DB2 Content Manager V8 provides a multi-part document model instead of
using standard non-resource items and single-binary resource items.
The built-in document model is the same as the single data model in
V7.1. Note that V8 introduces single-binary resource items that
are like parts that stand on their own as independent items.
The document model provided structures documents as an Item made up of
parts. A document within the DB2 Content Manager Document Model is an
item that that extends the full functionality of the non-resource items to
include parts. Parts are just like resource items with nearly the full
capability of resource items except that they are owned and controlled by
their parent document rather than separate items.
Compared to a resource item, a document separates the binary resource
content from the root component of the document into separate part
entities and therefore can support more than one binary object per document.
However, there is some overhead to this level of separation. If you
have only one part, you can push the resource content into the root
component of the document by storing it as a resource item. Note that
resource items perform faster than a single-part document. However,
there are many great cases where documents with the capability to store
multiple parts make sense and perform well depending on your needs.
An item can support parts if the item belongs to an item type that is
defined with classification "document" (document model). The item type
also specifies which part types are supported by each "document" classified
item type. A document can contain any number of parts for each part type
selected. See SItemTypeCreationICM sample for more information on the
definition.
Typically most applications use the system-defined part types. However
you can create your own part types by creating item type definitions
classified as "part" (document part).
The part item type (identified by the PID's object type within a part DDO)
is the validated true identify of a document part. You can set the semantic
type to any value of your choice. However, there exists semantic type values
for each of the system-defined part types. When using system-defined part type,
it is recommended that you also specify an equivalent semantic type. When
using user-defined part types, you might want to set the semantic type to the
nearest similar system-defined part type value that it resembles. However, you
can set the semantic type to any value of your choice if you do not want to give
a clue to other applications that might not understand your user-defined part type.
Therefore, you should not rely on the semantic type as the primary means to
identify part types.
The pre-defined semantic types are only alleged to most nearly resemble the part
type they indicate. Be careful of relying on semantic type values if your
application reads items created by other applications or tools since the meaning
and enforcement can vary among applications. For example, do not rely on the
various part semantic types since parts are allowed to be set with any semantic
type value. Instead rely first on the PID's object type which identifies the
exact item type which you might recognize or you can retrieve the definition to
tell you more, such as classification as a part, XDO class, etc. You can rely
on the semantic type as a secondary measure if you do not recognize the object
type.
For example, consider semantic type DK_ICM_SEMANTIC_TYPE_BASE.
This value does *not* uniquely identify or make it a BASE part. The semantic type
value is not validated or enforced. The item type of the part (identified in the
PID's object type for the part DDO) is what makes the part a BASE part. BASE parts
can be created with any semantic type of your choice. Do set this semantic type
for BASE parts, but when detecting part types, use the PID's object type first.
Use this value if you created your own custom part item types so that other
applications that might not know your custom part type and could map it to the
nearest similar part type that it understands.
System Defined Part Types
There are a number of system-defined part types which must be
selected for use with the item type at design time. Some or all of
the part types can be selected.
Part Name Suggested Semantic Type Description
------------- ------------------------------- -----------------------------------------------
ICMANNOTATION DK_ICM_SEMANTIC_TYPE_ANNOTATION LOB Resource that holds an annotation.
ICMBASE DK_ICM_SEMANTIC_TYPE_BASE LOB Resource that holds part of the doc.
ICMBASETEXT DK_ICM_SEMANTIC_TYPE_BASE Text Resource that holds part of the doc.
ICMBASESTREAM DK_ICM_SEMANTIC_TYPE_BASE Stream Resource that holds part of the doc.
ICMNOTELOG DK_ICM_SEMANTIC_TYPE_NOTE Text Resource for any use. Ex: Change History.
-----------------------------------------------------------------------------------------------
Note: Constants listed are defined in DKConstantICM.
Part names are specified using string values containing the name listed.
Note: Remember the semantic types listed are suggestions and are not validated
or enforced. You should not expect these semantic types to always be set
by other applications or tools.
Adding / Modifying / Removing Parts
Parts may be added or removed by simply adding or removing them from
the Parts collection in the document. Parts are modified by modifying
them in the document item. Do not call .add(), .update(), or .del()
directly on the Parts. The document will be responsible for managing
the parts.
When adding and removing parts, there are multiple way to handle the
content. The typical ways are:
1) Loading the content via file name
2) Loading the content via a stream
3) Loading the content into memory in the DDO.
Although loading the content into memory is the simplest to do, this
approach is not recommended for any production application. As loading
content into memory takes up JVM heap memory for each user that is
doing this, it is very easy to get out of memory errors when there are
multiple users or if files are large. For this reason, either option
1 or 2, should be used for any production application.
All three methods are demonstrated in this sample.
Retrieving Parts
If you already have parts DDOs, either through an existing document
in memory or returned by query, you can retrieve parts directly the
same way you retrieve resource items and can be directly retrieved if
you already have the DDOs. However, if you want to start with a
document and retrieve its parts additional parts listing options
are available.
Parts are retrieved through the same retrieve interfaces shown in
SItemRetrievalICM. See SItemRetrievalICM for important information about
retrieve options in general. Through the same interfaces that you can
request attributes, children, and links, you can also request
parts to be listed by making additional selections using a
DKRetrieveOptionsICM instance. Additionally, you can also request
attributes and resource content for parts in the same call. Note that
resource content is restricted to single-item retrieve only for either
a single document with parts or individually retrieved parts as explained
in SResourceItemRetrievalICM.
When retrieving the content contained in parts, there are multiple way to
handle the content. The typical ways are:
1) Storing the content in a file
2) Getting a stream that will return the content
3) Loading the content into memory in the DDO, and accessing the memory buffer.
Although loading the content into memory is the simplest to do, this
approach is not recommended for any production application. As loading
content into memory takes up JVM heap memory for each user that is
doing this, it is very easy to get out of memory errors when there are
multiple users or if files are large. For this reason, either option
1 or 2, should be used for any production application.
All three methods are demonstrated in this sample.
An example of some of the parts-related retrieve options are listed below.
- DKRetrieveOptionsICM::partsList(boolean)
- DKRetrieveOptionsICM::partsAttributes(boolean)
- DKRetrieveOptionsICM::partsPropertyAclName(boolean)
- DKRetrieveOptionsICM::resourceContent(boolean)
* See DKRetrieveOptionsICM for full list of parts-related retrieve
options identified by names starting with parts____().
* Each option is explained in detailed reference documentation (Javadoc)
in DKRetrieveOptionsICM, including detailed explanations, performance
considerations, and more for each option.
*******************************************************************************/
// Imports
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import com.ibm.mm.sdk.common.*;
import com.ibm.mm.sdk.server.*;
/************************************************************************************************
* FILENAME: SDocModelItemICM.java
* ---------------------------------------------------------------------------
* DESCRIPTION: Creating / Updating / Deleting Document Model Items, Creating Parts,
* Accessing the Parts Collection, Adding Parts to a Document, Removing Parts
* from a Document, Deleting Parts
* ---------------------------------------------------------------------------
* DEMONSTRATION: Creating / Updating / Deleting Document Model Items
* Creating Parts
* Accessing the Parts Collection
* Adding Parts to a Document
* Removing Parts from a Document
* Deleting Parts
* List Document Parts
* ---------------------------------------------------------------------------
* COMMANDLINE USAGE: java SDocModelItemICM <database> <userName> <password>
* ---------------------------------------------------------------------------
* PREREQUISITES: The Data Model must be defined. If needed please run the following Samples
* - SAttributeDefinitionCreationICM
* - SAttributeGroupDefCreationICM
* - SReferenceAttrDefCreationICM
* - SItemTypeCreationICM
* The Item Types must be set to use the specified default Resource Manager.
* Please run the following samples.
* - SResourceMgrDefSetDefaultICM
* - SSMSCollectionDefSetDefaultICM
* NOTE: Sample SSampleModelBuildICM pulls together all of the above. It
* must be edited first for the RM Configuration information.
* ---------------------------------------------------------------------------
* FILES REQUIRED: SConnectDisconnectICM.java
* SResourceItemICM_Document1.doc
* SResourceItemICM_Text1.txt
* SResourceItemICM_Text2.txt
************************************************************************************************/
public class SDocModelItemICM{
// Using constants for File Names
public static final String LOB_FILE1_FILENAME = "SResourceItemICM_Document1.txt";
public static final String TEXT_FILE1_FILENAME = "SResourceItemICM_Text1.txt";
public static final String TEXT_FILE2_FILENAME = "SResourceItemICM_Text2.txt";
//-------------------------------------------------------------
// Main
//-------------------------------------------------------------
/**
* Run the Sample.
* @param argv[] String Array containing arguments. Optional arguments are <databse> <userName> <password>.
*/
public static void main(String argv[]) throws DKException, Exception{
// Defaults for connecting to the database.
String database = SConnectDisconnectICM.DEFAULT_DATABASE;
String userName = SConnectDisconnectICM.DEFAULT_USERNAME;
String password = SConnectDisconnectICM.DEFAULT_PASSWORD;
//------------------------------------------------------------
// Checking for input parameters
//--------------------------------------------------------------
if (argv.length < 3) { // if not all 3 arguments were specified, use defaults and report correct usage.
System.out.println("Usage: " );
System.out.println(" java SDocModelItemICM <database> <userName> <password>" );
System.out.println(" *** Some parameters not specified, using defaults..." );
System.out.println("");
} else { // otherwise enough parameters were specified, use the first 3 for the 3 parameters.
if (argv.length > 0) database = argv[0];
if (argv.length > 1) userName = argv[1];
if (argv.length > 2) password = argv[2];
}//end else
String ver = SConnectDisconnectICM.VERSION;
System.out.println("===========================================");
System.out.println("IBM DB2 Content Manager v"+ver);
System.out.println("Sample Program: SDocModelItemICM");
System.out.println("-------------------------------------------");
System.out.println(" Database: "+database);
System.out.println(" UserName: "+userName);
System.out.println("===========================================");
try{
//-------------------------------------------------------------
// Connect to datastore
//-------------------------------------------------------------
// See Sample SConnectDisconnectICM for more information
System.out.println("Connecting to datastore (Database '"+database+"', UserName '"+userName+"')...");
DKDatastoreICM dsICM = new DKDatastoreICM(); // Create new datastore object.
dsICM.connect(database,userName,password,""); // Connect to the datastore.
System.out.println("Connected to datastore (Database '"+dsICM.datastoreName()+"', UserName '"+dsICM.userName()+"').");
//-------------------------------------------------------------
// Create a Document
//-------------------------------------------------------------
// Please refer to SItemCreationICM for all non-resource related
// information.
//
// Remember that "S_docModel" is an Item Type defined in
// SItemTypeCreationICM.
System.out.println("Creating a Document...");
DKDDO ddoDocument = dsICM.createDDO("S_docModel", DKConstant.DK_CM_DOCUMENT);
System.out.println("Created a Document.");
//-------------------------------------------------------------
// Create Parts
//-------------------------------------------------------------
// Please refer to SResourceItemCreationICM for all resource
// related information.
System.out.println("Creating Parts...");
DKLobICM base = (DKLobICM) dsICM.createDDO("ICMBASE", DKConstantICM.DK_ICM_SEMANTIC_TYPE_BASE);
DKTextICM baseText1 = (DKTextICM) dsICM.createDDO("ICMBASETEXT", DKConstantICM.DK_ICM_SEMANTIC_TYPE_BASE);
DKTextICM baseText2 = (DKTextICM) dsICM.createDDO("ICMBASETEXT", DKConstantICM.DK_ICM_SEMANTIC_TYPE_BASE);
System.out.println("Setting Parts' MIME Type / Type of Contents...");
base.setMimeType("application/msword");
baseText1.setMimeType("text/plain");
baseText2.setMimeType("text/plain");
// Important: The three methods of loading content are shown below.
// Content should never be loaded into memory for any
// production application.
// Method 1 - Add content from file
String fileName = "SResourceItemICM_Document1.doc"; // Load content from file
DKNVPair[] location = new DKNVPair[1];
location[0] = new DKNVPair(DKConstantICM.FILE, fileName);
base.setAddLocation(location);
base.setOrgFileName(fileName);
// Method 2 - Add content from stream
fileName = "SResourceItemICM_Text1.txt"; // Load content from stream
InputStream iStream = new FileInputStream(fileName);
File file = new File(fileName);
//..Set the stream and the length that will be used to add the part
location = new DKNVPair[2];
location[0] = new DKNVPair(DKConstantICM.STREAM, iStream);
location[1] = new DKNVPair(DKConstantICM.LENGTH, file.length());
baseText1.setAddLocation(location);
baseText1.setOrgFileName(fileName);
// Method 3 - Add content from in memory buffer. Not recommended.
baseText2.setContentFromClientFile("SResourceItemICM_Text2.txt"); // Load content into memory
System.out.println("Created Parts.");
//-------------------------------------------------------------
// Accessing the DKParts Attribute
//-------------------------------------------------------------
// The DKParts attribute is accessed the same way shown in
// SItemCreationICM & SItemRetrievalICM. Note that this is
// the same way a DKFolder collection is accessed.
//
// This attribute can be found programatically as described in
// Sample SItemRetrievalICM.
System.out.println("Accessing the DKParts Attribute...");
DKParts dkParts = (DKParts) ddoDocument.getData(ddoDocument.dataId(DKConstant.DK_CM_NAMESPACE_ATTR,DKConstant.DK_CM_DKPARTS));
// Important: If the DDO is not retrieved, the above may
// fail due to a null pointer exception. The
// following accounts for this.
short dataid = ddoDocument.dataId(DKConstant.DK_CM_NAMESPACE_ATTR,DKConstant.DK_CM_DKPARTS);
if(dataid==0)
throw new Exception("No DKParts Attribute Found! DDO is either not a Document Model classified Item or Document has not been explicitly retrieved.");
dkParts = (DKParts) ddoDocument.getData(dataid);
System.out.println("Accessed the DKParts Attribute.");
//-------------------------------------------------------------
// Adding Parts to Document
//-------------------------------------------------------------
// Use the "Element" methods to group all updates into a single
// call to the Library Server. "Member" methods, if available,
// are immediately persistent, but at a cost of a Library Server
// call for every single call.
System.out.println("Adding Parts to Document...");
dkParts.addElement(base);
dkParts.addElement(baseText1);
dkParts.addElement(baseText2);
System.out.println("Added Parts to Document.");
//-------------------------------------------------------------
// Adding New Document to Persistent Datastore
//-------------------------------------------------------------
System.out.println("Adding New Document to Persistent Datastore...");
ddoDocument.add();
System.out.println("Added New Document to Persistent Datastore.");
//-------------------------------------------------------------
// Printing Document Part List
//-------------------------------------------------------------
System.out.println("Printing Document Part List...");
printDocumentPartList(ddoDocument);
System.out.println("Printed Document Part List.");
//-------------------------------------------------------------
// Check out the Document for Modification
//-------------------------------------------------------------
System.out.println("Checking Out / Locking Document Before Update...");
dsICM.checkOut(ddoDocument); // Must check out / lock before updating.
System.out.println("Checked Out / Locked Docuent Before Update.");
//-------------------------------------------------------------
// Delete a Part / Remove a Part
//-------------------------------------------------------------
System.out.println("Deleting a Part / Removing a Part...");
// Look for the Part to Remove. In this case, we will look for
// the baseText2.
dkIterator iter = dkParts.createIterator();
while(iter.more()){ // while there are still items, continue searching
DKLobICM part = (DKLobICM) iter.next(); // Move pointer to next element & return that object.
if(part.getPidObject().pidString().compareTo(baseText2.getPidObject().pidString())==0){
dkParts.removeElementAt(iter); // Now that we found baseText2, remove it.
}
}
System.out.println("Removed a Part from a Document.");
//-------------------------------------------------------------
// Make Changes Persistent
//-------------------------------------------------------------
System.out.println("Making Changes Persistent...");
ddoDocument.update(DKConstant.DK_CM_CHECKIN); // Don't forget to explicitly check in when finished.
System.out.println("Made Changes Persistent.");
//-------------------------------------------------------------
// Recreate DDO to Demonstrate Retrieval
//-------------------------------------------------------------
// For existing items, always recreate as blank DDOs and use
// retrieve to populate accurate data. This way you can easily
// distinguish between an accurate value that has been retrieved
// from an initial or default state. See SItemRetrievalICM
// sample for more information on this important topic.
System.out.println("Recreating Document DDO...");
DKPidICM pid = (DKPidICM) ddoDocument.getPidObject(); // Get the PID object
ddoDocument = dsICM.createDDOFromPID(pid); // *ALWAYS* use "FromPID" // Recreate Blank DDO Using PID String.
// OR suppose you want to have the PID string created and parsed:
String pidString = ddoDocument.getPidObject().pidString(); // Get the PID string
ddoDocument = dsICM.createDDOFromPID(pidString); // *ALWAYS* use "FromPID" // Recreate Blank DDO Using PID String.
System.out.println("Recreated Document DDO.");
//-------------------------------------------------------------
// Retrieving Document
//-------------------------------------------------------------
// This section covers retrieving a Document Item with the
// DKParts attribute / collection.
//
// Please review SItemRetrievalICM's retrieval option documentation.
System.out.println("Retrieving Document...");
// Suppose we want to retrieve the document attributes,
// parts list, and parts attributes. (However consider your
// scenario carefully for optimal retrieve option use).
DKRetrieveOptionsICM dkRetrieveOptions = DKRetrieveOptionsICM.createInstance(dsICM);
dkRetrieveOptions.baseAttributes(true);
dkRetrieveOptions.partsList(true);
// Parts attributes are normally only needed when content will be retrieved, so this
// option should not be used for a search result, as it will return information that
// likely will not be used for all items in the result. If just basic part
// information (Semantic Type, Mime Type, Original File Name, and file size) is needed,
// then add this line to optimize retrieval:
// dkRetrieveOptions.behaviorPartsAttributesCoreOnly();
dkRetrieveOptions.partsAttributes(true);
ddoDocument.retrieve(dkRetrieveOptions.dkNVPair());
System.out.println("Retrieved Document.");
//-------------------------------------------------------------
// Printing Document Part List
//-------------------------------------------------------------
System.out.println("Printing Document Part List...");
printDocumentPartList(ddoDocument);
System.out.println("Printed Document Part List.");
//-------------------------------------------------------------
// Retrieving content from a document
//-------------------------------------------------------------
// Important: The three methods of retrieving content are shown below.
// Content should never be loaded into memory for any
// production application.
//..Retrieve options to get content only
dkRetrieveOptions = DKRetrieveOptionsICM.createInstance(dsICM);
dkRetrieveOptions.resourceContent(true);
dkRetrieveOptions.behaviorSkipResourceAttrRefresh(true);
dkRetrieveOptions.behaviorSkipExistenceCheck(true);
//..Get the parts that we will retrieve content for
short id = ddoDocument.dataId(DKConstant.DK_CM_NAMESPACE_ATTR,DKConstant.DK_CM_DKPARTS);
dkParts = (DKParts)ddoDocument.getData(id);
dkIterator it = dkParts.createIterator();
//..Get the two parts from the collection
DKLobICM retrPart = (DKLobICM) it.next();
DKLobICM retrPart2 = (DKLobICM) it.next();
//..Method 1, Save content to a file
retrPart.retrieve("fileRetr.out",dkRetrieveOptions.dkNVPair());
//..Method 2, Get content as a stream
InputStream is = retrPart.getInputStream(dkRetrieveOptions.dkNVPair(), -1, -1);
writeStreamContentToFile(is, "streamRetr.out");
//..Method 3, Load content into memory and access the in memory buffer - Not recommended
retrPart2.retrieve(dkRetrieveOptions.dkNVPair());
byte[] buffer = retrPart2.getContent();
System.out.println(" Memory buffer size: " + buffer.length);
//-------------------------------------------------------------
// Deleting Document
//-------------------------------------------------------------
System.out.println("Deleting Document...");
ddoDocument.del();
System.out.println("Deleted Document.");
//-------------------------------------------------------------
// Disconnect from datastore & Destroy Reference
//-------------------------------------------------------------
// See Sample SConnectDisconnectICM for more information
System.out.println("Disconnecting from datastore & destroying reference...");
dsICM.disconnect();
dsICM.destroy();
System.out.println("Disconnected from datastore & destroying reference.");
//-------------------------------------------------------------
// Sample program completed without exception
//-------------------------------------------------------------
System.out.println("\n==========================================");
System.out.println("Sample program completed.");
System.out.println("==========================================\n");
}
//------------------------------------------------------------
// Catch & Print Exceptions
//------------------------------------------------------------
catch (DKException exc){
SConnectDisconnectICM.printException(exc); // Print the exception using the function listed below.
throw(exc);
} catch (Exception exc) {
SConnectDisconnectICM.printException(exc); // Print the exception using the function listed below.
throw(exc);
}
}// end main
/**
* Take the content from a stream and write it to a file.
*
* @param is Stream with content that is returned from CM
* @param fileName the name of the file to write the content to
* @throws IOException
*/
private static void writeStreamContentToFile(InputStream is, String fileName) throws IOException {
//..Write the content to a file
System.out.println(" Write stream content to file: " + fileName);
FileOutputStream fos = new FileOutputStream(fileName);
long total = 0;
byte[] buffer = new byte[1024*32];
int count;
while ((count = is.read(buffer)) != -1){
fos.write(buffer, 0, count);
total = total + count;
}
System.out.println(" Total bytes Read: " + total);
System.out.println(" Closing streams...");
is.close();
fos.close();
}
//=================================================================
// Wrapper Functions
//=================================================================
// The following are wrapper functions for functionality covered
// in this sample. These functions can be used by other samples.
/**
* Print Document Part List
* @param document Item based on Document Model classified Item Type.
**/
public static void printDocumentPartList(DKDDO document) throws Exception{
String documentItemId = ((DKPidICM)document.getPidObject()).getItemId();
// Get the DKParts object.
short dataid = document.dataId(DKConstant.DK_CM_NAMESPACE_ATTR,DKConstant.DK_CM_DKPARTS);
if(dataid==0)
throw new Exception("No DKParts Attribute Found! DDO is either not an Item of a Document Model classified Item Type or Document has not been explicitly retrieved.");
DKParts dkParts = (DKParts) document.getData(dataid);
// Print the list
System.out.println("Document ("+documentItemId+") Parts:");
dkIterator iter = dkParts.createIterator(); // Create an Iterator go to through DDO Collection.
while(iter.more()){ // While there are items still to be printed, continue
DKDDO part = (DKDDO) iter.next(); // Move pointer to next element & return that object.
System.out.println(" Item Id: "+((DKPidICM)part.getPidObject()).getItemId() +" ("+part.getPidObject().getObjectType()+")");
}
}
}//end class SDocModelItemICM