/*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 Informaiton:
Doc Model Items are an extension of non-resource items. Doc Model Parts
are resource items. Therefore, both the standar item & resource item
samples are pre-requisit 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.h
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.
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.
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.
*******************************************************************************/
// Includes / Imports
#include <DKConstant.h>
#include <DKConstantICM.h>
#include <DKDatastoreICM.hpp>
#include <DKParts.hpp>
#include <DKLobICM.hpp>
#include <DKRetrieveOptionsICM.hpp>
#include <DKTextICM.hpp>
#include "SConnectDisconnectICM.hpp"
#include "SDocModelItemICM.hpp"
/************************************************************************************************
* 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.
* Plese run the following samples.
* - SResourceMgrDefSetDefaultICM
* - SSMSCollectionDefSetDefaultICM
* NOTE: Sample SSampleModelBuildICM pulls together all of the above. It
* must be edited first for the RM Confiuration information.
* ---------------------------------------------------------------------------
* FILES REQUIRED: SConnectDisconnectICM.hpp/cpp
* SDocModelItemICM_launch.cpp
* SDocModelItemICM.hpp
* SResourceItemICM_Document1.doc
* SResourceItemICM_Text1.txt
* SResourceItemICM_Text2.txt
************************************************************************************************/
//-------------------------------------------------------------
// Main
//-------------------------------------------------------------
/**
* Run the Sample.
* @param argc Argument Count / Number of Arguments Specified
* @param argv[] String Array containing arguments. Optional arguments are <databse> <userName> <password>.
* @return Returns SConnectDisconnectICM_RC_SAMPLE_PASSED (0) if no sample program completed, SConnectDisconnectICM_RC_SAMPLE_FAILED (-1) if any errors / exceptions were caught.
**/
int SDocModelItemICM::main(int argc, char *argv[]){
// Defaults for connecting to the database.
char * database = SConnectDisconnectICM_DEFAULT_DATABASE;
char * userName = SConnectDisconnectICM_DEFAULT_USERNAME;
char * password = SConnectDisconnectICM_DEFAULT_PASSWORD;
//------------------------------------------------------------
// Checking for input parameters
//--------------------------------------------------------------
if (argc < 4) { // if not all 3 arguments were specified, use defaults and report correct usage.
cout << "Usage: " << endl;
cout << " SDocModelItemICM <database> <userName> <password>" << endl;
cout << " *** Some parameters not specified, using defaults..." << endl;
cout << endl;
} else { // otherwise enough parameters were specified, use the first 3 for the 3 parameters.
if (argc > 1) database = argv[1];
if (argc > 2) userName = argv[2];
if (argc > 3) password = argv[3];
}//end else
char * ver = SConnectDisconnectICM_VERSION;
cout << "===========================================" << endl;
cout << "IBM DB2 Content Manager v" << ver << endl;
cout << "Sample Program: SResourceItemICM" << endl;
cout << "-------------------------------------------" << endl;
cout << " Database: " << database << endl;
cout << " UserName: " << userName << endl;
cout << "===========================================\n" << endl;
try{
//-------------------------------------------------------------
// Connect to datastore
//-------------------------------------------------------------
// See Sample SConnectDisconnectICM for more information
cout << "Connecting to datastore (Database '" << database << "', UserName '" << userName << "')..." << endl;
DKDatastoreICM* dsICM = new DKDatastoreICM(); // Create new datastore object.
dsICM->connect(database,userName,password,""); // Connect to the datastore.
cout << "Connected to datastore (Database '" << dsICM->datastoreName() << "', UserName '" << dsICM->userName() << "')." << endl;
//-------------------------------------------------------------
// Create a Document
//-------------------------------------------------------------
// Please refer to SItemCreationICM for all non-resource related
// information.
//
// Remember that "S_docModel" is an Item Type defined in
// SItemTypeCreationICM.
cout << "Creating a Document..." << endl;
DKDDO* ddoDocument = dsICM->createDDO("S_docModel", DK_CM_DOCUMENT);
cout << "Created a Document." << endl;
//-------------------------------------------------------------
// Create Parts
//-------------------------------------------------------------
// Please refer to SResourceItemCreationICM for all resource
// related information.
cout << "Creating Parts..." << endl;
DKLobICM* base = (DKLobICM*) dsICM->createDDO("ICMBASE", DK_ICM_SEMANTIC_TYPE_BASE);
DKTextICM* baseText1 = (DKTextICM*) dsICM->createDDO("ICMBASETEXT", DK_ICM_SEMANTIC_TYPE_BASE);
DKTextICM* baseText2 = (DKTextICM*) dsICM->createDDO("ICMBASETEXT", DK_ICM_SEMANTIC_TYPE_BASE);
cout << "Setting Parts' MIME Type / Type of Contents..." << endl;
base->setMimeType("application/msword");
baseText1->setMimeType("text/plain");
baseText2->setMimeType("text/plain");
cout << "Loading Content into Parts..." << endl;
base->setContentFromClientFile("SResourceItemICM_Document1.doc"); // Load the file into memory.
baseText1->setContentFromClientFile("SResourceItemICM_Text1.txt");
baseText2->setContentFromClientFile("SResourceItemICM_Text2.txt");
cout << "Created Parts." << endl;
//-------------------------------------------------------------
// 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.
cout << "Accessing the DKParts Attribute..." << endl;
DKParts* dkParts = (DKParts*)(dkCollection*) ddoDocument->getData(ddoDocument->dataId(DK_CM_NAMESPACE_ATTR,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(DK_CM_NAMESPACE_ATTR,DK_CM_DKPARTS);
if(dataid==0)
throw DKException("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*)(dkCollection*) ddoDocument->getData(dataid);
cout << "Accessed the DKParts Attribute." << endl;
//-------------------------------------------------------------
// 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.
cout << "Adding Parts to Document..." << endl;
dkParts->addElement((dkDataObjectBase*)(DKDDO*)base);
dkParts->addElement((dkDataObjectBase*)(DKDDO*)baseText1);
dkParts->addElement((dkDataObjectBase*)(DKDDO*)baseText2);
cout << "Added Parts to Document." << endl;
//-------------------------------------------------------------
// Adding New Document to Persistent Datastore
//-------------------------------------------------------------
cout << "Adding New Document to Persistent Datastore..." << endl;
ddoDocument->add();
cout << "Added New Document to Persistent Datastore." << endl;
//-------------------------------------------------------------
// Printing Document Part List
//-------------------------------------------------------------
cout << "Printing Document Part List..." << endl;
printDocumentPartList(ddoDocument);
cout << "Printed Document Part List." << endl;
//-------------------------------------------------------------
// Check out the Document for Modification
//-------------------------------------------------------------
cout << "Checking Out / Locking Document Before Update..." << endl;
dsICM->checkOut(ddoDocument); // Must check out / lock before updating.
cout << "Checked Out / Locked Docuent Before Update." << endl;
//-------------------------------------------------------------
// Delete a Part / Remove a Part
//-------------------------------------------------------------
cout << "Deleting a Part / Removing a Part..." << endl;
// 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()->value(); // Move pointer to next element & return that object.
if(strcmp(((DKPidICM*)part->getPidObject())->pidString(),((DKPidICM*)baseText2->getPidObject())->pidString())==0){
dkParts->removeElementAt(*iter); // Now that we found baseText2, remove it.
}
}
delete(iter); // Free Memory
cout << "Removed a Part from a Document." << endl;
//-------------------------------------------------------------
// Make Changes Persistent
//-------------------------------------------------------------
cout << "Making Changes Persistent..." << endl;
ddoDocument->update(DK_CM_CHECKIN); // Don't forget to explicitly check in when finished.
cout << "Made Changes Persistent." << endl;
//-------------------------------------------------------------
// Recreate DDO to Demonstrate Retrieval
//-------------------------------------------------------------
// When recreating a DDO for an existing item in C++, always
// use createDDOFromPID() that states "FromPID", not any of
// the deprecated "createDDO" variations. This ensures a clean,
// blank DDO and avoids uncessary initialization of metadata
// structures with defaults, intiial values, and empty collections.
//
// 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 initialial or default state. See SItemRetrievalICM
// sample for more information on this important topic.
cout << "Recreating Document DDO..." << endl;
DKDDO* original = ddoDocument; // Save a reference to free the original after the DDO is recreated. The PID object is needed to pass to createDDOFromPID and therefore the DDO that owns the PID cannot be deleted until after recreated.
DKPidICM* pid = ((DKPidICM*)ddoDocument->getPidObject()); // Get the PID object
ddoDocument = dsICM->createDDOFromPID(pid); // *ALWAYS* use "FromPID" // Recreate Blank DDO Using PID String.
delete(original); // Free the original DDO that we have now replaced in pointer "ddoDocument".
// OR suppose you want to have the PID string created and parsed:
DKString pidString = ((DKPidICM*)ddoDocument->getPidObject())->pidString(); // Get the PID string
delete(ddoDocument); // Free the original DDO since we are going to replace the pointer "ddoDocument". We can free it before recreating because we already generated the PID string and do not need a reference to the PID objects anymore.
ddoDocument = dsICM->createDDOFromPID(pidString); // *ALWAYS* use "FromPID" // Recreate Blank DDO Using PID String.
cout << "Recreated Document DDO." << endl;
//-------------------------------------------------------------
// Retrieving Document
//-------------------------------------------------------------
// This section covers retrieving a Document Item with the
// DKParts attribute / collection.
//
// Please review SItemRetrievalICM's retrieval option documentation.
cout << "Retrieving Document..." << endl;
// 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);
dkRetrieveOptions->partsAttributes(TRUE);
ddoDocument->retrieve(dkRetrieveOptions->dkNVPair(),dkRetrieveOptions->dkNVPairLength());
cout << "Retrieved Document." << endl;
//-------------------------------------------------------------
// Printing Document Part List
//-------------------------------------------------------------
cout << "Printing Document Part List..." << endl;
printDocumentPartList(ddoDocument);
cout << "Printed Document Part List." << endl;
//-------------------------------------------------------------
// Deleting Document
//-------------------------------------------------------------
cout << "Deleting Document..." << endl;
ddoDocument->del();
delete(ddoDocument); // Free Memory
delete(dkRetrieveOptions); // Free Memory
cout << "Deleted Document." << endl;
//-------------------------------------------------------------
// Disconnect from datastore & Destroy Reference
//-------------------------------------------------------------
// See Sample SConnectDisconnectICM for more information
cout << "Disconnecting from datastore & destroying reference..." << endl;
dsICM->disconnect();
delete(dsICM);
cout << "Disconnected from datastore & destroying reference." << endl;
//-------------------------------------------------------------
// Sample program completed without exception
//-------------------------------------------------------------
cout << "\n==========================================" << endl;
cout << "Sample program completed." << endl;
cout << "==========================================\n" << endl;
}
//------------------------------------------------------------
// Catch & Print Exceptions
//------------------------------------------------------------
catch (DKException &exc){
SConnectDisconnectICM::printException(exc); // Print the exception to the screen
return(SConnectDisconnectICM_RC_SAMPLE_FAILED); // Report using return code that it failed
}
return(SConnectDisconnectICM_RC_SAMPLE_PASSED); // If no exceptions were thrown, return a code to indicate passed.
}// end main
//=================================================================
// 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 of a Document Model classified Item Type.
**/
void SDocModelItemICM::printDocumentPartList(DKDDO* document){
DKString documentItemId = ((DKPidICM*)document->getPidObject())->getItemId();
// Get the DKParts object.
short dataid = document->dataId(DK_CM_NAMESPACE_ATTR,DK_CM_DKPARTS);
if(dataid==0)
throw DKException("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*)(dkCollection*) document->getData(dataid);
// Print the list
cout << "Document (" << documentItemId << ") Parts:" << endl;
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()->value(); // Move pointer to next element & return that object.
cout << " Item Id: " << ((DKPidICM*)part->getPidObject())->getItemId() << " (" << ((DKPidICM*)part->getPidObject())->getObjectType() << ")" << endl;
}
delete(iter); // Free Memory
}