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:

Amr Ismail Gawish said...

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

Andrejus Baranovskis said...

Thanks for great feedback :)

Hasim said...

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

Andrejus Baranovskis said...

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

Thanks,
Andrejus

Anonymous said...

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

Andrejus Baranovskis said...

Hi,

Its special Red Samurai trick :)

Andrejus

pawel said...

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?

Andrejus Baranovskis said...

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

Andrejus

Pranab said...

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

Khad said...

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

Andrejus Baranovskis said...

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

Khad said...

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

Andrejus Baranovskis said...

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

Andrejus

Khad said...

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.

Andrejus Baranovskis said...

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

Andrejus

Khad said...

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

Ramesh Chandra said...

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

Sunil Dhage said...

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

Andrejus Baranovskis said...

I will, on my todo list ;)

Andrejus

Sunil Dhage said...

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();
}

Anonymous said...

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

raj said...

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

Andrejus Baranovskis said...

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

Andrejus

Anonymous said...

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?

Andrejus Baranovskis said...

You can download example from this blog.

Andrejus

Anonymous said...

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

leong said...

Thanks!! you helps me a lot!

Anton Kabachkov said...

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?

Andrejus Baranovskis said...

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

Andrejus

mahendra said...

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

Suman Vadlamudi said...

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

Andrejus Baranovskis said...

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

Pavan kumar said...

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

Vijayalakshmi said...

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.



Siva Sankar said...

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