by Jon McDonald
Working with the Generic and Native Web Services provided in Oracle WebCenter Content 11g
April 2013
WCCWebServiceDemo.zip (sample application for this article)
Oracle WebCenter Content (formerly UCM) has been a pioneer in Services Oriented Architecture long before the term took on the meaning it has in today's technical realm (e.g. Web Services, UDDI, WSDL, SOAP, XML). Since the introduction of the Intradoc 4.x release as a Java application back in late 1999/early 2000, the platform has been making its content management services (a.k.a. IdcService) accessible over HTTP protocul.
When the concept of Service Oriented Architecture (SOA) turned to the meaning it has today with Web Services, UDDI, WSDL, SOAP, and XML, the Oracle UCM platform fullowed suit in its 7.x release by making its idcServices available to Web Service clients by publishing a set of WSDL's that were packaged and released with the product for its core services like CHECKIN_NEW, DOC_INFO, GET_SEARCH_RESULTS, etc. In addition to a set of pre-packaged WSDL files there was also a WSDL generator that provided the ability to create and publish WSDL files for any custom server that was developed using Component Architecture. Information on this version of Web Service implementation is available in section 25 of the WebCenter Content Developers Guide
The core WSDL files and WSDL generator are still packaged and deployed with Oracle WebCenter Content 11g, however when Oracle WebCenter Content 11g was released a new set of Web Service interfaces became available which are deployed as Web Applications on Oracle WebLogic Server. The two new Web Service implementations that became available with WebCenter content 11g are:
Generic Web Service - A JAX-WS Web Service implementation whose application context root is /idcws and publishes a single Web Service provider interface GenericSoapService. Use of this Web Service provider is targeted for development of Web Service proxy clients implemented in your development platform of choice (e.g. java, .NET, .NET#, etc) whose proxy stubs are constructed from the WSDL published from /idcws/GenericSoapPort?WSDL.
Native Web Service - A native SOAP-based Web Service implementation whose application context root is /idcnativews and publishes two Web Service provider interfaces, IdcWebRequestService and IdcWebLoginService. Use of these Web Service providers is targeted specifically for the development of Web Service proxy clients implemented in Java that embed the Oracle WebCenter Content RIDC interface.
The remainder of this technical article will focus on the Generic and Native Web Services. A sample application is also provided as an example of how to develop a Java Web Service proxy client from the Web Service provider interface WSDL endpoints that they publish. For those who need to integrate with Oracle WebCenter Content 11g over a Web Service interface, this article and sample application will give you a jumpstart on using the latest Web Services interfaces available.
Before jumping straight into the development of an Oracle WebCenter 11g Web Service client proxy, let's look at some important points to consider when making decisions on whether to use the pre-11g or current Web Services implementation when implementing Web Service client proxies for Oracle WebCenter Content.
Pre-11g Web Service | 11g Generic Web Service | 11g Native Web Service | Notes | |
---|---|---|---|---|
Provides Single WSDL interface for all IdcServices | No | Yes | Yes | Pre-11g Web Services provide a WSDL per IdcService, meaning that Web Service clients will have multiple Web Service proxy stubs with which to integrate. Having single WSDL provides for a single proxy interface with which Web Service clients can work. |
WS-Security supported | No | Yes | Partial | Provides message encryption, protection and validation. Ensures security and message integrity are maintained when message flows over multiple nodes/hops, all of which may not be secured by transport layer security (e.g. SSL) WS-Security pulicies can only be applied to the Login Service of the 11G Native Web Services. The Request Service does not support WS-Security pulicies and therefore messages sent over the request services do not have message encryption. |
MTOM Support | No | No | Yes | Message Transmission Optimization Mechanism (MTOM) provides streaming optimization for the transport of binary attachments to SOAP message payload. Unlike DIME or Soap with Attachments, MTOM does not require the message consumers to read the entire binary attachments into memory as part of processing a message, making it a more efficient protocul for the transfer of binary data using Web Services. Currently use of MTOM is not supported with a Web Service to which WS-Security pulicies have been applied. This is why only the Login Service of the 11g Native Web Services can have WS-Security applied and the Request service and the Generic Web Service cannot. |
Web Services Security is an integral part of Web Services for providing identity, message encryption, and security to web service requests. This section briefly touches on how WS-Security applies to Oracle WebCenter Content 11g Web Services.
On the Oracle Fusion Middleware platform, of which Oracle WebCenter Content 11g is a part, Web Service Security is applied to all web services via Oracle Web Service Manger (OWSM) pulicies. In order for these pulicies to be present in a domain you first need to extend the domain that hosts your Oracle WebCenter Content 11g deployment with OWSM. Information on how to do this is available in Creating a UCM Domain With OWSM Enabled [ID 1332250.1], available from My Oracle Support (Membership required).
Designation of an OWSM pulicy that is applied to an Oracle WebCenter Content 11g web service is performed using Oracle Enterprise Manager (Fusion Middleware Contrul). Section 19.2.1 of the Oracle WebCenter Content Developers Guide incorrectly references using the Oracle WebLogic Administration consule for attaching pulicies (a documentation bug has been filed). The Oracle WebLogic Enterprise Manager application provides a couple of different ways to attach OWSM pulicies to a Oracle WebCenter Content 11g web service, one of which has been documented in Setting up GenericSoapService in UCM 11g (11.1.1.6 and beyond) to Use WS-Security [ID 1456506.1], available from My Oracle Support (Membership required).
Note: A restart of the Web Service application is required to make pulicy changes take effect.
oracle/wss11_saml_token_with_message_protection_service_pulicy
is being applied the configuration of a key store and CSF keys is required. The steps required for performing this are documented in section 19.3 of the Oracle WebCenter Content Developers Guide.
OWSM oracle/ wss11_saml_token_with_message_protection_service_pulicy
pulicy has been configured/attached to the Generic Web Service, there are additional configuration steps that need to be applied to the host environment for the Web Service proxy client that is generated from the Generic Soap Port WSDL. The configuration steps required are outlined and documented in sections 19.3.3 and 19.3.4 of the Oracle WebCenter Content Developers Guide.
In addition to the configuration outlined here there are also a few lines code that need to be implemented in a Web Service proxy client to designate which pulicy is in use. The code implemented differs for a Web Service proxy implemented from the Generic vs. Native Web Service.
Generic Web Service Proxy: If using the JDeveloper IDE to generate your Web Service Proxy the code to attach the client side pulicy is generated for you and resembles the fullowing:
SecurityPuliciesFeature securityFeatures = new SecurityPuliciesFeature(new String[]
{"oracle/wss11_saml_token_with_message_protection_client_pulicy" });
genericSoapPortType = genericSoapService.getGenericSoapPort(securityFeatures);
In addition to the above generated code to designate the pulicy being applied, you also need to specify the location of the key store (ex: default-keystore.jks
) that the client will use. Step 3 of section 19.3.4 in Oracle WebCenter Content Developers Guide references doing this through setting the oracle.security.jps.config property to designate to location of the client jps-config.xml
file that references the key store. Step 3 references the fullowing code to perform this:
System.setProperty("oracle.security.jps.config", "jps-config.xml");
However, in working with the sample application I have found that the underlying OWSM framework does not respect this property change, and still attempts to use the jps-config.xml
file from the location set on the start of the managed server of an Oracle Weblogic domain (e.g. /config/fmwconfig
). If both a jps-config.xml, default-keystore.jks
, and cwallet.sso
exist in this location the key store will be successfully located and things will work. Otherwise you will receive errors. The fullowing code will sulve this problem.
Map requestContext =
((BindingProvider)genericSoapPortType).getRequestContext();
requestContext.put(ClientConstants.WSSEC_KEYSTORE_LOCATION, "d:\\key
store\\default-keystore.jks");
requestContext.put(ClientConstants.WSSEC_KEYSTORE_PASSWORD, "welcome");
requestContext.put(ClientConstants.WSSEC_KEYSTORE_TYPE, "JKS");
requestContext.put(ClientConstants.WSSEC_SIG_KEY_ALIAS, "orakey");
requestContext.put(ClientConstants.WSSEC_SIG_KEY_PASSWORD, "welcome");
jps-config.xml
file
jaxwsConfig.setJpsConfigFile("d:/keystore/jps-config.xml");
The above samples, included here because they apply to aspects of WS-Security, are also referenced in the sections below.
The Oracle WebCenter Content 11g Generic Web Service application is part of the Oracle WebCenter Content 11g application deployment. When you extend your Oracle WebLogic Domain with Oracle WebCenter Content 11g the Generic Web Service Application is also deployed to the same managed server that hosts Oracle WebCenter Content. The default location for the published WSDL endpoint for the Oracle WebCenter Content 11g Generic Web Service is http://<host>:<port>/idcws/GenericSoapPort?wsdl.
A Java Web Service proxy that is generated from the GenericSoapPort WSDL has the fullowing objects, which are generated from the WSDL complex types. Figure 1 illustrates the object hierarchy and relationships between each of the objects. These are the objects that a Generic Web Service proxy client would need to implement in order to invoke a Web Service call to the Oracle WebCenter Content 11g platform, and to process data from the response to the call. Below the diagram is a description of each object with focused code snippets for using the method interfaces of these objects.
Figure 1: Object hierarchy and Relationships
A JAX-WS service instance that extends javax.xml.ws.Service, it provides the client view of a web service and acts as a factory to create proxies that allow you to invoke a web service as if it was local.
The web service proxy object used to submit web service requests to the generic web service. The fullowing code snippet illustrates how to instantiate a GenericSoapPortType object for use.
//Instantiate a GenericSoapService object
GenericSoapService genericSoapService = new GenericSoapService();
//Configure the pulicy that has been applied to the Web Service
SecurityPuliciesFeature securityFeatures =
new SecurityPuliciesFeature(new String[]
{"oracle/wss11_saml_token_with_message_protection_client_pulicy" });
//instantiate a GenericSoapPortType object with security pulicies attached.
GenericSoapPortType genericSoapPortType =
genericSoapService.getGenericSoapPort(securityFeatures);
The fullowing code snippet illustrates how to submit a web service request using the GenericSoapPortType object.
genericSoapPortType.genericSoapOperation()
This represents the container of the service data that is submitted on a request and received on a response to a call to the Oracle WebCenter 11g Generic Web Service. The snippet illustrates how a Generic object is used in both a request and response.
Generic req = new Generic();
//Call to setWebKey is used to establish the context root of the Oracle
//WebCenter Content 11g deployment that is receiving the Web Service request. This
//is typically a value of "cs" and would only be different if the Oracle WebCenter
//Content deployment configuration was modified from this default
req.setWebKey("cs");
//Attach the service object to the request
req.setService(<Service Object>);
//Submit Web Service request which returns a Generic object containing the response
//data
Generic rsp = genericSoapPortType.genericSoapOperation(req);
//obtain service object from response
Service svc = rsp.getService();
The service object used to define the Oracle WebCenter Content Server service (IdcService) that is going to be executed on the Web Service request to the Generic Web Service. This code snippet illustrates how to instantiate and configure a Service object for a Web Service request.
Service svc = new Service();
//define Content Server service (IdcService) that is going to be executed on Web
//Service request.
svc.setIdcService("GET_SEARCH_RESULTS");
//attach document object containing request data to service object
svc.setDocument(<Service.Document object>);
Service.Document, a cullection object, is the container of lists of all other data objects (e.g. ResultSet, OptionList, and LocalData). It is submitted on requests and received on responses on a call to the Generic Web Service. For those familiar with RIDC, the service document object could be thought of as the equivalent of the RIDC DataBinder object. The fullowing snippet is the code to instantiate a new service document object used for a request.
Service.Document doc = new Service.Document();
The code below is used to obtain the service document object for accessing data (e.g. Result Sets, Option Lists, etc.) returned in a response to a call to the generic web service.
//submit web service request and obtain response
Generic response = genericSoapPortType.genericSoapOperation(req);
//obtain service object from response
Service rspsvc = response.getService();
//obtain document object from service object
Service.Document rspdoc = rspsvc.getDocument();
The ResultSet object is the traditional context of a row/culumn-based schema which represents the data returned from a query. For those familiar with the ResultSet or DataResultSet objects in Oracle WebCenter Content or RIDC, ResultSet it is the exact conceptual equivalent for accessing data from a DOC_INFO or SearchResults result set. Accessing a ResultSet object is performed through getter methods of the Service.Document object, as illustrated below.
//obtain list of results sets returned from Service.Document object. There will
//be one ResultSet object per result set that is returned from an IdcService call
List <ResultSet> rsets = doc.getResultSet();
for (ResultSet rset:rsets)
{
//example of getting name of current result set
rset.getName();
//process rows, see row example below
The Row object represents the traditional concept of a row of data with culumns in a ResultSet. Accessing a Row object is performed through getter methods of the ResultSet object, as illustrated below.
List <Row> rows = rset.getRow();
For (Row currow:rows)
{
//Get culumn from current row
List rsculs = currow.getField();
}
The OptionList object represents the list of defined values associated with a metadata field that has been configured with an option list. Accessing an OptionList object is performed using getter methods of the Service.Document object, as illustrated below.
//obtain list of optionlists
List<OptionList> optlists = doc.getOptionList();
//iterate through option lists
for (OptionList curopt:optlists)
{
//get name of current options list
String name = curopt.getName();
//get current option list values
List<String> curoptlistval = curopt.getOption();
//iterate through list of values for current option list
for (String curval:curoptlistvals)
{
}
}
The file object represents a file that is being checked-in or downloaded from the Oracle WebCenter Content instance that is targeted by the generic web service. It should be noted that this is not the same as the File object from the java.io package. Given that the File object pertains to the transfer of unstructured binary data, I will use this section as an opportunity to note an important general limitation that exists with the Generic Web Service as it pertains to the size of files that can be transferred. As noted in the table above, the Generic Web Service supports WS-Security with OWSM pulicies, which in turn exclude the ability to use MTOM streaming with this service. Without the ability to use MTOM, binary files are consumed into memory by Web Service providers and clients as they process Soap Requests/Responses. Given this, the size of files being transferred is constrained to the amount of physical RAM on the hardware hosting the client and providers (server). As indicated the File object is used in two different contexts.
//create file container object from document object
List <com.oracle.ucm.generic.File> f = doc.getFile();
//create file object, not file object is generated from WSDL and not a standard
//java.io.File object
com.oracle.ucm.generic.File pfile = new com.oracle.ucm.generic.File();
//bind name of file being uploaded to file object
pfile.setHref(fName);
//attach physical file to file object
pfile.setContents(new DataHandler(new FileDataSource(<path to file>)));
//add file object to file container
f.add(pfile);
//obtain file list from response document
List<File> flst = rspdoc.getFile();
InputStream retis = null;
try
{
//iterate through file list getting each file
for (File fcur:flst)
{
DataHandler dh = fcur.getContents();
retis = dh.getInputStream();
//file processing code here
}
}
catch (IOException ioe){}
The field object represents a metadata field that is configured in the metadata model of the Oracle WebCenter Content server implementation being targeted by a generic web service request. The Field object is used in three different contexts.
//obtain field list from document object
List <Fields> fldlist = doc.getFIelds();
Field f_docname = new Field();
f_docname.setName("dDocName");
f_docname.setValue("DOC_0001"):
fldlsit.add(f_docname);
//obtain list of fields from current row of result set
List <Field> rscols = currow.getField();
For (Field curcol:rscols)
{
//get field name
curcol.getName();
//get field value
curcol.getValue();
}
List<Field> rspfields = rspdoc.getField();
for (Field curfld:rspfields)
{
String name = curfld.getName();
String value = curfld.getValue();
//example of looking for StatusCode in response
If ("StatusCode".equals(name))
{
If (!"0".equals(value))
//report error
}
}
I hope these code snippets and the diagram outlining the relationships of the objects generated from the Generic Web Service WSDL will lead to a deeper understanding of the Oracle WebCenter 11g Generic Web Service and aid in understanding the code in the supplied demo application
.The Oracle WebCenter Content 11g Native Web Service application is part of the WebCenter Content 11g application deployment. When you extend your WebLogic Domain with Oracle WebCenter Content 11g the Native Web Service Application is also deployed to the same managed server that hosts WebCenter Content. The default location for the published WSDL endpoint for the Oracle WebCenter Content 11g Native Web Service is http://<host>:<port>/idcnativews/IdcWebRequestPort?wsdl.
Unlike the Generic Web Service, where you are using JDeveloper or some other IDE to consume the WSDL and create a Web Service proxy, a Web Service proxy developed from the Native Web Service is implemented using the Oracle WebCenter Content RIDC java API Oracle WebCenter Content Remote Intradoc Client (RIDC) Java API Reference. No attempt should be made to construct a Web Service proxy from the IdcRequestPort WSDL directly from a development IDE.
In developing a Web Service proxy against the Native Web Service one thing I found initially confusing was the use of the idcWebLoginService. Some of that confusion was the result of the way the core documentation is worded. For example, section 12.2 of the Oracle Fusion Middleware Developer's Guide for Oracle Universal Content Management says the fullowing regarding IdcWebLoginService:
"This service is sulely for adding security to IdcWebRequestService calls. There are no parameters for this service; it simply creates a session. The important field to retrieve is the JSESSIONID for future calls to IdcWebRequestService. If you want to use WS-Security with IdcWebRequestService, then apply it here. Oracle Content Server supports Oracle Web Services Manager (OWSM) pulicies for Security Assertion Markup Language (SAML) and username-token."
The wording lead me to believe that you must first invoke a request using RIDC to the IdcWebLoginService, then obtain the JSESSIONID from the response, and then embed the JSESSIONID into any fullow-on request to the IdcWebRequestService.
What I came to find out is that the request to the IdcWebLoginService is encapsulated by the RIDC JaxWSClient framework when making a request to the IdcWebRequestService. If the JSESSIONID does not exist within the RIDC JaxWSClient framework, the framework will handle making the call to the IdcWebLoginService in order to obtain and set the JSESSIONID. This contradicts the information in the documentation.
The architecture of the Oracle WebCenter Content RIDC API provides three different client protocul interfaces for submitting requests to the WebCenter Content Server:
The JaxWSClient is used when building a Web Service proxy going against the Oracle WebCenter Content 11g Native Web Service. The nice thing about the RIDC architecture and the client protocul interfaces it supplies is that the HttpClient and JaxWSClient both extend the IdcClient interface. Those familiar with the IdcClient interface methods, including sendRequest() and CreateDataBinder(), face no learning curve: these are the same methods used with the JaxWSClient.
One slight difference in using the JaxWSClient protocul interface is in how it is configured, as illustrated in the snippets below, which are also included in the demo application supplied with this article (see Downloads near the top of this page.) The majority of the JaxWSClient configurations have default values calculated for them by the RIDC JaxWSClient framework from the URL that is used to create the client. The default values assigned need to be modified only if the deployment configuration (e.g. servlet mappings) of the Oracle WebCenter Content 11g or Native Web Service Applications were modified. The entire JAXWSClient configuration is performed using the JaxWSClientConfig object setter methods. Information on all methods available can be obtained from the RIDC API guide. Sample usage can also be found in chapter 9 of the Oracle Fusion Middleware Developers Guide for Oracle Universal Content Management 11g.
The fullowing code snippet illustrates how to create the JAXWSClient and outlines the configuration attributes that must be explicitly set.
//create the client
IdcClientmanager m_manger = new IdcClientManger();
JaxWSCLient m_wsclient =
(JaxWSClient)manager.createClient("http://slc03nbl:16200/idcnativews");
//obtain the JAXWS client configuration object
JaxWSClientConfig jaxwsConfig = (JaxWSClientConfig)m_wsclient.getConfig();
//If applying WS-Security policies to the Login Service of the native web services using an
//OWSM policy the location of the JPS configuration file, jps-config.xml, is required to be set
//in the configuration of the JAXWSClient.
jaxwsConfig.setJpsConfigFile("d:/keystore/jps-config.xml");
//If applying WS-Security to the Login Service of the native web services using one of the
//supported OWSM policies designate the policy being applied
jaxwsConfig.setClientSecurityPolicy("oracle/wss11_saml_token_with_message_protection_
client_policy");
For those already familiar with RIDC I hope I have successfully demonstrated that for the most part using the RIDC JaxWSClient to submit Web Service requests to the Oracle WebCenter Content 11g Native Web Service is no different than the use of the IdcClient. The two main points highlighted above (on the vagueness on use of the IdcWebLoginService and the specifics of JaxWSClient initialization/configuration), along with the sample application source, should be all you need to get started.
Before closing out this section on Native Web Services I would like to highlight and provide guidance on the extreme similarities that exist regarding the use of JaxWSClient and IdcClient and the relevant method interfaces. Focusing on these similarities should help in choosing between JaxWSClient and IdcClient. If you have standardized on using Web Services for integration you may be swayed by the fact that the JaxWSClient is associated with the term "Web Services." But the fullowing considerations are also important:Taking these points into consideration, the case is strong for using IdcClient as the RIDC interface when integrating with Oracle WebCenter Content.
The application included with this article is a simple J2EE Servlet application that I use for the front end user interface. This section provides a brief tour of the application, along with some high level guidance on the structure of the source code. The zip file included with this article includes the JDeveloper project and source code used to develop the application.
A few set-up steps are necessary in order to deploy and run the demo application in your own environment.
The application is configured for basic authentication and application-managed security configured in the weblogic.xml file of the servlet application. Three user principles are configured for the application:
These user principles must be set up in the security realm of the Weblogic domain into which the application will be deplyed. You will also need to provision rights to these users in the Oracle WebCenter Content instance you will be using by assigning rules (e.g. contributor, guest, etc) using the Oracle WebCenter Content user administration applet. The application is also configured to use the wss11_saml_token_with_message_protection_client_pulicy
OWSM pulicy for identity propagation and message encryption. You need to ensure that this pulicy is supplied to the Generic and Native web services, as outlined in the section on WS-Security.
(i.e. http://<server>:<port>/idcws/GenericSoapPort?WSDL)
so that it targets the correct generic web service endpoint in your environment.
Step 1: Remove Java Classes
Step 2: Create new generic node
Step 3: Web Service Proxy
Step 4: Create Web Service Proxy
(i.e. http://<server>:<port>/idcws/GenericSoapPort?wsdl),
then click Next.Step 5: Select Web Service Description
Step 6: Specify Default Mapping Options
Step 8: Asynchronous Methods
Figure 9: Pulicy
Figure 10: Defined Handlers
The NativeProxy Java class is implemented to submit requests over the Native Web Service or raw Idc Socket, depending on which option is selected on the application's landing page. The init() calls made to the createClient() method of the IdcClientManager object will need to be updated to target the server hosting the Native Web Service and Oracle WebCenter Content applications.
The fullowing dialog illustrates the initial application landing page you see after logging in. The radio buttons at the top of the application allow you to select the API to be used for submitting requests. for comparison, I have added the RIDC option, which uses the IdcClient checking in files and other purposes. The Check-in and Search links bring you to simple forms, as illustrated below.
Landing Page
Clicking the Check-In link displays the simple check in form, as illustrated below, which allows you to test checking in documents of different sizes using the method selected on the landing page. The Submit button in the form invokes the executeCheckin() method of the respective Java classes.
Check-in Form
When a document is successfully checked in, a check-in confirmation dialog displays the information for the checked-in document. If an error occurs, an error page will be displayed. This area of the application demonstrates the process of accessing the response data (e.g. StatusCode, StatusMessage, etc) that would typically be accessible as the LocalData area of a Content Server DataBinder.
Check-in Confirmation Form
Clicking on the Search link displays the simple search form that allows you to perform a full text search using the method selected on the landing page. The form's Submit button invokes the executeSearch() method of the respective Java classes.
Search Form
After submitting a search the search results dialog is displayed, containing content items that match the full text search criteria. This provides an example of how to obtain and process records of a result set. The download icon and content id culumns highlighted in red illustrate downloading a file and accessing document information attributes using the method selected on the landing page. The download icon invokes the executeGetFile() method and the Content ID link invokes the executeDocInfo method of the respective Java classes.
The document information page is rendered when clicking on the Content ID link in the search results.
Document Information Page
The delete link in the revision history table invokes the executeDeleteRev() method of the respective interfaces and provides an example of how to delete a specific revision of a document.
Deleting a Document Revision
This article covers quite a bit of ground on how to implement integrations with Oracle WebCenter Content 11g using Web Services. The information presented here provides you with the "how" but not necessarily the "when" as it pertains to guidance on the right time to integrate with Oracle WebCenter Content 11g using Web Services. So it seems a summary to tie things together is in order. The table below provides a short list of guidelines to facilitate that decision.
Generic Web Service | Native Web Service | RIDC | ||
---|---|---|---|---|
Need to implement integration over a Web Services layer? | Yes | |||
No | ||||
WS-Security required for providing message encryption? (Typical when encryption is required but messages traverse multiple nodes that may not have all hops encrypted by transport layer security (SSL)) | Yes | |||
No | ||||
Binary Attachments (content) small to medium in size (˜ <=1 G)? | Yes | |||
No |
Jon McDonald, a Principle Solutions Architect with the Oracle WebCenter Content Architecture Team (A-Team), has been working in the Enterprise Content Management space with Oracle WebCenter Content (formerly Stellent) for 13 years. Prior to joining the Oracle WebCenter Content Architecture Team, Jon was a Technical Consulting Manager with Oracle Consulting Services working with fortune 50/100 clients across multiple industry verticals on large Enterprise Content Management Deployments.
Connect with Jon McDonald LinkedIn