Configuring MDB (on Glassfish) to listen to a shared topic subscription - glassfish

What I am looking for is the exact activation configuration property name in order to configure a Message Driven Bean to accept messages from a JMS Topic in Shared subscription mode
#MessageDriven(activationConfig = {
#ActivationConfigProperty(propertyName = "destinationLookup",propertyValue = "java:app/jms/testT1"),
#ActivationConfigProperty(propertyName = "destinationType",propertyValue = "javax.jms.Topic"),
//the below property is not working in GlassFish (4.1) - just to convey the idea
#ActivationConfigProperty(propertyName = "sharedSubscription",propertyValue = "TRUE")
})
//edited
Please note: the intention is to be able to use MDBs (against a shared topic for load balancing purposes) in a JavaEE application which can be scaled out horizonatally. This question is not related to a clustered setup, hence use of useSharedSubscriptionInClusteredContainer (in Open MQ) is not applicable

If I understand you correctly, you don't need to do this. The point of having multiple consumers allowed on a single subscription was to work around a Java SE limitation, which is not an issue in Java EE:
http://www.oracle.com/technetwork/articles/java/jms2messaging-1954190.html
In Java EE, you just need to create your MDB to subscribe to a topic, then configure the bean pool to have multiple MDBs:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-ejb-jar PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 EJB 3.1//EN" "http://glassfish.org/dtds/glassfish-ejb-jar_3_1-1.dtd">
<glassfish-ejb-jar>
<enterprise-beans>
<ejb>
<ejb-name>MyPooledMDB</ejb-name>
<bean-pool>
<max-pool-size>5</max-pool-size>
<resize-quantity>1</resize-quantity>
<steady-pool-size>1</steady-pool-size>
</bean-pool>
</ejb>
</enterprise-beans>
</glassfish-ejb-jar>
For more information, see the Oracle GlassFish docs:
https://docs.oracle.com/cd/E18930_01/html/821-2418/beait.html
(note that steady-pool-size === "Initial and Minimum Pool Size")

Related

Embed Payara in Java SE

Context: Existing JavaSE application written in Swing which fires up an embedded server (so far it was Jetty) but we need to switch to Java EE, so we thought about bringing in an enterprise container (candidates are: Payara, Tomee, Wildfly).
The server should be able to run a web app based on dynamic input: web context, with its own web.xml, specific web resources which are not known at build time, so uber jar is not really an option for us.
We have successfully started a web app on Payara using code like the following (this is not working code, but it shows the steps we took for using Payara)
GlassFish glassfish;
WebContainer container;
GlassFishRuntime glassfishRuntime = = GlassFishRuntime.bootstrap();
glassfish = glassfishRuntime.newGlassFish();
glassfish.start();
// Access WebContainer
container = glassfish.getService(WebContainer.class);
WebContainerConfig config = new WebContainerConfig();
container.setConfiguration(config);
Context context = container.createContext(contextPathLocation);
m_webAppContexts.put(p_contextName, context);
WebListener listener = container.createWebListener("listener-1", HttpListener.class);
listener.setPort(myDynamicPortNumber);
container.addWebListener(listener);
container.addContext(context, myDynamicContextPath);
context.addServlet(myDynamicMapping, myServletName);
This is all working and a basic web application starts in Payara when invoked from our Java SE application.
We also have a fragment of web.xml declaring additional servlets that we want to bring in this dynamic deployment if given conditions are satisfied.
What is the best way to override the existing web.xml with fragments from another web.xml? We need pointers to documentation, directions from more experienced Payara users.
This is not possible with Payara or Wildfly, as they work very differently from how Jetty works.
However, it is possible with Tomee.

WebSphere MQ 6.0: Can't switch from non-durable to durable

When I switch from non-durable to durable topic subscriber, I am unable to look up the topic name that I could read before (using JNDI).
It gives an error in the admin console as the topic is being looked up:
An error occurred during activation of changes, please see the log for details.
ERROR: Could not activate itft-jmsmodule!ITFT-JMS-1#ItftTopic
The Messaging Kernel ITFT-JMS-1 has not yet been opened
I am using Oracle WebLogic Server Administrative Console to set up the WebSphere queue. On the console, I made these changes:
For the Persistent Stores, On the Configuration tab, Added a file store called ItftFileStore
For the Persistent Stores, On the Configuration tab, Added a directory.
For the JMS Servers, On the Configuration -> General tab, Changed the Persistent Store to ItftFileStore
For the JMS Servers, On the Configuration -> General tab -> Advanced, Checked the Store Enabled field.
For the ItftTopic, Configuration -> Override tab, Changed Delivery Mode Override to Persistent.
This is the code which I am running. There are some comments on the pertinent lines.
public void start() throws Exception {
try {
LOG.info("Starting the FC MQ message consumer / listener ...");
InitialContext initialContext = getInitialContext();
topicConnectionFactory = (TopicConnectionFactory) initialContext.lookup(jmsFactory);
topicConnection = topicConnectionFactory.createTopicConnection();
topicConnection.setClientID(clientId);
LOG.info("1"+topicConnection.getClientID());
topicSession = topicConnection.createTopicSession(false, Session.CLIENT_ACKNOWLEDGE);
LOG.info("2"+topicConnection.getClientID());
//topicConnection.setExceptionListener(connectionExceptionListener);
jmsTopic = (Topic) initialContext.lookup(topic); // Error being thrown here
LOG.info("3"+topicConnection.getClientID());
//topicSubscriber = topicSession.createSubscriber(jmsTopic); // Works as a non-durable subscriber
topicSession.createDurableSubscriber(jmsTopic,subscriberName);
LOG.info("4"+topicConnection.getClientID());
topicSubscriber.setMessageListener(messageListener);
topicConnection.start();
The fundamental aspect of the problem is that you are connecting WebLogic to a Websphere JMS topic, this has become clear with the last edit of your question but it is not clear whether you are using WebLogic Messaging Bridge or not. The Messaging Bridge is the proper way of configuring a foreign JMS server in WebLogic. I suggest reading this FAQ and this how-to that is specific for Websphere.

How to manually set/propagate security context information e.g. Principal for JBoss 7 (over JBoss remoting 2)

I'm using jboss remoting 2.5.4.SP3 to provide remote access to EJBs in a JBoss 7.1 server from both a web app and other JBoss instances. I'm doing it manually because of issues with remote EJB access in JBoss 7.1, specifically (but not only) the inability to access the same (interface) bean on multiple servers simultaneously. I'm using remoting2 because remoting3 has no documentation.
I have remoting working using TransporterHandle/TransporterClient using the socket transport, but in methods called via this remote connection, the server wants to lookup the principal from the ejbContext. I can't find a way to manually set the principal, or other contextual security/identity information. At the limit I'd be happy just to set the principal when the ejb method is invoked - all incoming calls are to local EJB3 beans - or even to set it specifically for the EJBContext.
I've found a lot of information regarding Spring (which I'm not using), but nothing seems to match my particular context.
And now, the correct way to do this:
On the client side I get the security context and package up the security domain and subject info for transport to the server along with the invocation. The SecurityDomain is a String and SubjectInfo is serializable:
Map m = new HashMap();
SecurityContext securityContext = SecurityContextAssociation.getSecurityContext();
if (securityContext != null) {
m.put("SUBJECT-INFO", securityContext.getSubjectInfo());
m.put("SECURITY-DOMAIN", securityContext.getSecurityDomain());
}
response = remotingClient.invoke(request, m);
The map m gets sent with the invocation over jboss remoting. On the server side, I extract the security information and set the context for the invocation like this:
SecurityContext oldContext = SecurityContextAssociation.getSecurityContext();
SubjectInfo si = (SubjectInfo) invocation.getRequestPayload().get("SUBJECT-INFO");
String domain = (String) invocation.getRequestPayload().get("SECURITY-DOMAIN");
if (si != null) {
SecurityContext sc = new JBossSecurityContext(domain);
sc.setSubjectInfo(si);
SecurityContextAssociation.setSecurityContext(sc);
}
try {
return super.invoke(invocation);
} finally {
SecurityContextAssociation.setSecurityContext(oldContext);
}
Works like a charm!
Have a look at the jboss-ejb-client.properties. There is also a quickstart example using a remote client to lookup an EJB.
I've solved my underlying problem, although not in the general way I was hoping for.
I put a servlet filter on all incoming requests, recording request.getUserPrincipal in a thread local. I can then access this in non-EE code and find the principal making the request. Then when I make call to my app server I use JBoss Remoting's ability to attach metadata to each invocation to pass the Principal over the wire. I had to copy the TransporterClient to do this because it's private constructors et al don't allow for overriding the functionality required to attach per-request metadata (as opposed to per-connection). On the server side I take the incoming Principal and set it into a thread local. Then, in subsequent code that accesses EJBContext.getCallerPrincipal I also lookup the incoming Principal from the thread local, and if that isn't null (hence we are in a remote EJB call), I use that if the caller principal is anonymous. If it's not anonymous then it must have been set in some way after the incoming call, so I ignore the incoming Principal in that case.
All in all, a much more specialised solution than I was hoping for, and it doesn't shed any light on how I can do generic context propagation in JBoss 7.1 over the wire.

How to create a jms Topic and TopicConnectionFactory programmatically?

Anyone know if you can create a topic and its connection factory programmatically? Currently I use the glassfish admin utility to create my topic and its connection factory. If I can't create it in code does glassfish/openmq have a default topic and conn factory I can use?
If you only want to circumvent creating the resources manually in the admin you can simply deploy them with the file "glassfish-resources.xml" (GF 3.1, see http://docs.oracle.com/cd/E18930_01/html/821-2417/giyhh.html).
You need an admin-object-resource like this one (for a topic):
<admin-object-resource enabled="true" jndi-name="jms/myTopic"
object-type="user" res-adapter="jmsra" res-type="javax.jms.Topic">
<property name="Name" value="physicalTopic"/>
</admin-object-resource>
Be aware that you must use different "Name" values for the Topic (here: "physicalTopic") if you implement multiple Topics whose messages should not get mixed up.
Further you need a connector-resource referencing a connector-connection-pool of type javax.jms.TopicConnectionFactory.
If you don't aim for dynamically creating resources using the deployment descriptor glassfish-resources.xml seems to be the best way.
Please note that resources deployed that way are application-scoped: http://docs.oracle.com/cd/E18930_01/html/821-2417/giydj.html
"glassfish-resources.xml" is the file for GF 3.x, for GF 2.x it was "sun-resources.xml". The file is located in the "Server Resources" folder in your project view if you are using NetBeans. Attention: the glassfish-resources.xml in "Server Resources" is only used by NetBeans if you use NetBeans to deploy! NetBeans knows how to create theses resources and conducts this task. If you deploy an EAR directly to Glassfish without NetBeans -- which seems very likely for a production environment -- you have to provide glassfish-resources.xml in:
META-INF of your EJB module or WEB-INF of your WAR for module scoped resources
META-INF of your enterprise application for application wide resources
In NetBeans you accomplish this by placing the file into the "Configuration Files" folder of your project view (which is src/conf/ in the file system).
You can easily create this resource definition by using NetBeans' [New Message-Driven Bean] wizard (simply add an MBean by selecting [New ...]). In the wizard choose "Project Destinations" > [Add]. A complete 3.1 example looks like this:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
<admin-object-resource enabled="true" jndi-name="jms/myDestination" res-type="javax.jms.Topic" res-adapter="jmsra">
<property name="Name" value="PhysicalTopic"/>
</admin-object-resource>
<connector-connection-pool name="jms/myDestinationFactoryPool" connection-definition-name="javax.jms.TopicConnectionFactory" resource-adapter-name="jmsra"/>
<connector-resource enabled="true" jndi-name="jms/myDestinationFactory" pool-name="jms/myDestinationFactoryPool" />
</resources>
This is the MBean annotation:
#MessageDriven(mappedName = "java:app/jms/myDestination", activationConfig =
{
#ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
#ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "Durable"),
#ActivationConfigProperty(propertyName = "clientId", propertyValue = "NewMessageBean"),
#ActivationConfigProperty(propertyName = "subscriptionName", propertyValue = "NewMessageBean")
})
public class NewMessageBean implements MessageListener
{
[...]
Caution: "java:app/" in mappedName is correct only if you use application scoped resources. You can spare "java:app/" in the definition in glassfish-resources.xml. The GF deployment guide says: "Application-scoped resource JNDI names begin with java:app or
java:module. If one of these prefixes is not specified in the JNDI name, it is added."
You can also introduce another level of indirection by using "name" instead of "mappedName". You then have to provide a file named "application-client.xml" where the (logical) name gets mapped to an JNDI "physical" location.

EJB lookup problem

I have a Glassfish v2.1.1 cluster setup. I deployed an EAR file consisting a single stateless bean to stand alone server. It has an IIOP port 3752.
My client application which will be communicating with this bean is deployed on cluster. When i lookup bean's name, i get NameNotFoundException. Code looks as below:
Properties props = new Properties();
props.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");
props.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming");
props.setProperty("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
if (logger.isDebugEnabled()) {
logger.debug("Looking for bean from location : " + PropertiesService.instance().getSchedulerOrbHost() + ":"
+ PropertiesService.instance().getSchedulerOrbPort());
}
props.setProperty("org.omg.CORBA.ORBInitialHost", PropertiesService.instance().getSchedulerOrbHost());
props.setProperty("org.omg.CORBA.ORBInitialPort", PropertiesService.instance().getSchedulerOrbPort());
InitialContext context = null;
try {
context = new InitialContext(props);
} catch (NamingException e) {
e.printStackTrace();
}
String beanName = "test.OperationControllerRemote";
OperationControllerRemote remote = (OperationControllerRemote) context.lookup(beanName);
Note that i checked JNDI tree and name "test.OperationControllerRemote" is there.
Any opinions please?
Here are the ways I have got it to work with a GF 2.1.1 cluster and a Swing client. I'm currently going with the Standalone option because of client launch speed, but the ACC might work for you.
Standalone
The way you're doing it is considered standalone.
http://glassfish.java.net/javaee5/ejb/EJB_FAQ.html#StandaloneRemoteEJB
http://blogs.oracle.com/dadelhardt/entry/standalone_iiop_clients_with_glassfish
ACC
Another way to approach this is to launch the client with the ACC. This means packaging the client code into the ear as an Application Client and either launching using the JNLP method or manually installing a bundled ACC (mini glassfish really) on client machines. In GF 2.1, either way works ok, but both are pretty fat and JNLP method can make startup times a bit longer. Supposedly in GF 3.1 they've reworked the ACC and it starts up faster. Something that may not be obvious is that with the ACC you get the list of servers in the cluster provided automatically at client startup.
http://blogs.oracle.com/theaquarium/entry/java_ee_clients_with_or
http://download.oracle.com/docs/cd/E18930_01/html/821-2418/beakv.html#scrolltoc
http://download.oracle.com/docs/cd/E18930_01/html/821-2418/gkusn.html
Lookups
Either of the above ways provides RMI/CORBA failover and load balancing for the client.
Either way, when you have the right dependencies on your classpath and the com.sun.appserv.iiop.endpoints system property set (like node1:33700,node2:33701), you'll only need the no-args InitialContext because Glassfish's stuff autoregisters their connection properties, etc as described in the first link:
new InitialContext()
And lookups will work. For my remote session beans (EJB 3.0) I typically do it like:
#Stateless(mappedName="FooBean")
public class FooBean implements FooBeanRemote {}
#Remote
public interface FooBeanRemote {}
then in client code:
FooBeanRemote foo = (FooBeanRemote) ctx.lookup("FooBean");