using System; using System.IO; using System.Text; using Plumtree.Remote.PRC; using Plumtree.Remote.PRC.Content; using Plumtree.Remote.PRC.Content.DataEntryTemplate; using Plumtree.Remote.PRC.Content.Folder; using Plumtree.Remote.PRC.Content.Item; using Plumtree.Remote.PRC.Content.PresentationTemplate; using Plumtree.Remote.PRC.Content.Property; using Plumtree.Remote.PRC.Content.SelectionList; using Plumtree.Remote.PRC.Content.Security; namespace ContentItemCommandLineExample { /// /// Command-line example of Content api /// /// ///This sample demonstrates all of the basic Content Server API /// objects. It can be run from the command line, creates all of /// its data, and cleans up after itself when it is done. /// ///This is an example of a programatically creating content items ///(records in the Content Server). The use case is a business /// process where something triggers a customer support incident. /// This creates a content item for the incident that can be viewed ///from the portal in a support incident portlet /// /// Before running this sample /// 1) Verify the endpointURL and username and password are correct in EstablishSession() /// 2) Set any break points to observe the sample as it runs /// 3) Comment out the folderManager.removeFolder(folder); if you want to keep the created items after the sample has run /// class ContentExample { /// /// Runs through the high-level logic of importing records /// into Content Server. /// [STAThread] static void Main(string[] args) { Console.WriteLine("Started Sample Application."); // Step 1: Get an EDK session and Content Server factory. IRemoteSession session = EstablishSession(); IContentFactory contentFactory = session.GetContentFactory(); Console.WriteLine("Step 1 - Session Established and Content Factory Created"); // Step 2: Get a Content Server folder. // All Content Server objects are stored in folders. Since // they are necessary for creating or querying objects, the // first real step is to get your application's folder(s). IFolder folder = RetrieveContentFolder(contentFactory); Console.WriteLine("Step 2 - Folder retrieved with name: " + folder.Name); // Step 3: Set security on the Content Server folder // All Content Server folders have access control lists // or ACLs associated with them. This step adds a user // and a group to this folder's ACL. folder = UpdateContentFolderSecurity(folder); Console.WriteLine("Step 3 - Folder security updated with name: " + folder.Name); // Step 4: Get the Data Entry Template (DET). // A DET is used when creating any collection of records. // It defines the fields within each record and logically // groups them together. A DET is analogous to creating // a new database table. In this example the DET represents // the fields in each customer support incident. IDataEntryTemplate det = RetrieveDET(contentFactory, folder); Console.WriteLine("Step 4 - Data Entry Template retrieved with name: " + det.Name); // Step 5: Get the Presentation Template (PT). // The PT describes how each record within a collection is // displayed. For each collection of records, there is // exactly one DET and PT. Both are needed to publish // individual records (content items). IPresentationTemplate pt = RetrievePT(contentFactory, det); Console.WriteLine("Step 5 - Presentation Template retrieved with name: " + pt.Name); // Step 6: Create content items. // Each support incident is a new content item. Content items // are records and analogous to rows in a database table. // // In a real application, we would actually want receive events // for when new support incidents are registered from some // other system such as Siebel. This would probably be done // as a loop, but for this example we will create a single // record. IContentItem ci = CreateSupportIncident(contentFactory, det, pt); Console.WriteLine("Step 6 - Content Item created with name: " + ci.Name); Console.WriteLine("\nThe Content Item has been created. \nYou may go to the Content Server Manager to observe the objects that have been created"); Console.WriteLine("When you are done, press any key to remove the created items and finish the sample"); Console.ReadLine(); // Step 7: Cleanup. // Normally an application would not erase all of its data, // but since this is a sample it should clean up after itself. // Comment out these lines if you want to see all of the // content that is created without setting break points. IFolderManager folderManager = contentFactory.GetFolderManager(); folderManager.RemoveFolder(folder); Console.WriteLine("Step 7 - Folder deleted"); Console.WriteLine("Finished Sample Application."); } /// /// Creates an EDK session. Change this to reference your SOAP endpoint. /// private static IRemoteSession EstablishSession() { // Change the values below to match your configuration. Uri endpointURL = new Uri("http://localhost/ptapi/services/QueryInterfaceAPI"); string username = "Administrator"; string password = ""; // Create a remote API session. IRemoteSession remoteSession = RemoteSessionFactory.GetExplicitLoginContext(endpointURL, username, password); return remoteSession; } /// /// Gets the Content Server folder used to store all Content /// Server objects for our application. ///

/// In this sample, we will create a new folder. In your /// real application you would likely have created the folder * already and will need to query for it here. ///

private static IFolder RetrieveContentFolder(IContentFactory factory) { // Get a folder manager for working with Content Server folders. IFolderManager folderManager = factory.GetFolderManager(); //If we were looking for an existing folder by path we could //use the following method //IFolder subFolder = folderManager.GetFolderByPath("/folder1/folder2"); //Instead, we will create our own folder for the sample // Get a reference to the root folder. It always exists. IFolder rootFolder = folderManager.GetRootFolder(); // Create a new folder. IFolder subFolder = folderManager.CreateFolder(rootFolder, "C# Example - Support Incidents"); subFolder.Store(); return subFolder; } /** * Gets the Content Server ACL for the folder used to store the Content * Server objects for our application. *

* In this sample, we will display the current ACL on the folder and will add * a new user and group entry for this folder. */ private static IFolder UpdateContentFolderSecurity(IFolder folder) { //get the existing ACL associated with this folder IFolderACL folderACL = folder.GetFolderACL(); // get the entries off of this ACL IFolderACLEntry [] entries = folderACL.GetEntries(); // loop through the entries and print out the values of each entry Console.WriteLine("Printing ACL for folder " + folder.Name); Console.WriteLine(entries.Length + " entries found in this ACL"); for (int i = 0; i < entries.Length; i++) { // get the individual entry IFolderACLEntry aclEntry = entries[i]; // print out its details Console.WriteLine("---------------------------------------------------------"); Console.Write("ObjectID for this FolderACLEntry " + aclEntry.GetObjectID()); Console.Write("MemberType for this FolderACLEntry " + aclEntry.GetMemberType()); Console.WriteLine("RoleType for this FolderACLEntry " + aclEntry.GetRoleType()); } // now add a new entry to this acl for the portal Guest user // the guest user's object id is 2. folderACL.AddUserEntry(2, RoleTypes.Editor); // now add a new entry to this acl for the portal Administrator's group // the portal Administrator's group's object id is 1. folderACL.AddGroupEntry(1, RoleTypes.Administrator); // store this acl to persist the changes back to the server folderACL.Store(); // loop through the entries and print out the values of each entry Console.WriteLine("Printing ACL for folder " + folder.Name); Console.WriteLine(entries.Length + " entries found in this ACL"); for (int i = 0; i < entries.Length; i++) { // get the individual entry IFolderACLEntry aclEntry = entries[i]; // print out its details Console.WriteLine("---------------------------------------------------------"); Console.Write("ObjectID for this FolderACLEntry " + aclEntry.GetObjectID()); Console.Write("MemberType for this FolderACLEntry " + aclEntry.GetMemberType()); Console.WriteLine("RoleType for this FolderACLEntry " + aclEntry.GetRoleType()); } return folder; } ///

/// Gets the DET that defines what fields are present in each /// customer support incident. ///

/// In this sample, we will create a new DET. In your real /// application, this method would probably query for an existing Data Entry Template. * existing DET. ///

private static IDataEntryTemplate RetrieveDET(IContentFactory factory, IFolder folder) { // // A Data Entry Template object is a collection of // property objects. Each property object represents // a field in the records associated with the DET. // // This sample uses all of the classes of properties // available in Content Server. Each customer support // incidents will have: // (integer) Incident ID // (boolean) If the incident has been resolved // (float) Incident severity rating // (date) Date the incident was opened // (text line) Customer name // (item reference) Link to other content item representing the customer // (selection list) The product the incident was reported in // (text block) Reported problem // (file) Logs of problem // (image) Screen shot of problem // // Get manager objects needed for creating a DET. IDataEntryTemplateManager detManager = factory.GetDataEntryTemplateManager(); IPropertyManager propertyManager = factory.GetPropertyManager(); ISelectionListManager slManager = factory.GetSelectionListManager(); // Create a DET object. IDataEntryTemplate det = detManager.CreateDataEntryTemplate(folder, "Support Incident Data Entry Template"); // Add an integer property. IIntegerProperty incident = propertyManager.CreateIntegerProperty("Incident ID", "The ticket number for this incident."); det.AddProperty(incident); // Add a boolean property IBooleanProperty resolved = propertyManager.CreateBooleanProperty("Resolved", "True if the incident has been closed; false if it is still open."); det.AddProperty(resolved); // Add a double property. IDoubleProperty severity = propertyManager.CreateDoubleProperty("Severity", "Percentage stating how severe the incident is."); det.AddProperty(severity); // Add a date property. IDateProperty opened = propertyManager.CreateDateProperty("Date Opened", "The date and time the incident was reported."); det.AddProperty(opened); // Add a text line property. // Text lines are brief strings without newline characters. // Use the text block property for storing longer strings. ITextLineProperty customerName = propertyManager.CreateTextLineProperty("Customer Name", "The name of the customer."); det.AddProperty(customerName); // Add an item reference property. // An item reference links to another content item. The // content item does not have to be associated with the // same DET. For example, we will link to a fictional // content item representing the customer that is having // the support problem; which would be associated with // a DET representing customers. // // Not shown is the item collection property. It is // similar to the item reference property, but links to // multiple content items. IItemReferenceProperty customerData = propertyManager.CreateItemReferenceProperty("Customer Information", "Links to information about the customer such as the contact and their phone number."); det.AddProperty(customerData); // Add a selection list property. // A selection list is a defined set of choices of which // one may be selected. This can be visualized as a // drop down box. string[] listValues = {"Portal", "Search Server", "Collaboration Server", "Content Server", "Analytics"}; ISelectionList selectionList = slManager.CreateSelectionList(folder, "Products Selection List", listValues); selectionList.Store(); ISelectionListProperty products = propertyManager.CreateSelectionListProperty("Product", "The product which the support incident is opened against", selectionList); det.AddProperty(products); // Add a text block property. // Text block properties are used to store long strings // that can span many lines. For short strings contained // on only one line, use the text line property instead. ITextBlockProperty description = propertyManager.CreateTextBlockProperty("Incident Description", "A writeup summarizing the problem the customer is experiencing."); det.AddProperty(description); // Add a file property. IFileProperty log = propertyManager.CreateFileProperty("Log File", "A log file taken while the problem occurred."); det.AddProperty(log); // Add an image property. IImageProperty screenShot = propertyManager.CreateImageProperty("Screen Shot", "A screen shot of the problem."); det.AddProperty(screenShot); // Actually store the DET and all the properties associated with it. det.Store(); return det; } /// /// Gets the PT that defines how to display customer support /// incident records. ///

/// In this sample, we will create a new PT. In your real /// application, this method would probably query an already * existing PT. ///

private static IPresentationTemplate RetrievePT(IContentFactory factory, IDataEntryTemplate det) { // // A Presentation Template object defines how content // items associated with a Data Entry Template should // be displayed. For content items to be displayed, // the must have a DET and PT associated with them // and be published. // // Get a PT manager object. IPresentationTemplateManager ptManager = factory.GetPresentationTemplateManager(); // Create a PT. StringBuilder templateBuffer = new StringBuilder(); templateBuffer.Append("\n") .Append("\n") .Append("\n") .Append("\n") .Append("\n") .Append("\n") .Append("\n") .Append("\n") .Append("\n") .Append("\n") .Append("\n") .Append("\n") .Append("
Incident ID
Created By on
Resolved
Severity
Date Opened
Customer Name
Customer Information
Product
Incident Description
Log File
Screen Shot
\n"); IPresentationTemplate pt = ptManager.CreatePresentationTemplate(det.GetContainingFolder(), "Customer Support Incident Presentation Template", templateBuffer.ToString()); // Store the PT. pt.Store(); // Validate the template text before using it to publish items String[] errorsInText = ptManager.ValidateTemplateText(pt, pt.TemplateText); if(errorsInText.Length != 0) { Console.WriteLine("Validate Template Text returned the following errors"); for(int i = 0; i < errorsInText.Length; i++) { Console.WriteLine("error[" + i + "]: " + errorsInText[i]); } } // Associate the PT with a DET. // There is a one-to-one correspondance between Data Entry // Templates and Presentation Templates. A PT must be attached // to a DET in order for content items to be published (i.e. // viewable). det.AttachPresentationTemplate(pt); det.Store(); return pt; } /// /// Creates a content item representing a single support /// incident. /// private static IContentItem CreateSupportIncident(IContentFactory factory, IDataEntryTemplate det, IPresentationTemplate pt) { // // Content items (CI) are associated with a single DET/PT // combination. There can be zero or more content // items associated with that pair. The DET defines // the fields in the content items while the PT // defines how to display them. // // Get a CI manager object. IContentItemManager ciManager = factory.GetContentItemManager(); // Create a new CI. IContentItem incident = ciManager.CreateContentItem(det.GetContainingFolder(), "Incident Name", det); // Assign the fields of the CI. // Each field is defined by the DET corresponding to the CI. IBaseProperty[] props = det.GetAllProperties(); // Incident ID. incident.SetIntegerPropertyValue(props[0], 123); // Resolved? incident.SetBooleanPropertyValue(props[1], false); // Severity. incident.SetDoublePropertyValue(props[2], 0.90 ); // Date incident opened. incident.SetDatePropertyValue(props[3], DateTime.Now); // Customer's name incident.SetTextLinePropertyValue(props[4], "Customer X"); // Link to another content item (CI) representing the customer's data. // Assumes there was another content item in the same folder named // with the customer's name. In reality this will return null since // we never created it. //IContentItem customer = ciManager.GetContentItem(det.GetContainingFolder(), "Customer X"); //incident.SetItemReferencePropertyValue(props[5], customer); // Product name containing problem. // When setting a selection list value, you must have your string exactly // match one of the values in the selection list. incident.SetSelectionListPropertyValue(props[6], "Portal"); // Incident description. incident.SetTextBlockPropertyValue(props[7], "The widget is broken.\nThe widget is fixed in the latest version and the fix must be back ported."); // Log file. //Commented out because we don't automatically have a WidgetBroken.log to upload. //To test this property, change the file name to a valid file on your system and uncomment //FileStream log = new FileStream("C:\\uploads\\WidgetBroken.log", FileMode.Open); //incident.SetFilePropertyValue(props[8], "WidgetBroken.log", log); // Screen shot. //Commented out because we don't automatically have a WidgetBroken.log to upload. //To test this property, change the file name to a valid file on your system and uncomment //FileStream screenShot = new FileStream("C:\\uploads\\WidgetBroken.gif", FileMode.Open); //incident.SetImagePropertyValue(props[9], "WidgetBroken.gif", screenShot); // Store the CI. ciManager.CheckInItem(incident, "Automatically created support incident."); // Publish the CI. // This will make it visible to end users. Simply checking in a content // item is not enough to make it visible. ciManager.PublishContentItem(incident); return incident; } } }