The Oracle Service Bus is often used for service virtualization. Endpoints are exposed on the Service Bus which proxy other services. Using such an abstraction layer can provide benefits such as (among many other things) monitoring/logging, dealing with different versions of services, throttling/error handling and result caching. In this blog I will provide a small (Java) script, which works for SOA Suite 11g and 12c, which determines exposed endpoints on the Service Bus.
How to determine endpoints?
In order to determine endpoints on the Service Bus, The Service Bus MBeans can be accessed. These MBeans can obtained from within a local context inside the Service Bus or remotely via JMX (when configured, see http://stackoverflow.com/questions/1013916/how-to-enable-jmx-on-weblogic-10-x). In this example I’ll use a remote connection to a Weblogic Server instance which runs on the same machine (JDeveloper IntegratedWeblogicServer). To browse MBeans, you can use jvisualvm (http://docs.oracle.com/javase/7/docs/technotes/guides/visualvm/) which is distributed as part of the Oracle JDK. JVisualVM has a plugin to browse MBeans.
When connected, the Service Bus MBeans are located under com.oracle.osb. The proxy services which define the exposed endpoints, can be recognized by the Proxy$ prefix. In order to determine the actual endpoint, you can look at the ResourceConfigurationMBean of the proxy service. Under configuration, transport-configuration you can find a property called url. The script also filters HTTP SOAP services since the url field is also used for other transports. A replace of // with / is done on the combination server:host/url since the url can start with a /. This causes no difference in functioning but provides better readable output. If you want WSDL’s, you can add ‘?wsdl’ to the obtained endpoint.
The script requires some libraries. For 11g, you can look at http://techrambler99.blogspot.nl/2013/11/oracle-service-bus-using-management.html. On that blog, more specific API calls are done which have more dependencies. This example requires less. For 12c, it was enough to add the Weblogic 12.1 remote client library in the project properties.
The script does not determine the hostname/port of the server the Service Bus is currently running on. This could lead to misinterpretation when for example a load-balancer or another proxy component (such as OHS) is used.
The script
package nl.amis.smeetsm.sb; import java.io.IOException; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Hashtable; import java.util.Set; import javax.management.MBeanServer; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import javax.management.openmbean.CompositeDataSupport; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import weblogic.management.mbeanservers.domainruntime.DomainRuntimeServiceMBean; public class SBEndpointList { private static MBeanServerConnection connection; private static String HOST = "localhost"; private static Integer PORT = 7101; private static String USERNAME = "weblogic"; private static String PASSWORD = "Welcome01"; public SBEndpointList() throws IOException, MalformedURLException, NamingException { this.connection = this.getMBeanServerConnection(); } private ObjectName[] getObjectNames(ObjectName base, String child) throws Exception { return (ObjectName[]) connection.getAttribute(base, child); } public ArrayList<String> getEndpoints() throws Exception { ArrayList<String> result = new ArrayList<String>(); Set<ObjectName> osbconfigs = connection.queryNames(new ObjectName("com.oracle.osb:Type=ResourceConfigurationMBean,*"), null); for (ObjectName config : osbconfigs) { if (config.getKeyProperty("Name").startsWith("ProxyService$")) { //System.out.println(config); CompositeDataSupport cds = (CompositeDataSupport) connection.getAttribute(config, "Configuration"); String servicetype = (String) cds.get("service-type"); if (servicetype.equals("SOAP")) { CompositeDataSupport pstt = (CompositeDataSupport) cds.get("transport-configuration"); String url = (String) pstt.get("url"); String tt = (String) pstt.get("transport-type"); if (tt.equals("http")) { result.add("http://SERVER:PORT" +("/" + url).replace("//" ,"/") ); } } } } return result; } private JMXConnector initRemoteConnection(String hostname, int port, String username, String password) throws IOException, MalformedURLException { JMXServiceURL serviceURL = new JMXServiceURL("t3", hostname, port, "/jndi/" + DomainRuntimeServiceMBean.MBEANSERVER_JNDI_NAME); Hashtable<String, String> h = new Hashtable<String, String>(); h.put(Context.SECURITY_PRINCIPAL, username); h.put(Context.SECURITY_CREDENTIALS, password); h.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES, "weblogic.management.remote"); return JMXConnectorFactory.connect(serviceURL, h); } private MBeanServerConnection getMBeanServerConnection() throws IOException, MalformedURLException, NamingException { try { InitialContext ctx = new InitialContext(); MBeanServer server = (MBeanServer) ctx.lookup("java:comp/env/jmx/runtime"); return server; } catch (Exception e) { JMXConnector jmxcon = initRemoteConnection(HOST, PORT, USERNAME, PASSWORD); return jmxcon.getMBeanServerConnection(); } } public static void main(String[] args) throws IOException, MalformedURLException, Exception { SBEndpointList me = new SBEndpointList(); ArrayList<String> result = me.getEndpoints(); System.out.println("Endpoints:"); for (String endpoint : result) { System.out.println(endpoint); } } }
Very good! Exactly what I was looking for to extract data from OSB!
Thank you very much!
This technique does not appear to work on 12.2.1.0 or later. There’s no Configuration/transport-configuration structure in the OSB MBean.
Thanks for the article, it’s really nice. I cannot find the way how to retrieve the additional information such as HTTP Transport Configuration details (Read Timeout, Connection Timeout etc..), can you please help?
Were you able to retrieve HTTP Transport Configuration details (Read Timeout, Connection Timeout etc..)?
Hi Maarten,
I have created a Generic Rest Service in Service Bus 12c which will get hostname,Params and template values from dvm, the Service is working as expected.
Now i want to dynamically pass security information (service account) depending on the which endpoint i am invoking.But i am not able to find service-account element in outbound header properties. Could you please let me know any other way to dynamically pass username/password.
Thanks,
Mahesh