JMS connection from Java SE - java

I would like to create a JMS connection from a Java SE application in a broker-agnostic way.
I'm comparing to JDBC with its URL scheme for database connections. This creates independence from the actual implementation.
For JMS I haven't found something similar. I'm aware that in Java EE the JNDI will fulfill this role, but this is Java SE.
I don't want to tie my code to any particular queue broker as my needs are pretty simple JMS 1.1 send/receive of text messages.
I've looked at Spring Boot too because it is usually good at providing some level of agnosticism. But even with Spring Boot, I do not see such possibility.

JNDI is the way you write your JMS application to connect in a broker-agnostic way. JNDI client classes are part of Java SE. Both Spring and non-Spring Java SE applications use JNDI for this kind of integration.
Any JMS implementation should also provide a JNDI implementation that can be plugged into your application. Typically this is done by placing a file named jndi.properties on your classpath and putting the proper configuration for whatever JNDI implementation you're using into that file. When you create an empty InitialContext the jndi.properties file on your classpath is read automatically. The key=value pairs in jndi.properties are put into the InitialContext so that when you perform a lookup everything works with the implementation you've chosen. You can also configure this programmatically if you like by supplying the implementation specific details to the InitialContext via a constructor.
By using both the JMS and JNDI APIs in your Java SE application and externalizing broker-specific connection details to your jndi.properties file you can effectively isolate your applications from broker-specific code so you can deploy your app and work with different brokers with a few simple changes in a properties file.
The JNDI client implementation will come from whoever is providing the JMS implementation. The JNDI client essentially comes in the form of an javax.naming.spi.InitialContextFactory implementation packaged in a jar and there is usually documentation describing the available properties.
Here are a few examples:
The ActiveMQ 5.x broker provides org.apache.activemq.jndi.ActiveMQInitialContextFactory available in their activemq-client-<version>.jar. Documentation is available here.
The ActiveMQ Artemis broker provides org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory available in their artemis-jms-client-<version>.jar. Documentation is available here.
To be clear, the JMS specification doesn't require the use of JNDI to look-up admin objects, but it establishes the convention and expectation that JMS providers will do so. Section 4.2 of the JMS 1.1 specification states:
Although the interfaces for administered objects do not explicitly depend on JNDI, JMS establishes the convention that JMS clients find them by looking them up in a namespace using JNDI.
and later it says:
It is expected that JMS providers will provide the tools an administrator needs to create and configure administered objects in a JNDI namespace. JMS
provider implementations of administered objects should be both javax.naming.Referenceable and java.io.Serializable so that they can be stored in all JNDI naming contexts.
In my experience, JMS providers are usually eager to provide a JNDI implementation because they won't be as competitive without it since any alternative solution will not be standards compliant and will force users to implement non-portable code.
If you run into a provider that doesn't provide a JNDI implementation you could implement your own following the same pattern used by ActiveMQ 5.x, ActiveMQ Artemis, and Qpid JMS. These 3 implementations are client-side only and simply instantiate the admin objects based on the configuration provided to the InitialContext. Most of the code is boiler plate, and what isn't is very straight-forward.

Related

ActiveMQ 5.1.1 WebSphere 8.5.5 Activation Spec configuration?

Thanks to Maarten I was able to get basic ActiveMQ JMS topics and connection factories working in WAS. He has a nice write up in his reply to this topic: ActiveMQ 5.11 with WebSphere Application Server 8.5
But I cannot find a way to define any ActiveMQ JMS Activation Specs in the WAS admin console. And of course I need those in order to trigger my MDBs. ActiveMQ simply doesn't show up as a JMS provider when creating a new AS.
How do I configure Activation Specs in WAS using ActiveMQ as the provider? Am I missing a jar file?
activemq-client-5.11.0.jar
hawtbuf-1.11.jar
slf4j-api-1.7.10.jar
If you want to use Activation specification, you need to install ActiveMQ as JCA 1.5 compliant resource adapter. As far as I know, ActiveMQ provides resource adapter as separate install.
See also:
Deploying the ActiveMQ Resource Adapter into IBM WebSphere
Managing messaging with a third-party JCA 1.5 or 1.6-compliant messaging provider
ActiveMQ resource adapter
Listener ports are stabilized, and should only be used if provider doesn't support JCA.
Really straight forward once you understand (of course).
From the IBM Redbook mentioned above, sg247770.pdf, we need to configure ActiveMQ as a Generic JMS provider in WAS. And since we want to use Activation Specs, again from the Redbook, we need to use the ActiveMQ Resource Adapter, or rar file. There is a link on the ActiveMQ page to the latest rar, I don't need to provide it here. Once the rar is installed, using the WAS Console/Resources/Resource Adapters menu, you can configure J2C CFs, ASs, and administered objects including Queues and Topics from the rar configuration page. These will all have custom properties where you will enter your destinations, etc.

JBoss configuration : Where should JMS Bridge configuration be?

I'm new to JMS programming (Java).
I have a machine M1, in a domain D1 and a machine M2 in another domain D2.
I have in M1 a JMS producer. And in M2 a JMS consumer. Both have as servers JBoss 7.2.
So it seems the only solution is to create a JMS bridge.
I'm reading the official documentation. So I wonder if creating an SSH tunnel is necessary.
Second, in which hornetq-configuration.xml file should I set the following configuration?
<bridge name="my-bridge">
<queue-name>jms.queue.sausage-factory</queue-name>
<forwarding-address>jms.queue.mincing-machine</forwarding-address>
<filter-string="name='aardvark'"/>
<transformer-class-name>
org.hornetq.jms.example.HatColourChangeTransformer
</transformer-class-name>
<retry-interval>1000</retry-interval>
<ha>true</ha>
<retry-interval-multiplier>1.0</retry-interval-multiplier>
<reconnect-attempts>-1</reconnect-attempts>
<failover-on-server-shutdown>false</failover-on-server-shutdown>
<use-duplicate-detection>true</use-duplicate-detection>
<confirmation-window-size>10000000</confirmation-window-size>
<user>foouser</user>
<password>foopassword</password>
<static-connectors>
<connector-ref>remote-connector</connector-ref>
</static-connectors>
<!-- alternative to static-connectors
<discovery-group-ref discovery-group-name="bridge-discovery-group"/>
-->
</bridge>
Should it be in the in JBoss server of the JMS producer machine or consumer machine?
My third question is, is there a difference in settings between JMS bridge and core bridge?
I would be so thankful for any additional information and explainations!
Thank you a lot!
I know this is little late for OP, may be this information helps someone.
Firstly, the difference between Core and JMS bridge.
Read doc here
Core bridges are for linking a HornetQ node with another HornetQ node and do not use the JMS API. A JMS Bridge is used for linking any two JMS 1.1 compliant JMS providers.
The Core bridge uses proprietary HornetQ core api so it can only connect two HornetQ servers. Whereas JMS bridges use the JMS API so could connect any JMS1.1 API complaint servers.eg: HornetQ to ActiveMQ.
The configuration mentioned in question is Core bridge and can be configured in the source server.Since you seem to connect two HornetQ server Core bridges is the way forward. That said, in your case you could use JMS bridges as well since both are JMS complaint.But the recommended approach would be to use Core bridge due to performance advantage gain.
Finally, the JBoss installation server comes with some handy examples.You could find Core bridge example under [JBOSS_HOME]\jboss-as\extras\hornetq\examples\jms\bridge.

Java - DBCP vs JNDI?

I am a newbie and I have created a few simlpe Java Swing applications. I was able to use apache commons DBCP to create a connection pool and access the datasource.
I have recently started to create java web based applciations using JSP and Servlets. I have learnt to use JNDI to access the datasource. I update the XML files and use InitialContext() and lookup("java:comp/env") and that is it!!!! I am using Apache Tomcat as my Servlet/JSP container.
1. But where is the DB connection pool created?
2. If yes, then does that mean JNDI somehow uses the DBCP internally?
When I have to create a DBCP for Swing applications, I had to first create an instance of GenericObjectPool and then create a connection factory object and finally a PoolableConnectionFactory object to create the Datasource which will be used to get a connection.
JNDI is a mechanism to pass objects from one part of the system to another (in technical terms across class loaders). This is most useful for classes and interfaces found in the Java Runtime like String or DataSource.
This means that in your case JNDI is just a transport mechanism and you need to have the actual connection pool defined elsewhere. Most web containers have a mechanism for defining a system wide connection pool, and JNDI then allows you to get to it.
Tomcat use a custom implementation of Apache DBCP and Apache Pool for the JNDI Datasource. These libraries are located in a single JAR at $CATALINA_HOME/lib/tomcat-dbcp.jar.
The main package is org.apache.tomcat.dbcp for avoid conflicts with the regular packages form Apache Commons.
JNDI is a mechanism of locating remote resources via lookup. It has nothing in common with connection pooling libraries. These libraries, of which c3p0, DBCP and BoneCP, are the most famous, allow you to create data sources with ability to pool connections and/or statements. If this data source is used within your application, you don't need to use JNDI, if it is located on a remote system (for instance, in Tomcat), you need to use JNDI to get access to the data source.
As a side note, why did you choose to work with old-school Servlet/JSP combo? It is a better idea to work with JSP successor, facelets that is a preferred view technology in JSF 2.x.
Another comment is to transfer management of your data source to a well-known framework. One direction might be to use an ORM, for example, Hibernate, to manage your data source (which was created with connection pooling in mind).

Does OSGI JNDI allow coexistence with JNDI calls from non-OSGI code?

Chapter 126 of the OSGI Enterprise Release 5 specification mentions compatibility:
"Support the traditional JNDI programming model used by Java SE and Java EE clients."
and use of OSGI-unaware code:
"Clients and JNDI Context providers that are unaware of OSGi use static methods to connect to the
JRE JNDI implementation. The InitialContext class provides access to a Context from a provider and
providers use the static NamingManager methods to do object conversion and find URL Contexts.
This traditional model is not aware of OSGi and can therefore only be used reliably if the consequences
of this lack of OSGi awareness are managed."
but it is not clear to me if this text only applies to "legacy" code executed inside an OSGI bundle, or also to code outside the OSGI container, f ex in a scenario where the OSGI container is embedded in an application.
In an embedding scenario, there may be application code both outside and inside the OSGI container that performs JNDI calls, and as they execute in the same JVM they will share JNDI implementation.
Question: Should an OSGI JNDI implementation running in an embedded OSGI container allow OSGI-unaware code outside the container to perform its JNDI calls like usual, or is some porting to "OSGI-awareness" required?
Trying this out myself with Apache Karaf 2.3.0 (which uses Apache Aries JNDI 1.0.0) this doesn't seem to work, as Apache Aries requires JNDI client calls to originate from an OSGI bundle.
Partial stacktrace:
javax.naming.NoInitialContextException: The calling code's BundleContext could not be determined.
at org.apache.aries.jndi.OSGiInitialContextFactoryBuilder.getInitialContext(OSGiInitialContextFactoryBuilder.java:46)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:307)
at javax.naming.InitialContext.init(InitialContext.java:242)
at javax.naming.InitialContext.<init>(InitialContext.java:192)
Question: Is this correct behaviour, or is there a section of the specification I can refer to that is violated by this limitation?
I ran into same issue when trying to deploy Apache Karaf on Weblogic.
We use karaf through a servlet bridge - a war is deployed in weblogic which bridges all http requests to karaf.
I am running with the the following applications on weblogic:
app1 (uses JNDI)
app2
karaf-bridge (bridges requests to Karaf)
As soon as karaf starts the Aries JNDI implementation running inside Karaf sets InitialContextFactoryBuilder inside javax.naming.NamingManager to its own implementation. NamingManager holds a static reference to the initial context factory builder, so whichever implementation, irrespective of whether its running in an OSGI environment, sets this static reference becomes the JNDI provider.
In my case when app1 (non-OSGI) tries to do a new InitialContext, Aries JNDI tries to resolve it using the BundleContext and fails.
I fixed this using some very ugly hacks that involved extracting the javax.naming package from jre and installing it as a bundle in karaf.
So the answer to your question: I think the issue is really in the jre and not with OSGI on how JNDI lookup is managed.
I'm not sure if I understand the problem correctly... JNDI is a Service Provider Interface, and it needs some underlying implementation to run with. All you need to do is to provision it the OSGI container.
I would recommend creating single bundle with all jars needed by JNDI and export all packages. Then use Dynamic-Import: * to use it. It worked in our case (Eclipse RCP application with JBoss 5 JNDI used for EJB calls).
However if you need JNDI inside and outside of the container and you don't want to struggle with Classloading, I would recommend adding all jars to the applications classpath. This way it should be accessible in whole your application.
Apache Aries seems to have thought about this and have provided an implementation of JRE initial context factory builder (org.apache.aries.jndi.JREInitialContextFactoryBuilder) which seems to work. However, for this to work, I had to change Aries code that registers the JVM wide initial context factory builder. There may be another (and possibly better) way of achieving this. But this seemed to work.
Also, note that the problem does not stop at InitialContextFactoryBuilder being set in NamingManager. The same issue arises for ObjectFactoryBuilder (which is again set JVM wide in NamingManager). Depending on the JNDI provider you are trying to connect to, you may need to change that part of Aries JNDI code as well. e.g. for Tibco EMS JNDI connection, I had to tweak the code for OSGiObjectFactoryBuilder from Aries to return a Tibco specific ObjectFactory. This can be easily generalized using Context.OBJECT_FACTORIES environment value.
I've raised a JIRA for the same - https://issues.apache.org/jira/browse/ARIES-1127

DI in an EJB/MDB Application

I'm currently developing a small EJB application running on IBM Websphere Application Server 7 (Java EE 5). The app mainly consists of one MDB listening for incoming MQ messages which are transformed and stored in a DB. Currently I'm using a lot of Singleton/Factories to share configurations, mappings, datasource lookups etc. But this actually leads to some very hard to test code. The solution might be using a (simple) DI framework like guice/spring to inject the different instances. The question is: Where to place the initialization/ setup code? Where is the main entry point of the application? How can I inject instances into the MDBs?
it might be worth looking at backing off from using Guice, and trying to work with the injection mechanisms already available with Java EE 5.
Regarding finding a suitable "startup point", unfortunately the EJB specification does not define a way where you can have a bean run at startup. However, the web profile of the EE spec does have one -- you can add a WAR to your application, and set a servlet listener component:
http://java.sun.com/javaee/5/docs/api/javax/servlet/ServletContextListener.html
You can set this to start whenever the application is loaded and started by the container (WebSphere). Watch out for classloader issues though.
Using Spring, you can do it via EJB3 interceptors, see http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ejb.html#ejb-implementation-ejb3
Useful info on caveats are in the javadoc, make sure you read it: http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/ejb/interceptor/SpringBeanAutowiringInterceptor.html

Categories

Resources