Ucm and Adf
Ucm and Adf
1 Table of Contents
2 3 Introduction..................................................................................................................................... 4 Prerequisites.................................................................................................................................... 4 3.1 4 Preparing UCM 11g for a socket connection........................................................................... 5
Document Service Taskflows ........................................................................................................... 7 4.1 4.2 Creating a connection to UCM ................................................................................................ 8 Configuring ADF security ....................................................................................................... 11 Configure security ......................................................................................................... 11 Add Users ...................................................................................................................... 14 Authorization to pages .................................................................................................. 15
Document Manager .............................................................................................................. 17 Documents - List View ........................................................................................................... 23 Documents - Recent documents ........................................................................................... 25 Documents - Content Presenter............................................................................................ 26 Templates for single items ............................................................................................ 26 Templates for multiple items ........................................................................................ 27 Adding content from your connection .......................................................................... 27
Content Server Data Control ......................................................................................................... 28 5.1 5.2 Creating the data control ...................................................................................................... 28 Methods of the data control ................................................................................................. 29 search method............................................................................................................... 29
Advanced search ................................................................................................................... 30 getAttributes method............................................................................................................ 30 getItems method ................................................................................................................... 30 getURI method ...................................................................................................................... 31 Using the methods: Parameter form and table .................................................................... 31 Add parameter form...................................................................................................... 31 Adding the table ........................................................................................................... 32 What happened: ............................................................................................................ 33 Test the page ................................................................................................................. 34
Using the methods: Adding a table without parameter form............................................... 35 Yannick Ongena | www.contribute.be 2
Using the RIDC API......................................................................................................................... 37 6.1 6.2 6.3 6.4 6.5 Install the RIDC extension ..................................................................................................... 37 Initialize the connection ........................................................................................................ 38 Configure the connection ...................................................................................................... 38 Authentication....................................................................................................................... 38 Services .................................................................................................................................. 38 Search service ................................................................................................................ 39 Check in Service ............................................................................................................. 40
6.5.1 6.5.2 7
Sample application: Document Manager ...................................................................................... 41 7.1 7.2 7.3 7.4 7.5 7.6 Creating the application ........................................................................................................ 43 Create the UCM Connection ................................................................................................. 45 Adding Search results to the page......................................................................................... 47 Search popup......................................................................................................................... 49 Upload popup ........................................................................................................................ 51 Delete document ................................................................................................................... 55
Final thoughts ................................................................................................................................ 58 8.1 8.2 8.3 Document Service Taskflows ................................................................................................. 58 Data control from Content Repository Connection .............................................................. 58 RIDC API ................................................................................................................................. 58
2 Introduction
In WebCenter there are different methods to integrate UCM with your custom applications or WebCenter spaces application. In this document I will describe different techniques to create application with lots of functionality from the Content Server. This document exist of 2 big parts. In the first part I will discuss the out of the box components (taskflows and data controls) to access your content in a WebCenter application. In the second part I will show how to use the RIDC API to access and manipulate content from your server. The style of this document is written as a tutorial with lots of screenshots so you can easily follow and create your own application based upon this.
3 Prerequisites
In order to build the examples from this white paper you will need the latest JDeveloper (version 11.1.1.3 at the moment of writing) with the WebCenter extension installed. You can check if you have the WebCenter extension installed from the about window in the help menu. Look in the extensions tab for WebCenter extensions. If you have not yet installed the extensions you can download them from within JDeveloper. In the help menu open the check for updates window. When you have the list of available downloads, look for webcenter and make sure they are checked. JDeveloper will then download the extensions and install them. After the installation process you will need to restart JDeveloper. We will also need a Content Server. In this paper I will also use the latest version (11g). The change between 10g and 11g is big so when I include screenshots of the content server, it may be different from your version if you are using 10g. Some configurations are different but I will try to explain most of the differences when we come to them. For most of the examples you also need to enable the folders_g component. This component let you organize content into folders. Webcenter works with folders all the time so it's a good thing to enable them.
3.1
In most of the examples we will use a socket connection to our UCM server. In UCM 10g, the port of the socket is asked upon install and is defaulted to 4444. In 11g this has changed. We need to specify the port in the Enterprise Manager and set the filter for trusted IP's. When we create a domain for UCM you will have an adminServer and a UCM_Server. The Enterprise Manager will be installed on the adminServer so in order to set the RIDC port we need to login to the EM. By default the adminServer uses port 7001 so if you use it on your localhost, the EM can be found on following URL: http://localhost:7001/em You need to login with the admin user you specified upon creation of the weblogic domain. After login select Oracle Universal Content Management from the menu on the left:
From there you need to open the settings by clicking UCM and select Configuration:
This will open the configuration window. from their you can set the Intradoc Server Port and the IP Address Filter. These settings will be used when you create a connection to your content server. The Intradoc Server Port is used to connect to your CS using a socket type of connection. You can set this to 4444. After you have made changed in the configuration, you need to reboot the UCM server. No need to restart the admin server, only the UCM server needs to be restarted.
Documents - Content Presenter: Component that allows you to show content and apply templates on that content to render it correctly Documents - Document Manager: An explorer like component to browse and manage files from your content server Documents - List view: Shows a list of content Documents - Recent Documents: shows a list of recent documents uploaded to the content server
In the following popup you need to specify the parameters of the connection:
General parameters Connection Name: specify a name for your connection Repository Type: The type of repository you want to use. In our case we want to use the Oracle Content Server. As you can see, the Configuration parameters will change when you have selected the OCS as repository type Set as primary connection for Documents Service: this checkbox is set to false by default. It is important you check this because the taskflows will use the primary connection. If you haven't set a connection as a primary connection, you will get errors when trying to run the application.
Configuration Parameters When you have selected OCS for content repository you will have following parameters: RIDC socket type: this is the type of socket that will be used to connect to the content server. It can be either socket, socketssl or web. server host name: the host name of your content server Content Server Listener port: the port of your content server. This is used when you use socket or socketssl. UCM uses 4444 for the RIDC socket but you need to configure this in the 11g version. In 10g version port 4444 will be configured upon install and is available after that. URL of the web server plugin: this is used when you set the socket type to web. It is a composition of the hostname, port and idcplg. for example if I have setup UCM on my localhost the web server plugin would be: http://localhost:16200/cs/idcplg Admin username: username of a user with admin rights in the content server Admin password: password of the user provided in the Admin Username field Keystore and other parameters: used for the socketssl type of connection.
when you want more information about these parameters you can press the Help button in the connection popup. This will open the JDeveloper Help center on the correct section about the UCM connection. These are the parameters I use for my connection: Socket type: socket server host name: localhost server listener port: 4444 Admin username: weblogic Admin password: weblogic1 A URL of the web server is not needed because i use the socket type instead of the web type. You can test the connection by pressing the Test Connection button. If it shows Success! you know your connection is good and you can start using the taskflows. Once that you have created the connection, you can see it in the connections folder in your application resources. When you pres the plus sign next to your connection, you can open it. It will open the folder view of your content server and show the contribute folder by default. This way you know that the connection has been created correctly.
10
in JDeveloper it is not hard to setup security. From the application menu select Secure and then Configure ADF security. Following popup will appear:
11
You have 3 methods: ADF Authentication and authorization: this will configure your application so users need to login using ADF security and you will also have the ability to secure your pages based upon roles that you assign to the users ADF Authentication: this will only configure authentication. No authorization based upon roles. Remove ADF security: this will remove the security from your application.
We will select the first option: ADF Authentication and authorization. This way you will see the complete wizard. The second option has a few steps less. Press next to configure the Authentication type. We need to select the web project were we want to define the security and the type of authentication. We will use a form based Authentication in our application and select the Generate default pages checkbox so JDeveloper will generate the default login and error html page.
In the next step we can let JDeveloper grant automatic policy grants. This way JDeveloper will create basic rules for all the pages/taskflow we have created. We will do this ourselves so select No Automatic grants:
12
The next step lets you specify what page should be shown upon successful login. You can also let JDeveloper generate a default page. Suppose we have an index.jspx page in our project, we can select it by using the browse button. As you can see, when you select a JSPX page, JDeveloper will automatically add the /faces/ to the path.
13
When you press next you will see a summary of what will be created and modified. We can press Finish to apply the configuration. 4.2.2 Add Users
Now that we have configured security, we need to add users to our application so we can login. Users are added in the jazn-data.xml. Upon deployment the users will be merged with the users already configured in the WLS security domain. In JDeveloper open the jazn-data.xml from the application resources, descriptors, META-INF folder.
At the bottom you will see following tabs: ADF policies: here we can define the policies for our pages and taskflows Users and roles: In this tab we can manage the users and roles Source: View the source of the jzan-data.xml
Select the Users and Roles tab. Press the Plus sign in order to create a new user in our application:
14
Once you have pressed the plus sign, the fields on the right will be enabled and you can create a new user. Be careful when selecting a password because you won't see it and you don't need to enter it twice. In weblogic the default policy is that the password is at least 8 characters long and contains at least one number. Otherwise it will not be created correctly. Do not forget to press tab or select another field once you have entered the password because it needs to be encrypted and this is done upon focus change from the password field. Press ctrl+s in order to save the user or press the save button. Make sure that the username you enter here also exist in the Content Server because we are using identity propagation. The password does not need to match the password from the same user in the content server but the username does. 4.2.3 Authorization to pages
Now that we have created a user we only need to authorize access to a page. This can be done from the page you want to authorize. So in JDeveloper, open the page and right click on it. Select edit authorization from the menu. As you see, it will open the jazn-data on the ADF policies tab:
Here you can define what roles are authorized to perform actions on a page. Make sure you have selected your page like in the image above. In the Grant to roles column, press the plus sign in order to open the Select Role popup. From there you can select a role you want authorize an action. Yannick Ongena | www.contribute.be 15
By default the anonymous-role and the authenticated-role is available. The first one is for public users who have not logged in to the application and the second if for the users who have logged in. If you haven't defined a role to a page, it means that nobody can access it so we are obliged to select at least one role. From the popup, check the authenticated-role as in the image below:
Press ok and you will see that authenticated-role. In the last column we can define the action that are allowed by the selected role. By default the view action is selected. This allows the user to view the page.
Now we have defined security on our application and we know how to authorize actions to pages. It is important that we define users that also exist in the content server. If you want to know more about ADF Security, you can follow the links on following page: http://wiki.oracle.com/page/ADF+Security
16
4.3
Document Manager
In this part we will add and use the document manager taskflow. We will start by creating a new webcenter application.
1) Create application and connection In JDeveloper select New from the File menu. The new gallery opens. Select Application from the list on the left and select Webcenter Application from the list on the right:
Give your application a name like DocumentManager, select the location and default package and press finish. Because we have created a new application, we will need to add a connection to the content server. Read the information from the previous part in order to create a connection. Don't forget to set the "Set as primary connection for document services". Below a screenshot from my connection as a reference:
17
2) Create JSPX page The next step is to create a new JSPX page were we will add the document manager. In JDeveloper right click the ViewController project and select new. The new gallary opens. Select JSF from the list on the left and select JSF Page from the list on the right as show in following image:
18
In the next popup choose a name for your JSF page like index.jspx. As a template we will use the "Oracle Three column layout". This way our page will have a default stretch layout with a header and three columns.
19
Press OK to create your page. 3) Add the document manager From the resource palette, open the Webcenter Service catalog and the taskflow folder. Select Documents - Document manager and drop it to the center facet of the page. JDeveloper will ask to create a region or dynamic region. Select region. You will also be prompted to add the doclib-service-view.jar to your project. This will add the needed library to your project 's classpath. The next popup you will see is the task flow input parameter window. The document manager will take 2 input parameters: connectionName: the name of the connection in case you don't want to use your primary connection startfolderPath: the path of the folder that will be used to start the document manager. To start our document manager we can leave the connectionName empty and set the startFolderPath to "/" as in the image below:
When you press OK the taskflow will be added to our page. What just happened? When you view your page in design view you will see that the taskflow will not be rendered because it can only be rendered at runtime. In the source we see following entry for the taskflow:
20
<af:region value="#{bindings.doclibdocumentlibrary1.regionModel}" id="r1"/> As you can see, the real definition of the taskflow can be found in the databindings of the page. From the bindings select the taskflow and click the pencil button to edit the taskflow definition. We will see the edit task flow binding popup were we can set the input parameters. When we view at the source of the binding we can see the "real" definition of the document manager taskflow: <taskFlow id="doclibdocumentlibrary1"
taskFlowId="/oracle/webcenter/doclib/view/jsf/taskflows/mainView.xml#doclib -document-library" activation="deferred" xmlns="http://xmlns.oracle.com/adf/controller/binding"> <parameters> <parameter id="startFolderPath" value="/"/> </parameters> </taskFlow> The taskFlowId is the name of the taskflow including the complete path of the taskflow class in the JAR file. You can also see the parameters. Because we did not specify the connectionName, it is not included in the parameters. 4) Run the page Now that we know what happened when we add the taskflow, we can press the run button. If your integrated WLS has not yet been started it will start itself when you right click your page and press RUN. It can take a few minutes depending on your computer... Finally JDeveloper will open your default browser and it will show the Document manager on your page as shown in the image below:
21
As you can see, you have a nice window with lots of features to manage your documents. You cam upload, delete, rename,... documents. You can also perform a search and when you press the Advanced button, you can do an advanced search. Because this taskflow is a general document manager taskflow that also need to work with a file system connection or an oracle portal connection, you don't have much options that UCM has to offer. For example in UCM you can define check-in profiles so you can preset some fields with values. These profiles can not be used in the document manager because it is a general component. It should be better to just remove the upload and delete button when we don't have the privileges for it but unfortunately this is not the case... 5) Security As you might notice, when you try to upload a document, you will get an error message saying you don't have permission to upload a document. This is because we don't have configured security on our application and to the CS server, we are the public user so we can't upload documents. You can add security to your application by following the steps in 4.2. When you do this, you will be able to upload and delete documents.
22
None of these parameters are required so you just can drop the taskflow to your page and run it without entering any parameter. It will show up on the page like this:
23
Notice that these documents are all the documents from the ROOT FOLDER. This means that if you have uploaded documents without assigning them to a folder, they won't show up in the list view. Because the default value of showFolders parameter is false, we don't see the subfolders of the root folder. If we set this value to true instead of the default false, we also will see the subfolders. It will not be visible as a hierarchy but each folder will be a link. In the left top of your page in running mode, you will notice a View link. With this link you can add additional columns to the list table:
As the name of the taskflows says, this is a list view. You aren't able to upload or delete files from here. It is only possible to view the documents in this taskflow, no matter what security you have. Offcourse, you will only see the documents you have rights to.
24
If you want to show only your own documents in the recent documents list than you can set the lastModifier parameter to ${securityContext.userName}. When we add the taskflow without changing anything on the parameters it will look like this:
You can't change anything about the taskflow. No extra columns, no upload or delete. It just shows a list with the name and icon of a document.
25
Below you can find a list of the out of the box templates provided by webcenter: 4.6.1 Templates for single items
Template Name Default Document Details View Default List Item View Default View (default when no template is selected) Default List Item View for Folders
For a description of these templates, you can take a look at section 14.2.4 in the "Developing webcenter application" guide in the help center of JDeveloper.
26
4.6.2
Template Name Accordion View Bulleted View Bulleted with Folder Label View Carousel View Icon View List View (default when no template is selected) List with Details Panel View Sortable Table View Tabbed View
Template ID (needed in taskflow parameter) oracle.webcenter.content.templates.default.list.panel.accordion oracle.webcenter.content.templates.default.list.bulleted oracle.webcenter.content.templates.default.list.bulleted.label oracle.webcenter.content.templates.default.list.carousel oracle.webcenter.content.templates.default.list.tile oracle.webcenter.content.templates.default.list.simple oracle.webcenter.content.templates.default.list.details.panel oracle.webcenter.content.templates.default.list.tabular oracle.webcenter.content.templates.default.list.panel.tabbed
For a description of these templates, you can take a look at section 14.2.4 in the "Developing webcenter application" guide in the help center of JDeveloper. 4.6.3 Adding content from your connection
There is a shortcut for adding single items to your page in design time. In JDeveloper we have configured a connection to our Content Server. You can browse it by following the hierarchy of your folders. You can easily drag & drop a file from the connection to your page. This will open a context menu where you can add the file as a goLink, inlineFrame or in the content presenter. When you select the content presenter, parameters of the taskflow will automatically be filled in accordingly:
27
28
In that popup, you can also add additional fields if you like. You only need to know the name of the field in the content server. An important field that we will need to use often is the folder ID of the item. In Content Server the folder ID is stored in a field called xCollectionID so if we want to add this to the data control, press the Plus sign at the bottom of the popup. You will see an additional row. Enter folderID for the name. As a type select Long. The JCR Path of the xCollectionID is following: jcr:content/idc:metadata/idc:xCollectionID Now we can press the OK button to create our data control. You can always add fields or change names once the data control has been created. In JDeveloper you can right click the data control and select Edit definition. This will bring up the same popup as when you create the data control. There you can add other fields.
Each method need some parameters and will return a collection of items. 5.2.1 search method
With the search method you can execute a search on the content server with basic parameter. The method takes following parameters: path: the path to start the search in isRecursive: if set to true, the search will look in each subfolder of the path provided, else it will only search in the provided path keyword: the keyword to look for namePattern: a pattern to match the name of your content
The return type is a record with the metadata of your content. It include all the fields defined in the definition of the data control.
29
The return type is the same as the search method. It includes all the fields defined in the data control.
30
As a first step we will add the search form to our left column. Drag the search method from your data control to the left column of the page. In the context menu you can choose between a method and an ADF method form. A method will only add the button but no parameter. The ADF Method form will add both the parameters and the search button. You will see following popup to specify the form:
In this popup you can specify the labels of the parameters and perhaps remove a parameter if it's not needed. Yannick Ongena | www.contribute.be 31
We are not going to change anything here so we can press ok. As you will see in JDeveloper, all the fields and the search button are added:
5.7.2 Adding the table The next step is to add the return to our page. Open the search method from your data control. Drag and drop the Return to the center of the page.
You will first see the context menu were you have a wide chose of controls to add to your page based upon the data from the return of the search method.
32
In our case, we will add a table with the data of the search result. From the context select Table => ADF Read only Table. We want a read only table because we don't have a way to save the changes to the content server. It will open the popup to specify which fields we want to add to our table. You will see all the fields that are specified in the data control. Because most of the fields are not needed for the users, we will remove most of the fields. We will only add the name, path, URI and title field. You can also arrange the fields with the two buttons on the right of the table. By selecting the Row selection we can select a row and by selecting Sorting we can sort the table. All the logic will be managed by ADF and we don't need to write anything in order to make this work. The specifications of the table looks something like this:
when we press ok, the table will be created on our page. 5.7.3 What happened:
Before we continue to test our page, a brief explanation on what JDeveloper has been created for us. The most important changes are made to our data bindings so bring up the data bindins. In the first column you will find the bindings. For each parameter in the parameter form, you will find an attribute value bound to a variable. Yannick Ongena | www.contribute.be 33
The search method is also bound in the bindings. When you select it and press the pencil button to bring up the edit screen you will see that the parameters are bound to the variables of the respective parameters from our form. This way when we execute the method, the search wil get his values from the input fields bound to those values. The return is bound to the search iterator. When you press the pencil button to edit it, you will notice a list of available attributes and which one are used for displaying. When you want to add a column to your table with a table that you did not select upon creation, you first need to add the attribute to the list on the right before you can add the column. The table uses that iterator and therefore it can only display the attributes from the Display Attributes list. 5.7.4 Test the page
Test your page right clicking it and press run. If everything went well, you will be able to test out the search form. You will notice that JDeveloper takes care of binding the parameters to the search method and refreshes the table when you press the search button. It should look something like in the example below:
As you will see, the URI will display as a goLink in the table. This is not clean so we will modify this. The goLink element is defined as following in our page: Yannick Ongena | www.contribute.be 34
<af:goLink text="goLink1" id="goLink1" destination="#{row.bindings.URI.inputValue}"/> You can replace it by changing the text to the binding of the title so it will become like this: <af:goLink text="#{row.title}" id="goLink1" destination="#{row.bindings.URI.inputValue}"/> Because the goLink will show the title, we can remove the title column from our table. If you want, you can also change the headerText from the URI table from #{bindings.Return.hints.URI.label} to #{bindings.Return.hints.title. label}
35
These parameters can also be EL so you can bind them to attributes from a backing bean. You can also just enter the fixed value in that popup. When you look at the bindings of the page you will notice that their aren't bindings for each parameter. You will only see the search method and return collection. When you edit the search method you will get the same popup as when you dropped the return to your page.
36
37
6.4 Authentication
In order to authenticate we create context. In that context we provide the username and password of the user we want to use to connect to the content server: IdcContext userPasswordContext = new IdcContext("sysadmin", "idc");
6.5 Services
The IDC API works by using services from the content server. Almost all the functionality in the content server is exposed as a service which you can use in the API. You only need to know the name and the parameter of the server. Luckily for us, there is a reference document listing all the services available with a brief explanation and the list of the parameters. Yannick Ongena | www.contribute.be 38
You can find the PDF on following link: http://download.oracle.com/docs/cd/E14571_01/doc.1111/e11011.pdf A service is called by using a data binder were you can add the parameters to the map. You always have at least one mandatory parameter which is the IdcService. This is the parameter for the name of the service we want to call. The instance of the IdcClient we created before is used to send the request. The request takes 2 parameters. The userContext which we also have created and the binder with the parameters. As a return, you will get a serviceResponse. That response also contain a binder . In case that the service returns a list of items, it will be made available using a ResultSet from the binder in the serviceResponse. Following snippet shows a basic service call without a ResultSet in the response. You can use this as a template for later use. DataBinder binder = idcClient.createBinder(); binder.putLocal ("IdcService", "serviceName"); binder.putLocal ("paramName", "paramValue"); ServiceResponse response = idcClient.sendRequest (userContext, binder); DataBinder serverBinder = response.getResponseAsBinder (); In following paragraphs I will show a few examples of services that can be used so it will all be clear. 6.5.1 Search service
The search service is the service used to call the search functionality of the content server. It is a simple search. There is another service for an advanced search which takes more parameters. IdcClientManager manager = new IdcClientManager(); IdcClient idcClient = manager.createClient("idc://localhost:4444"); IdcContext userContext = new IdcContext("weblogic", "weblogic1"); // populate the binder with the parameters DataBinder binder = idcClient.createBinder(); binder.putLocal ("IdcService", "GET_SEARCH_RESULTS"); binder.putLocal("QueryText",""); binder.putLocal ("ResultCount", "20"); ServiceResponse response = idcClient.sendRequest (userContext, binder); DataBinder serverBinder = response.getResponseAsBinder (); binder = response.getResponseAsBinder (); DataResultSet resultSet = binder.getResultSet ("SearchResults"); // loop over the results for (DataObject dataObject : resultSet.getRows ()) { System.out.println ("Title is: " + dataObject.get ("dDocTitle")); }
39
6.5.2
Check in Service
One service you will use a lot is the CHECKIN_UNIVERSAL service. With this service you can add a document to your document server. With this service you have several mandatory parameters: dDocName: The content ID of your item. When you have enabled auto generation of the content ID, this parameter is not required. dDocAuthor: the author of the document. If you do not specify this, the user who does the check-in will be the author. dDocTitle: Title of the document dDocType: content type of your item dSecurityGroup: the security group you want to assign to the item dDocAccount: in case you have enabled accounts, this parameters takes the account. Otherwise, this is not mandatory primaryFile: the actual file IdcClientManager manager = new IdcClientManager(); IdcClient idcClient = manager.createClient("idc://localhost:4444"); IdcContext userContext = new IdcContext("weblogic", "weblogic1"); DataBinder binder = idcClient.createBinder(); binder.putLocal ("IdcService", "CHECKIN_UNIVERSAL"); binder.putLocal ("dDocTitle", title); binder.putLocal ("dDocName", name); binder.putLocal ("dDocType", "Document"); binder.putLocal ("dSecurityGroup", "Public"); // add a file binder.addFile ("primaryFile",new File("C:/temp/file.txt"); // checkin the file ServiceResponse response = idcClient.sendRequest (userContext, binder); As you can see from this snippet, we add the file by using the addFile method of the binder instead of the putLocal to put a parameter on the map. The file is an instance of the java.io.File so nothing special about that. As you notice, using the RIDC services are very easy. You only need to know the name of the service and the parameters. Almost all of that information you can find in the reference document for the RIDC services: http://download.oracle.com/docs/cd/E14571_01/doc.1111/e11011.pdf In the next part we will put the techniques discusses here together and create a complete ADF Webcenter application using the UCM connection data control and the RIDC API. This way you can see it all in action.
40
41
The table of the search results comes from the search method of the data control we use from a UCM connection. The upload and remove method is written using the RIDC API. We will also use another method to get the ID of the folder we want to upload our document. This is also done using the RIDC API. When we have created the application, you should be able to combine different techniques to create advanced interfaces to integrate UCM. I will not explain the basics of ADF and JSF because it is out of scope of this document. When you start on this application you should know what data bindings are and how an ADF application works.
42
Application name: DocumentManager Choose a folder to store the application and package prefix. Click finish. Next step is to create our page: Right click the viewController project and select New from the context menu. The new gallery popup shows. Select JSF from the menu on the left and then JSF Page from the list on the right. The Create JSF Page popup shows. Give your page a name. Make sure the checkbox Create as XML document is selected. From the templates select the Oracle Three column Layout
43
We will also create one backing bean for our page. We will call this the IndexBean. Open the faces-config.xml from the WEB-INF folder. From the overview tab click on the PLUS sign of the managed beans. Give the bean a name, this will be used in our JSF page. Select a class and package. Make sure you have set the scope to session like in the example below:
If you have checked the checkbox "Generate Class if it does not exist", your class will be generated if you haven't created it already.
44
From the repository type select Oracle Content Server. Fill in the correct parameters for your connection. For more information on creating the connection, see section 4.1: Creating a connection to UCM.
45
After that the connection has been created, we need to create the data control it. Again in the Application resources, open the connection folder. Open the Content repository folder and right click your UCM connection. From the menu select create data control:
In the next popup we need to specify the attributes we want to use in the data control. We will need to add a field to add the ID of the document. This is not added to the data control by default. We need the ID for deleting content. Press the PLUS sign at the bottom of the popup. This will add an empty line to the attributes table. Give the attribute a name for example dID and in the JCR Path enter jcr:content/idc:metadata/idc:dID.
46
You should see the data control in the data control list of your application as in the image below:
From the context menu select Table => ADF Read only Table. This will open the Edit table columns popup. You will see all the attributes specified in the creation of the data control. We only need to show a few of them. All the rest can be removed. Following columns will be used in our table:
47
Make sure the rest of the columns are removed. When we press OK we will see the popup to populate the parameters of the search function. We will populate them later so just press ok. Now you should see the table on your page. We will make some small changes to table. For example he URI column will render the goLink with a default text goLink instead of a meaningful something. We can remove the complete column. In the source code look for following snippet and remove it: <af:column sortProperty="URI" sortable="false" headerText="#{bindings.Return.hints.URI.label} id="c5"> <af:goLink text="goLink1" id="goLink1" destination="#{row.bindings.URI.inputValue}"/> </af:column> Look for the title column and replace the outputText with following goLink: <af:goLink text="#{row.title}" destination="#{row.bindings.URI.inputValue}" id="ot5"/> This way, the title column will render as a link with the destination of the file. This way, when we click the title, the actual document will be downloaded. we will also add the commandButtons that will show the upload and search popup. Therefore we need to surround the table with a panelGroupLayout. Copy/paste following snippet before the <af:table> tag:
48
<af:panelGroupLayout id="pnlDocManager" layout="vertical"> <af:panelGroupLayout id="pnlHeader" layout="horizontal"> <af:commandButton text="Upload document" id="upload" partialSubmit="true"> <af:showPopupBehavior triggerType="click" popupId="popUpload"/> </af:commandButton> <af:spacer id="sp1" width="10px"/> <af:commandButton text="Remove" actionListener="#{IndexBean.deleteDoc}" id="delete" partialSubmit="true"> </af:commandButton> <af:spacer id="sp2" width="10px"/> <af:commandButton text="Search" id="search" partialSubmit="true"> <af:showPopupBehavior triggerType="click" popupId="popSearch"/> </af:commandButton> </af:panelGroupLayout> <af:spacer id="sp3" height="10px"/> You will get errors because the upload and search popup does not exist yet, but you can ignore them for now. We will create it in a few moments. You also see warnings for the actionListener of the delete button. Add following code after the </af:table> snippet to close the panelGroupLayout: </af:panelGroupLayout>
49
<af:popup id="popSearch" contentDelivery="lazyUncached"> <af:dialog id="dlgSearch" title="Search" affirmativeTextAndAccessKey="Search" dialogListener="#{IndexBean.searchListener}"> <af:panelFormLayout id="pnlSearch"> <af:inputText label="Path" id="txtPath" value="#{IndexBean.path}"/> <af:selectBooleanCheckbox label="Recursive" id="chkResursive" value="#{IndexBean.isRecursive}"/> <af:inputText label="Keyword" id="txtKeyword" value="#{IndexBean.keyword}"/> <af:inputText label="Name Pattern" id="txtPattern" value="#{IndexBean.namePattern}"/> </af:panelFormLayout> </af:dialog> </af:popup> In the code above we create the search popup. The popup will have a form on it with some inputText mapping to the search method. Now we still need to map the properties of our managed bean to the parameters of the search function. This is done in the bindings of the page. Bring up the bindings of the JSPX. In the left column you will find the search method. Select it and press the pencil in order to edit it. At the bottom of the popup you will see the parameters needed for the search method. In the value of the parameters, we can use expression language so we can bind them to properties in the managed bean as shown in following image:
Now that we have mapped the parameters to our manage bean, the search method will use the values we have set in the search popup. The only thing we need to do, is tell the search method to execute when we press the Search button from our dialog. This is done using the dialogListener . Add following code to the IndexBean.java file:
50
public void searchListener(DialogEvent dialogEvent) { if(dialogEvent.getOutcome() != DialogEvent.Outcome.no) { BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry(); OperationBinding operationBinding = bindings.getOperationBinding("search"); operationBinding.execute();operationBinding = bindings.getOperationBinding("Execute"); operationBinding.execute(); } } This code will check if we have pressed the Search or Cancel button. It will also get the BindingContainer so we can get an instance to the search operationBinding. This way we can execute the search method. Because we also have added the search popup to the partialTrigger of the table, it will get refreshed when we press the search button.
51
public static boolean uploadDocument (String name,String title,String type,File file,long folder) { try { IdcClientManager manager = new IdcClientManager(); IdcClient idcClient = manager.createClient(connection); IdcContext userContext = new IdcContext(username, password); DataBinder binder = idcClient.createBinder(); binder.putLocal ("IdcService", "CHECKIN_UNIVERSAL"); binder.putLocal ("dDocTitle", title); binder.putLocal ("dDocName", name); binder.putLocal ("dDocType", type); binder.putLocal ("xCollectionID", Long.toString(folder)); binder.putLocal ("dSecurityGroup", "Public"); binder.addFile ("primaryFile",file); ServiceResponse response = idcClient.sendRequest (userContext, binder); return true; } catch(Exception e) { System.out.println("Unable to upload document: " + e.getMessage()); return false; } } In the code above we define a method with the needed parameters to upload a document to the content server. As you also notice we use a try catch block to check if there are errors while uploading the document. It will return a boolean that tells if the upload has been successful or not. When we enter a folder, we don't know the exact ID of the folder so we need to ask the content server what the ID of the folder is based upon a path. Therefore we will create a function getFolderIDFromPath. This method takes one parameter: the path and it returns the ID of the folder. In order to retrieve the ID we use the COLLECTION_INFO service. This service will return the metadata of each folder in a specific path. Below is the code needed for the method:
52
public static long getFolderIDFromPath(String path) throws Exception { IdcClientManager manager = new IdcClientManager(); IdcClient idcClient = manager.createClient(connection); IdcContext userContext = new IdcContext(username, password); DataBinder request = idcClient.createBinder(); request.putLocal ("IdcService", "COLLECTION_INFO"); request.putLocal ("hasCollectionPath", "true"); request.putLocal ("dCollectionPath", path); ServiceResponse response = idcClient.sendRequest (userContext, request); DataBinder binder = response.getResponseAsBinder(); DataResultSet rs = binder.getResultSet("PATH"); DataObject da = rs.getRows().get(rs.getRows().size()-1); Long folderID = new Long(da.get("dCollectionID")); return folderID; } As you see, we use the last row of the DataResultSet to get the dCollectionID. This is because we get a row for each folder in the path so if we would ask the folder ID of following path: /Contribution Folder/project1/documentation We will have 3 rows in the DataResultSet. The first row is the metadata of the /contribution folder. The second row is the data of the project1 folder and the last row is the folder we want. Therefore we use following code to get the last row: DataObject da = rs.getRows().get(rs.getRows().size()-1); When we upload a file with JSPX using an af:inputFile, we get an instance of the UploadedFile in our managed bean. This instance can not be passed to our upload function. Therefore we need to convert it to a regular File object. This can be done using the inputStream of the UploadedFile. Following code will also be added to the UCM_API as a helper function to transform the inputStream to a File: public static File inputStreamToFile(InputStream is,String filename) { try { File f=new File(filename); OutputStream out=new FileOutputStream(f); byte buf[]=new byte[1024]; int len; while((len=is.read(buf))>0) out.write(buf,0,len); out.close(); return f; } catch(Exception e) { System.out.println("Error in converting file: " + e.getMessage()); return null; } } Yannick Ongena | www.contribute.be 53
This code will create a temporary file which we can use in the upload function. Now we have created everything we need to create the upload popup and call the upload method. In the IndexBean we first need to create a few properties that we will use in the upload form: private String name,title,type,folder; private UploadedFile file; In the JSPX file, after the ending tag of the search popup </af:popup> add following code: <af:popup id="popUpload" contentDelivery="lazyUncached"> <af:dialog id="dlgUpload" title="Upload" affirmativeTextAndAccessKey="Upload" dialogListener="#{IndexBean.uploadListener}"> <af:panelFormLayout id="pnlUpload"> <af:inputText id="txtName" label="Name" value="#{IndexBean.name}"/> <af:inputText id="txtTitle" label="Title" value="#{IndexBean.title}"/> <af:selectOneChoice id="ddlType" label="Document Type" value="#{IndexBean.type}"> <af:selectItem label="Document" value="Document"/> <af:selectItem label="Digital Media" value="DigitalMedia"/> </af:selectOneChoice> <af:inputText id="txtFolder" value="#{IndexBean.folder}" label="Folder"/> <af:inputFile id="txtFile" label="Primary File" value="#{IndexBean.file}"/> </af:panelFormLayout> </af:dialog> </af:popup> In this popup we create a form to upload a document and the parameters needed to identify the document in the content server. The folder field is a free text were users can add the path of the folder. The document type is limited to Document and DigitalMedia. As you see, we also use a dialogListener to execute our custom code when the user pressed the Upload button. In the dialogListener we will call the inputStreamToFile function to get a regular File from the UploadedFile and we also call the getFolderIDFromPath because we need this to set the xCollectionID. Following snippet shows the complete dialogListener:
54
public void uploadListener(DialogEvent dialogEvent) { if(dialogEvent.getOutcome() != DialogEvent.Outcome.no) { try { File f = UCM_API.inputStreamToFile( file.getInputStream(),file.getFilename()); long folderID = UCM_API.getFolderIDFromPath(folder); UCM_API.uploadDocument(name, title, type, f, folderID); BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry(); OperationBinding operationBinding = bindings.getOperationBinding("search"); operationBinding.execute(); operationBinding = bindings.getOperationBinding("Execute"); operationBinding.execute(); } catch(Exception e) { e.printStackTrace(); } } } When the upload has been done, we also execute the search function in order to refresh the table so it will show the uploaded document. However... For some reason, this does not work here. I haven't figured out why... In order to work around this issue, we can add a button below the table to refresh the table. Add following code just below the </af:table> tag if you wish to refresh the data when you want: <af:commandButton actionListener="#{bindings.search.execute}" text="Refresh Table" disabled="#{!bindings.search.enabled}" id="cb1"/> When the document has been uploaded and you press that button, the table will show the latest document.
55
public static boolean deleteContent(String id,String name) { try { IdcClientManager manager = new IdcClientManager(); IdcClient idcClient = manager.createClient(connection); IdcContext userContext = new IdcContext(username, password); DataBinder binder = idcClient.createBinder(); binder.putLocal ("IdcService", "DELETE_DOC"); binder.putLocal ("dID", id); binder.putLocal ("dDocName", name); ServiceResponse response = idcClient.sendRequest (userContext, binder); DataBinder serverBinder = response.getResponseAsBinder (); return true; } catch(Exception e) { System.out.println("Unable to delete: " + e.getMessage()); return false; } } we also add a try catch block so we can check if the deletion has been correctly executed. In our managed bean we need to get a value from the iterator that populates the table. That iterator will automatically point to the selected row so we can easily request a value from it. This is also done using the BindingContainer. Following method is a helper function to request an attribute value from a specific iterator: public Object getAttributeValue(String iterator,String attribute) { BindingContainer vBindingContainer = BindingContext.getCurrent().getCurrentBindingsEntry(); DCBindingContainer vDCBindingContainer = (DCBindingContainer)vBindingContainer; DCIteratorBinding vDCIteratorBinding = vDCBindingContainer.findIteratorBinding(iterator); Row vRow = vDCIteratorBinding.getCurrentRow(); return vRow.getAttribute(attribute); } We use this method in the deleteDoc actionListener. Following snippet is the actionListener for the delete button:
56
public void deleteDoc(ActionEvent e) { String ID = (String)this.getAttributeValue("searchIterator", "dID"); String name = (String)this.getAttributeValue("searchIterator", "title"); UCM_API.deleteContent(ID, name); BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry(); OperationBinding operationBinding = bindings.getOperationBinding("search"); operationBinding.execute(); operationBinding = bindings.getOperationBinding("Execute"); operationBinding.execute(); } In this method we will also call the search method to execute it in order to refresh the table but it does not seem to work... If you want to refresh the table, you can use the button added in the upload functionality.
57
8 Final thoughts
To conclude this document you can find a brief summary that lets you easily choose which method you can best use in your use case:
58