Some time ago I was thinking in how to read XML Resources available in OSB projects at runtime. It would be very useful to hold some configuration data to be read by the proxy services through XPath or Java Call. After many searches in Google, I did not find any documentation or example in how to read OSB resources content programmatically at runtime. The popular OSB APIs and MBeans do not provide any method to get the resources content, but only their references. The question was how to get the resources content through their references.
With the help of JShrink I spent some time decompiling the OSB native jar functions and making a reverse engineering to discover how to do this. Fortunately, after some good tries I found what I was looking for. Using some internal OSB built-in libraries we can access any project resource at runtime.
In this article I will show how to read a sample XML Resource programmatically at runtime. In this sample I will use a Custom XPath to read a XML resource that holds application configuration parameters. Obs.: the same API shown here can also be used into a Java Call.
The sample project structure will look like this:
File “xsd/Parameters.xsd”: a simple schema that we’ll use in this scenario to describe the XML structure that holds the parameters:
<xsd:complexType name="Parameters"> <xsd:sequence> <xsd:element name="ParameterList" type="tns:ParameterList"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="ParameterList"> <xsd:sequence> <xsd:element name="Parameter" type="tns:Parameter" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="Parameter"> <xsd:sequence> <xsd:element name="Key" type="xsd:string"/> <xsd:element name="Value" type="xsd:string"/> </xsd:sequence> </xsd:complexType>
File “xml/Parameters.xml”: the sample XML that will be read by our XPath function at runtime:
<ns0:Parameters xmlns:ns0="https://gibaholms.wordpress.com/samples/xsd/2012/02/parameters"> <ns0:ParameterList> <ns0:Parameter> <ns0:Key>Color</ns0:Key> <ns0:Value>Blue</ns0:Value> </ns0:Parameter> <ns0:Parameter> <ns0:Key>Size</ns0:Key> <ns0:Value>500</ns0:Value> </ns0:Parameter> </ns0:ParameterList> </ns0:Parameters>
File “xq/ReadXmlParameters.xq”: a sample test XQuery that calls our XPath function passing as argument the full reference path to the XML parameters file:
xquery version "1.0" encoding "Cp1252"; (:: pragma bea:schema-type-return type="ns0:Parameters" location="../xsd/Parameters.xsd" ::) declare namespace xf = "http://tempuri.org/ReadXmlResource/xq/ReadXmlParameters/"; declare namespace ns0 = "https://gibaholms.wordpress.com/samples/xsd/2012/02/parameters"; declare namespace param = "https://gibaholms.wordpress.com/xpath/ReadXmlResource"; declare function xf:ReadXmlParameters() as element() { param:readXml("ReadXmlResource/xml/Parameters") }; xf:ReadXmlParameters()
Now, let’s create the custom XPath that does the magic. Create a simple Java project and add the following compile dependencies:
- <MIDDLEWARE_HOME>\Oracle_OSB1\modules\com.bea.common.configfwk_1.5.0.0.jar
- <MIDDLEWARE_HOME>\Oracle_OSB1\modules\com.bea.core.xml.xmlbeans_2.1.0.0_2-5-1.jar
- <MIDDLEWARE_HOME>\Oracle_OSB1\lib\modules\com.bea.alsb.resources.core.jar
- <MIDDLEWARE_HOME>\Oracle_OSB1\lib\modules\com.bea.alsb.resources.xml.jar
The XPath project structure is shown below:
In the file “osb-readxmlresourcefunction.xml” we describe the XPath functions contract. This file is a requirement of OSB and must be copied to the functions directory with the generated jar file:
<xpf:xpathFunctions xmlns:xpf="http://www.bea.com/wli/sb/xpath/config"> <xpf:category id="Custom Functions"> <xpf:function> <xpf:name>readXml</xpf:name> <xpf:comment>This function reads a XML Resource file from OSB</xpf:comment> <xpf:namespaceURI>https://gibaholms.wordpress.com/xpath/ReadXmlResource</xpf:namespaceURI> <xpf:className>com.wordpress.gibaholms.xpath.ReadXmlResource</xpf:className> <xpf:method>org.apache.xmlbeans.XmlObject readXml(java.lang.String)</xpf:method> <xpf:isDeterministic>true</xpf:isDeterministic> <xpf:scope>Pipeline</xpf:scope> <xpf:scope>SplitJoin</xpf:scope> </xpf:function> </xpf:category> </xpf:xpathFunctions>
The secret to access OSB resources at runtime is the various “*Repository” classes. The code of our “readXml” XPath function is shown below:
package com.wordpress.gibaholms.xpath; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlObject; import com.bea.wli.config.Ref; import com.bea.wli.config.component.NotFoundException; import com.bea.wli.sb.resources.config.XmlEntryDocument; import com.bea.wli.sb.resources.xml.XmlRepository; public class ReadXmlResource { public static XmlObject readXml(String xmlRefPath) { Ref ref = new com.bea.wli.config.Ref("XML", Ref.getNames(xmlRefPath)); XmlObject xmlObject = null; try { XmlEntryDocument xmlEntryDocument = XmlRepository.get().getEntry(ref); String xmlContent = xmlEntryDocument.getXmlEntry().getXmlContent(); xmlObject = XmlObject.Factory.parse(xmlContent); } catch (NotFoundException e) { e.printStackTrace(); throw new RuntimeException("XML Resource not found."); } catch (XmlException e) { e.printStackTrace(); throw new RuntimeException("Error parsing XML content.", e); } return xmlObject; } }
As we can see in the code, the class “com.bea.wli.sb.resources.xml.XmlRepository” does the magic of retrieve the XML resource content through it “com.bea.wli.config.Ref” reference. Following the same principle, we can use the other various “*Repository” classes to access other types of resources in projects at runtime, like Schemas, XSLTs, WSDLs and so on.
To test the function, just run the XQuery “xq/ReadXmlParameters.xq” in the sbconsole:
The test XQuery has no parameters, so just execute it:
Then you must see the parameters XML loaded at runtime, like shown below:
I’m glad to share this discovery with other ALSB / OSB developers and I hope help you to do more useful things with this knowledge.
If someone already has another solution to read OSB project resources at runtime or already use this API for some other purpose, please share the experience with us through comments. Thanks.
Attachments
Source Code:
https://github.com/gibaholms/articles/tree/master/Read_XML_Resource_in_OSB
Really nice,
Great we can then have a central MDS project which contains all the xml entries.
maybe you can also make a MDS implementation, where you have your osb partition in MDS or re-use the soa one for the xml ( the soa already has the required upload and delete scripts )
for the OSB book ,Eric Elzinga make a recipe where he used a file adapter to do the same.
thanks for sharing.
Thanks for the feedback Biemond.
Im planning to use this technique to make something about integrating JUnit to create automated testing support to XQuery and XSLT transformations, and even to automate Proxy Services message flow unit testing.
What do you think about it ?
https://github.com/TrentBartlem/osbutils/tree/master/XQTestFramework
Hi,
I know somebody already tried to do this for Xquery , I know the jdev xquery jars are different then that of OSB.
but it would be really cool.
good luck
Great Post!
why not simply rename the extension from xml to xq?
Hi Alessandro,
Thanks for the reply!
For the case of data parametrization your suggestion is valid, I already did this xq approach in many clients. The only cons I’ve come across was the need to use a assign task to get all the parameters every time and the time spent to explain the sysadmin what is a xq and no support for caching the parameters.
But the data parametrization is only a practical sample to show the possibilities, much more things can be done using this approach. The main purpose was to show the possibility to get programmatically at run-time not only xml, but any resource from OSB, like cannonical models, xqueries, xslts, do unit testing of transformations with JUnit, etc.
“This file is a requirement of OSB and must be copied to the functions directory with the generated jar file”. Where is this function directory?
Hi Dhiego,
To install a custom xpath function in OSB 11g, you must copy the jar file and the xml descriptor to the folder “\Oracle_OSB1\config\xpath-functions”, then you must restart the server.
Thank you very much. I’ll try it!
excellent post. in my case I have some parameters which changes from environment to environment . I wanted to add to customization xml file and have proxy read it from it. couldn’t find a way to add/read custom variable to customization file. Any ideas?
Hi Ross,
With customization files you will be able to do search and replace in your xml parameters or xquery, but i never tried it With a pattern, maybe you must replace the exact value. Letme know if worked. Regards.
Nice post.
I followed this article to access an osb resource (xsd) within a jar called from a proxy service via java callout. But I am getting an error – java.lang.RuntimeException: XML Resource not found at line
Ref ref = new com.bea.wli.config.Ref(“XML”, Ref.getNames(schemaRefPath));
I verified the path of the resource and everything is ok. Could you please help.
Hi Viv,
If your resource is a xsd, you must try:
Ref ref = new com.bea.wli.config.Ref(“XSD”, Ref.getNames(schemaRefPath));
Each type of resource have its own “type name” (XML, XSD, WSDL, etc…)
Regards,
Gilberto
Hi Gib,
Changes it to XSD leads to this error –
java.lang.IllegalArgumentException: Expected a query of type XML but got XSD
at this line of code –
XmlEntryDocument xmlEntryDocument = XmlRepository.get().getEntry(ref);
Hi Viv,
The BEA naming conventions are pretty consistent, the classes XmlEntryDocument and XmlRepository works only for “XML” resources…
For “XMLSchema” resources, you must replace it to “SchemaEntryDocument” and “SchemaRepository”, from the jar file “com.bea.alsb.resources.schema.jar”.
Another thing, in the previous post I said “XSD”, but I guess the correct String is “XMLSchema”. Try with both please and then let me know which worked.
Appreciate your help Gib. It worked with following line of codes –
Ref ref = new com.bea.wli.config.Ref(“XMLSchema”, Ref.getNames(schemaRefPath));
try {
SchemaEntryDocument schemaEntryDocument = SchemaRepository.get().getEntry(ref);
String xsdContent = schemaEntryDocument.getSchemaEntry().getSchema();
Another thing to note that the schema name should NOT suffix “.xsd”.
Great news Viv !! Thanks for your feedback. Regards !
Hi…
Can u give an example of a xmlRefPath ?
Regards,
CV
Hi,
The xmlRefPath is the xml file path in OSB, removing the (.xml) extension: “ReadXmlResource/xml/Parameters” .
Good night, Gilberto, I wanted to see if you can do this in OSB 10gR3, or what would be the code of equivalence, since I need to read some XML’s in a dynamic but can not find the way eh tested with XQuery but the function fn: doc () not working.
Regards,
Carlos
I think that fn:doc() will not work, because OSB works with references, not files. Did you tried the posted code to retrieve the XML contents ? The OSB 10gR3 and 11g have the same core.
Hi Very nice article, i am having requirement to read wsdl document from other projects resources folder. but I am unable to get it i get following error
WsdlEntryDocument wsdldoc = WsdlRepository.get().getEntry(ref);
String wsdlcontent = wsdldoc.getWsdlEntry().getWsdl();
can you help me please
also to note additionally i am passing wsdl location as a string to xmlRefPath and refType as “WSDL”
public static XmlObject readXml(String xmlRefPath, String refType) {
Ref ref = new com.bea.wli.config.Ref(refType, Ref.getNames(xmlRefPath));
XmlObject xmlObject = null;
try {
WsdlEntryDocument wsdldoc = WsdlRepository.get().getEntry(ref);
//wsdldoc.getWsdlEntry().getWsdl();
System.out.println(“wsdl read>>>> ” + wsdldoc.getWsdlEntry().getWsdl());
Hi, your code seems correct, but I’m not sure if WSDL expected refType is “WSDL”. Try to use the constant instead, like com.bea.wli.sb.util.Refs.WSDL_TYPE (https://docs.oracle.com/cd/E29542_01/apirefs.1111/e15033/com/bea/wli/sb/util/Refs.html#WSDL_TYPE). Let us know if works.
Looking to fork and polish this up a bit, could you provide a license or state it is in the public domain? See commit comment on github, thanks.
Hi Jason,
MIT license created and commited in the root project level.
Thanks,
Gilberto.
Thanks! Starting coding now…
Good stuff!
It doesn’t work in oracle service bus 12c