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