Wednesday, December 8, 2010

Oracle UCM 11g Remote Intradoc Client (RIDC) Integration with Oracle ADF 11g

Few days ago I was describing Oracle Universal Content Management (UCM) 11g connection setup from JDeveloper 11g for Oracle WebCenter 11g ADF task flows - Oracle Universal Content Management 11g and Oracle ADF/WebCenter 11g Integration. Its great we have out of the box WebCenter ADF task flows for document management in UCM. However, for complete business scenario implementations usually its not enough and we need to manage Content Repository programmatically. This can be achieved through Remote Intradoc Client (RIDC) API. Its quite hard to find any practical information about this API, but I managed to get code for UCM folder creation/removal and folder information. Will share it today with you, through sample application - UCMNewFolder.zip.

To compile this sample application, you will need to install RIDC library as extension for JDeveloper 11g. Please read instructions available here.

This application allows to add new employee, same time when new employee record is stored in database, it automatically creates new folder in UCM. Folder name is the same as employee ID, this allows to show documents related to selected employee. Adding new employee into the system:


Newly added employee is assigned with ID #232, folder with the same name is created in UCM (achieved programmatically using RIDC API) - WebCenter Document Management ADF task flow renders this folder:


UCM folder is changed dynamically, based on employee table row selection, because startFolderPath parameter points to managed bean method - where folder path is constructed based on current employee row selection:


We can upload new documents using out of the WebCenter functionality:


If someone is trying to remove employee record, we can check first if any documents exist for this employee. If there are documents available in Content Repository - employee removal can be prevented (achieved programmatically, using RIDC API):


Delete associated documents first:


Employee record is removed successfully:


Below I'm listing RIDC API methods from sample application. Connection with UCM is established through socket type, without specifying Content Repository password, Identity Propagation is done automatically through ADF Security Context.

1) Create new UCM folder

DataBinder dataBinder = idcClient.createBinder();
dataBinder.putLocal("IdcService", "COLLECTION_ADD");
dataBinder.putLocal("hasParentCollectionID", "true");
dataBinder.putLocal("dCollectionName", folderName);
dataBinder.putLocal("dParentCollectionID", this.getFolderIdFromPath(idcClient, userContext, PATH));
dataBinder.putLocal("dCollectionOwner", "sysadmin");
ServiceResponse response = idcClient.sendRequest(userContext, dataBinder);
DataBinder serverBinder = response.getResponseAsBinder();
System.out.println(serverBinder.getLocal("dCollectionID"));

There is no need to close RIDC connection after request, it is closed automatically when response.getResponseAsBinder() method is invoked. For new folder we must specify parent folder ID, it is internal UCM identificator, it can be retrieved from folder path:

2) UCM folder ID Info

DataBinder dataBinder = idcClient.createBinder();
dataBinder.putLocal("IdcService", "COLLECTION_INFO");
dataBinder.putLocal("hasCollectionPath", "true");
dataBinder.putLocal("dCollectionPath", path);
ServiceResponse response = idcClient.sendRequest(userContext, dataBinder);
DataBinder serverBinder = response.getResponseAsBinder();
DataResultSet resultSet = serverBinder.getResultSet("PATH");
DataObject dataObject = resultSet.getRows().get(resultSet.getRows().size() - 1);
folderId = dataObject.get("dCollectionID");

3) Delete UCM folder

DataBinder dataBinder = idcClient.createBinder();
dataBinder.putLocal("IdcService", "COLLECTION_DELETE");
dataBinder.putLocal("hasCollectionID", "true");
dataBinder.putLocal("dCollectionID", this.getFolderIdFromPath(idcClient, userContext, path));
dataBinder.putLocal("force", "true");
dataBinder.putLocal("deleteImmediate", "true");
ServiceResponse response = idcClient.sendRequest(userContext, dataBinder);
response.getResponseAsBinder();

4) Check if folder contains Files or internal Folders

DataBinder dataBinder = idcClient.createBinder();
dataBinder.putLocal("IdcService", "COLLECTION_GET_COLLECTIONS");
dataBinder.putLocal("hasCollectionID", "true");
dataBinder.putLocal("dCollectionID", this.getFolderIdFromPath(idcClient, userContext, path));
ServiceResponse response = idcClient.sendRequest(userContext, dataBinder);
DataBinder serverBinder = response.getResponseAsBinder();


DataResultSet resultSet = serverBinder.getResultSet("COLLECTIONS");
docCount += resultSet.getRows().size();


dataBinder = idcClient.createBinder();
dataBinder.putLocal("IdcService", "COLLECTION_GET_CONTENTS");
dataBinder.putLocal("hasCollectionPath", "true");
dataBinder.putLocal("dCollectionPath", path);
response = idcClient.sendRequest(userContext, dataBinder);
serverBinder = response.getResponseAsBinder();


resultSet = serverBinder.getResultSet("CONTENTS");
docCount += resultSet.getRows().size();

When I was working with UCM RIDC API, sometimes its very tough to get any info about API method return values. But there is a small trick, you can iterate through response result set names and get names for all return values:

Iterator iter = serverBinder.getResultSetNames().iterator();
while (iter.hasNext()) {
System.out.println(iter.next());
}

35 comments:

  1. I've been using RIDC for a while, its amazing how can you accomplish using this APIs
    Like for instance, if this employee has a picture, you can store this picture as a content in his folder, and instead of having iconized picture in Document Library taskflow, you can use dynamic converter to show the actual content of the document selected, same goes for PDF, Word and all extensions supported by Dynamic Converter.
    RIDC are really fun to play with, Thanks for this great post, great as always Andrejus

    ReplyDelete
  2. There are 3 kind of interfaces to access UCM

    - SAOP Webservices
    - Content Integration Suite (CSI)
    - Light Weight Remote Intradoc Client(RIDC)

    I am happy to see RIDC example , I will love if i can find
    something that do the same thing using other two access way.I will try to do it.

    This is fantastic stuff to connect to UCM from plain java.

    always a great job from andrejus

    ReplyDelete
  3. Thats right, however RIDC seems to be the most popular...

    Thanks,
    Andrejus

    ReplyDelete
  4. Hi,
    thank you for information about ridc. Where do you get information about input parameter to the different services?
    For example COLLECTION_GET_CONTENTS. Service reference only list the name.

    Arnolf

    ReplyDelete
  5. Hi,

    Its special Red Samurai trick :)

    Andrejus

    ReplyDelete
  6. Very good article. I also use RIDC in my project and I wonder is ther possible to search specified folder by custom metadata? From other hand I specify metadat as input parameter and the function (idoc script if exists) return me a folder id or a list of ID's.
    Do you think is it possible?

    ReplyDelete
  7. I believe this should be possible, you should check in API, operations for find.

    Andrejus

    ReplyDelete
  8. I have created a XML document as datafile and I converted into a stream, so how could I use this to upload or create a new web asset for a specific REGIONDEFINATION.

    I tried by creating a temp xml file, and uploaded to UCM, but this does not work for multiple request. I want to create a new data file for each request inside a folder.

    I am looking for SS_CHECKIN_WEB_ASSET idcservice, but unable to found much on it. I believe this is used to create or check in new data file into UCM, which does not need any primary file.

    Regards,
    Pranab

    ReplyDelete
  9. Hi Andrejus

    I am using a RIDC DataControl to retrieve the QuickSearch results from UCM. I have configured the below user settings for RIDC:

    RIDC Socket Type: socket
    Server Host Name: localhost
    Content Server Listener Port: 4444
    Authentication: Identity Propagation
    Username/Password: weblogic/weblogi

    But even though I am using "weblogic" user credentials and RIDC socket connection, the logs on the UCM shows as a "CIS connection". Also, the user is coming as "anonymous" rather than "weblogic" (used from Connection Repository) Below are the search logs:

    searchquery/7 08.09 15:55:41.195 IdcServer-1320 Query by anonymous from CIS
    searchquery/6 08.09 15:55:41.198 IdcServer-1320 preparedQueryText: (xCollectionID > `0` xCollectionID < `0`) (test1)
    searchquery/6 08.09 15:55:41.199 IdcServer-1320 Setting substr to other operator conv flag: '(xCollectionID > `0` xCollectionID < `0`) (test1)'
    searchquery/6 08.09 15:55:41.199 IdcServer-1320 Parsing universal query: '(xCollectionID > `0` xCollectionID < `0`) (test1)'
    searchquery/6 08.09 15:55:41.199 IdcServer-1320 Processing callback on query value '0'
    searchquery/6 08.09 15:55:41.199 IdcServer-1320 Processing callback on query value '0'
    searchquery/6 08.09 15:55:41.200 IdcServer-1320 Converted native query: '( SDATA(xCollectionID > 0) or SDATA(xCollectionID < 0) ) and ( ((DEFINESCORE((test1), RELEVANCE * .1)) ))'
    searchquery/6 08.09 15:55:41.200 IdcServer-1320 query(cache): &QueryText=%28xCollectionID+%3e+%600%60+%3cOR%3e+xCollectionID+%3c+%600%60%29+%3cAND%3e+%28%3cqsch%3etest1%3c%2fqsch%3e%29/((((z5075626C6963) WITHIN zdSecurityGroup))) and ((((idcnull) WITHIN dDocAccount)))//ORACLETEXTSEARCH [1,200]
    searchquery/6 08.09 15:55:41.200 IdcServer-1320 Execution time is 5.25 ms.

    Is there any further configuration I have to in order to mark the connection as RIDC (either in JDev or UCM) ?

    Thanks
    Khad

    ReplyDelete
  10. Hi,

    You should enable ADF Security for your ADF application, so it will not use "anonymous" user, but "authenticated". As I can see from your error log message.

    Identity propagation works only with ADF Security enabled.

    Regards,
    Andrejus

    ReplyDelete
  11. Thanks Andrejus. Do you have any step by step guide/blog for adding ADF security (11g) for the page which is built on DataControl?

    ReplyDelete
  12. Yes, hope this will help: http://andrejusb.blogspot.com/2010/11/things-you-must-know-about-adf-faces.html

    Andrejus

    ReplyDelete
  13. Identity propagation happens through the login page. On a successful login, same user credentials are propagated to retrieve the content for the Search.jspx page. I don't think, any additional ADF security configuration need to be added for 11g. I mean, once you configure the Search.jspx page on pages.xml with the required grants Page will be visible once you login to portal from login.jspx.

    ReplyDelete
  14. Yes, if you are using WebCenter. But I don't recommend using pages.xml at all, is full of bugs.

    Andrejus

    ReplyDelete
  15. Hi Andrejus

    Do you have any example or blog on calling Jive Search using REST Web services ? Any suggestions on this is highly appreciated?

    Thanks
    Khad

    ReplyDelete
  16. Hi Andrejus,

    Could you suggest how we automate document upload process in UCM. We have large volume of scanned PDF files more 34,0000 files per day.



    Ramesh

    ReplyDelete
  17. Hi Andrejus,
    I am looking for an example to add content under a folder. I have searched documentation and found "COLLECTION_CHECKIN_NEW" service for my purpose. But the documentation doesnot talk about the required parameters to be passed to this service. Can you please share an example.

    regards,
    Sunil Kumar Dhage

    ReplyDelete
  18. Hi Andrejus,
    I have created a folder using "COLLECTION_ADD". I am able to do "COLLECTION_INFO" on the same folder. But while adding content under the same folder and I am getting "Content item '(null)' was not successfully checked in. Unable to open folder".

    public void addContent() {
    IdcClient idcClient = null;
    try {
    idcClient = getIdcClient();

    IdcContext userContext = new IdcContext(USER);
    DataBinder binder = idcClient.createBinder();
    binder.putLocal ("IdcService", "COLLECTION_CHECKIN_NEW");
    // get the binder
    binder.putLocal ("dDocTitle", "Image file");
    binder.putLocal ("dDocName", "3.001");
    //binder.putLocal ("dDocAuthor", "Developer");
    binder.putLocal ("dDocType", "Document");
    binder.putLocal ("dSecurityGroup", "Public");
    //binder.putLocal ("createPrimaryMetaFile", "true");
    //binder.putLocal ("AllowPrimaryMetaFile", "true");

    binder.putLocal("hasParentCollectionID", "true");
    //binder.putLocal("dParentCollectionID", "739373434448003843");
    binder.putLocal("dParentCollectionID", this.getFolderIdFromPath(idcClient, userContext, PATH));
    // add a file

    binder.addFile ("primaryFile", new TransferFile(new File("D:\\P6WS\\RIDC Test\\src\\com\\oracle\\ridc\\poc\\3.jpg")));

    // checkin the file

    ServiceResponse response = idcClient.sendRequest(userContext, binder);
    DataBinder serverBinder = response.getResponseAsBinder();

    String dAction = serverBinder.getLocal("dAction");
    System.out.println("the dAction "+dAction);
    Map localData = serverBinder.getLocalData();
    for( Object key : localData.keySet()) {
    System.out.println(" Key "+key +" Value "+localData.get(key));
    }
    } catch (IOException e) {
    System.err.println(" Error due to "+e.getMessage());
    //e.printStackTrace();
    } catch (IdcClientException e) {
    System.err.println(" Error due to "+e.getMessage());
    e.printStackTrace();
    }

    ReplyDelete
  19. use chekin universal service and provide the metadata xCollection id.Then i belive it sits in the sepcified folder.you dont need this much coding stuff

    ReplyDelete
  20. Hi Andrejus,

    tried to run this aplicastion but got this exception

    Target URL -- http://127.0.0.1:7101/UCMNewFolder-ViewController-context-root/faces/main
    UCM user weblogic was specified as typeShapeUser and does not exist for repository UCMFileStore. Option list for content type security groups may be incomplete (calls will be made as anonymous user).
    Submission[id=1, service=oracle.webcenter.content.jcr.login, resource=UCMFileStore] caught exception running task
    javax.jcr.RepositoryException: Unable to load content server metadata model using GET_DOC_METADATA_INFO.
    at oracle.jcr.impl.ExceptionFactory.repository(ExceptionFactory.java:142)
    at oracle.stellent.jcr.IdcConnection.refreshMetadataModel(IdcConnection.java:89)
    at oracle.stellent.jcr.IdcPersistenceManagerFactory.createPersistenceManager(IdcPersistenceManagerFactory.java:189)
    at oracle.jcr.impl.OracleRepositoryImpl.login(OracleRepositoryImpl.java:444)
    at oracle.vcr.jam.LoginTask.call(LoginTask.java:68)
    at oracle.vcr.jam.LoginTask.call(LoginTask.java:29)
    at oracle.webcenter.concurrent.Submission$2.run(Submission.java:484)
    at java.security.AccessController.doPrivileged(Native Method)
    at oracle.security.jps.util.JpsSubject.doAsPrivileged(JpsSubject.java:313)
    at oracle.webcenter.concurrent.Submission.runAsPrivileged(Submission.java:498)
    at oracle.webcenter.concurrent.Submission.run(Submission.java:424)
    at oracle.webcenter.concurrent.Submission$SubmissionFutureTask.run(Submission.java:888)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at oracle.webcenter.concurrent.ModifiedThreadPoolExecutor$Worker.runTask(ModifiedThreadPoolExecutor.java:657)
    at oracle.webcenter.concurrent.ModifiedThreadPoolExecutor$Worker.run(ModifiedThreadPoolExecutor.java:682)
    at java.lang.Thread.run(Thread.java:662)
    Caused by: oracle.stellent.ridc.protocol.http.HttpProtocolException: Form validation failed
    at oracle.stellent.ridc.protocol.http.auth.FormAuthHandler.throwFormValidateException(FormAuthHandler.java:342)
    at oracle.stellent.ridc.protocol.http.auth.FormAuthHandler.handleFormResponse(FormAuthHandler.java:322)

    ... 16 more


    can you help.

    Regards,
    Raj

    ReplyDelete
  21. I see you are using weblogic user to test, do you have such user in UCM?

    Andrejus

    ReplyDelete
  22. Hi, i am new to RIDC thingy and would like to start a project with it. May i know more about the "getFolderIdFromPath" function and what kind of PATH to be expected eg. the folder and actual example?

    ReplyDelete
  23. You can download example from this blog.

    Andrejus

    ReplyDelete
  24. Hi

    The Oracle® Universal Content Management Services Reference Guide 11g Document is not a complete reference , and i have many problems with this guide .

    do you have any better guide?

    can you help me (please .........)


    bye

    ReplyDelete
  25. Hello, I have a problem with this example.
    <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <> <> <352b2f8e7566887c:-36694a18:13b09a8e815:-8000-00000000000001a8> <1353078105110> <[ServletContext@350520588[app:UCMNewFolder_application1 module:UCMNewFolder-ViewController-context-root path:/UCMNewFolder-ViewController-context-root spec-version:2.5 version:V2.0]] Servlet failed with Exception
    java.lang.NullPointerException
    at oracle.adf.model.binding.DCIteratorBinding.executeQueryIfNeeded(DCIteratorBinding.java:2160)
    at oracle.adf.model.binding.DCBindingContainer.internalRefreshControl(DCBindingContainer.java:3244)
    at oracle.adf.model.binding.DCBindingContainer.refresh(DCBindingContainer.java:2874)
    at oracle.adf.controller.v2.lifecycle.PageLifecycleImpl.prepareModel(PageLifecycleImpl.java:115)
    at oracle.adf.controller.v2.lifecycle.Lifecycle$2.execute(Lifecycle.java:137)
    at oracle.adfinternal.controller.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:197)
    at oracle.adfinternal.controller.faces.lifecycle.ADFPhaseListener.access$400(ADFPhaseListener.java:23)
    at oracle.adfinternal.controller.faces.lifecycle.ADFPhaseListener$PhaseInvokerImpl.startPageLifecycle(ADFPhaseListener.java:238)
    at oracle.adfinternal.controller.faces.lifecycle.ADFPhaseListener$1.after(ADFPhaseListener.java:274).......



    Can anyone suggest me, please?

    ReplyDelete
  26. Looks like connection to the DB failed, do you have HR schema?

    Andrejus

    ReplyDelete
  27. I am tring to Approve/Reject a workflow using RIDC. There seems to be a bug in the API. It allows my to Approve using the superuser (Weblogic). The API throws a valid error while rejecting as weblogic, but it throws a form validation error when I create user context using actual reviewer. Any suggestions?

    ORACLE UCM: 11.1.1.5

    ReplyDelete
  28. Hi friends,

    How we can integrate BPM and UCM using RIDC API.

    I know we need to Connect to UCM server
    Fetch the DOC
    Close the connection.

    So can u provide code using BPEL based Embedded activity.


    Regards,
    Suman

    ReplyDelete
  29. Hi,

    I would suggest to integrate from ADF attached to BPM, don't integrate directly into BPM flow. Basically you would need to build ADF UI Task Form with UCM access.

    This is on my TODO list to show how with sample app.

    Andrejus

    ReplyDelete
  30. hi Andrejus,

    I have the same requirement...

    I requirement goes this way..

    I need to Connect UCM server of my client machine.

    Download the Document and Show it in ADF Screen.

    Close the connections.


    I've created the Java Class to connect to UCM using RIDC.


    Now i need to Download the PDf file and Need to Show it in ADF UI.

    Can u plz give sample example on this.. i've to deliver soon.


    Regards,
    Pavan

    ReplyDelete
  31. Hi andreju,

    I am trying to upload a document to UCM

    below is the code

    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.putLocal("hasParentCollectionID", "true");

    binder.addFile("primaryFile", file);


    ServiceResponse response = idcClient.sendRequest(userContext, binder);
    DataBinder serverBinder = response.getResponseAsBinder();


    But i get an exception

    oracle.stellent.ridc.protocol.ProtocolException: java.io.IOException: Read error
    at oracle.stellent.ridc.protocol.http.IdcHttpProtocol.sendRequest(IdcHttpProtocol.java:345)
    at oracle.stellent.ridc.protocol.http.auth.FormAuthHandler.sendAuthenticatedRequest(FormAuthHandler.java:134)
    at oracle.stellent.ridc.protocol.http.IdcHttpProtocol.writeRequest(IdcHttpProtocol.java:204)
    at oracle.stellent.ridc.IdcClient.sendRequest(IdcClient.java:181)
    at view.UCM_API.uploadDocument(UCM_API.java:43)
    at view.backing.DocUpload.uploadListener(DocUpload.java:51)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.sun.el.parser.AstValue.invoke(Unknown Source)
    at com.sun.el.MethodExpressionImpl.invoke(Unknown Source)
    at org.apache.myfaces.trinidad.component.UIXComponentBase.broadcastToMethodExpression(UIXComponentBase.java:1300)
    at oracle.adf.view.rich.component.UIXDialog.broadcast(UIXDialog.java:97)
    at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl.broadcastEvents(LifecycleImpl.java:1018)
    at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl._executePhase(LifecycleImpl.java:386)
    at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:194)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:265)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
    at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:300)
    at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
    at oracle.webcenter.framework.events.dispatcher.EventDispatcherFilter.doFilter(EventDispatcherFilter.java:44)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
    at oracle.adf.model.servlet.ADFBindingFilter.doFilter(ADFBindingFilter.java:205)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
    at oracle.adfinternal.view.faces.webapp.rich.RegistrationFilter.doFilter(RegistrationFilter.java:106)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl$FilterListChain.doFilter(TrinidadFilterImpl.java:446)
    at oracle.adfinternal.view.faces.activedata.AdsFilter.doFilter(AdsFilter.java:60)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl$FilterListChain.doFilter(TrinidadFilterImpl.java:446)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl._doFilterImpl(TrinidadFilterImpl.java:271)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl.doFilter(TrinidadFilterImpl.java:177)
    at org.apache.myfaces.trinidad.webapp

    Can you please tell me whats the issue in the code.



    ReplyDelete
  32. Hi Andrejus,

    I am implemented the same in webcenter portal application.but I am facing some issue while using treebavigation on leftside of the document manager taskflow.Once I used that when I click in employee the document manager is not rendering.illegalStateExpetion.
    ppr problem.if i ran your application its running fine.
    I am using jdev 11.1.1.7.o and webcenter as 1.1.1.8.0 version.

    please suggest me solution.
    below type of error i am getting
    https://forums.oracle.com/thread/2607074

    please give me some solution.

    Thanks,

    Siva Sankar

    ReplyDelete