JMX configuration on JBoss EAP 6.1 - deployment

I'm trying to configure JMX with JBoss EAP 6.1, for this I've added jmx-console.war in my JBoss and put jboss-service.xml in my application. I'm trying to load a properties file and want to get it registered with JMX. JMX is showing all system beans but not loading my application's bean. This thing was working in AS version of JBoss. Is there some other way of configuring JMX with JBoss EAP? I've googled with all the combination but not finding any suitable answer. My jboss-service.xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!-- ===================================================================== -->
<!-- JBoss Server Configuration -->
<!-- ===================================================================== -->
<server>
<mbean code="com.asd.store.util.mbean.SystemConfig"
name="com.asd.store.util.mbean:service=jmx-common">
<constructor>
<arg type="java.lang.String" value="store-properties.xml"/>
<arg type="java.lang.String" value="${jboss.server.home.dir}/conf"/>
</constructor>
</mbean>
</server>

JBoss AS 7.x does that slightly differently.
Here's a nice article on 'How to create SAR on JBoss AS7':
http://middlewaremagic.com/jboss/?p=366
You can see JBoss and your MBeans by using jconsole, e.g. JBOSS_HOME/bin/jconsole.sh and see MBeans tab. I guess your jmx-console.war would work too.
It seems your MBeans did not get instantiated and registered properly by your application.
There are few ways to register your MBeans, see the article above for one possible way.
Here is another way that you can create and register your MBean using #Singleton, #Startup EJB bean:
- make your MBean #Singleton, #Startup EJB
- register your MBean in #PostConstruct lifecycle method
- unregister you MBean in your #PreDestroy lifecycle method
Here's an example MBean that tracks current number of users, maximum number of users, performance, etc...
MBean interface, e.g. MonitoringResourceMXBean.java:
package examples.mymonitoring;
public interface MonitoringResourceMXBean {
// current user count
long getCurrentUsers();
void countUserUp();
void countUserDown();
// maximum user count
long getMaximumUsers();
void setMaximumUsers(long max);
// request count
long getRequests();
long countRequest();
// maximum duration of request
long getMaximumWait();
void reportWait(long wait);
}
MBean implementation, e.g.
package examples.mymonitoring;
import java.lang.management.ManagementFactory;
import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.management.MBeanServer;
import javax.management.ObjectName;
#Singleton
#Startup
public class MonitoringResource implements MonitoringResourceMXBean {
private MBeanServer platformMBeanServer;
private ObjectName objectName = null;
private long maximumUsers = 100;
private AtomicLong requestCount = new AtomicLong(0);
private AtomicLong currentUsers = new AtomicLong(0);
private long maximumWait = 0;
#PostConstruct
public void registerInJMX() {
try {
objectName = new ObjectName("MyMonitoring:type=" + this.getClass().getName());
platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
platformMBeanServer.registerMBean(this, objectName);
} catch (Exception e) {
throw new IllegalStateException("Problem during registration of Monitoring into JMX:" + e);
}
}
#PreDestroy
public void unregisterFromJMX() {
try {
platformMBeanServer.unregisterMBean(this.objectName);
} catch (Exception e) {
throw new IllegalStateException("Problem during unregistration of Monitoring into JMX:" + e);
}
}
#Override
public long getCurrentUsers() {
return this.currentUsers.get();
}
#Override
public void countUserUp() {
this.currentUsers.incrementAndGet();
}
#Override
public void countUserDown() {
this.currentUsers.decrementAndGet();
}
#Override
public long getMaximumWait() {
return this.maximumWait;
}
#Override
public long getMaximumUsers() {
return this.maximumUsers;
}
#Override
public void setMaximumUsers(long max) {
this.maximumUsers = max;
}
#Override
public void reportWait(long wait) {
if ( wait > maximumWait ) maximumWait = wait;
}
#Override
public long getRequests() {
return this.requestCount.get();
}
#Override
public long countRequest() {
return this.requestCount.incrementAndGet();
}
}
Hope the example helps.
Cheers!

Related

Purpose and behaviour of init() in Vertx class

I have the following verticle for testing purposes:
public class UserVerticle extends AbstractVerticle {
private static final Logger log = LoggerFactory.getLogger(UserVerticle.class);
#Override
public void start(Future<Void> sf) {
log.info("start()");
JsonObject cnf = config();
log.info("start.config={}", cnf.toString());
sf.complete();
}
#Override
public void stop(Future<Void> sf) {
log.info("stop()");
sf.complete();
}
private void onMessage(Message<JsonObject> message) { ... }
log.info("onMessage(message={})", message);
}
}
Is is deployed from the main verticle with
vertx.deployVerticle("org.buguigny.cluster.UserVerticle",
new DeploymentOptions()
.setInstances(1)
.setConfig(new JsonObject()
.put(some_key, some_data)
),
ar -> {
if(ar.succeeded()) {
log.info("UserVerticle(uname={}, addr={}) deployed", uname, addr);
// continue when OK
}
else {
log.error("Could not deploy UserVerticle(uname={}). Cause: {}", uname, ar.cause());
// continue when KO
}
});
This code works fine.
I had a look at the Verticle documentation and discovered an init() callback method I didn't see before. As the documentation doesn't say much about what it really does, I defined it to see where in the life cycle of a verticle it gets called.
#Override
public void init(Vertx vertx, Context context) {
log.info("init()");
JsonObject cnf = context.config();
log.info("init.config={}", cnf.toString());
}
However, when init() is defined I get a java.lang.NullPointerException on the line where I call JsonObject cnf = config(); in start():
java.lang.NullPointerException: null
at io.vertx.core.AbstractVerticle.config(AbstractVerticle.java:85)
at org.buguigny.cluster.UserVerticle.start(UserVerticle.java:30)
at io.vertx.core.impl.DeploymentManager.lambda$doDeploy$8(DeploymentManager.java:494)
at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:320)
at io.vertx.core.impl.EventLoopContext.lambda$executeAsync$0(EventLoopContext.java:38)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:462)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
My questions are:
Q1 : any clue why NullPointerException is thrown?
Q2 : what is the purpose of init()? Is it internal to Vertx or can it be be implemented by client code to, for example, define some fields in the verticle objects passed in deployment config ?
The init method is for internal usage and documented as such in the Javadoc. Here's the source code:
/**
* Initialise the verticle.<p>
* This is called by Vert.x when the verticle instance is deployed. Don't call it yourself.
* #param vertx the deploying Vert.x instance
* #param context the context of the verticle
*/
#Override
public void init(Vertx vertx, Context context) {
this.vertx = vertx;
this.context = context;
}
If init is documented in any user documentation it's a mistake, please report it.

my activemq plugin not work

I write an ActiveMQ plugin, but it does not work.
The code:
package cn.ennwifi.mqttplugin;
import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.BrokerPlugin;
public class MqttPlugin implements BrokerPlugin {
public Broker installPlugin(Broker broker) throws Exception {
return new MqttFilter(broker);
}
}
package cn.ennwifi.mqttplugin;
import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.BrokerFilter;
import org.apache.activemq.broker.ConnectionContext;
import org.apache.activemq.command.ConnectionInfo;
public class MqttFilter extends BrokerFilter {
public MqttFilter(Broker broker) {
super(broker);
System.out.println("mqtt插件");
}
#Override
public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
System.out.println("mqtt连接信息:" + info.getClientId());
if (info.getUserName() != "123") {
return;
}
super.addConnection(context, info);
}
}
The configure:
<plugins>
<bean xmlns="http://www.springframework.org/schema/beans" id="myplugin" class="cn.ennwifi.mqttplugin.MqttPlugin"/>
</plugins>
I used mvn:clean package pack a jar,put it to activemq/lib
The version is 5.14.1
I change my code
if (info.getUserName() == null) {
throw new Exception("用户名不能为空");
}
I used throw an exception replace return.
Use Log4j to be able to see what's happening.
Do something like below:
private static Logger LOG = LoggerFactory.getLogger(MqttFilter.class);
LOG.info("my message");
Hope this helps.

Best way to handle incoming messages with XMPP

Is there a work-around to get Spring to handle incoming messages from XMPP? I have tried many different configurations to get an inbound-channel-adapter to respond to incoming XMPP messages and nothing happens. I know that they show up at the Spring Integration layer (I can see that in the logs) but they are ignored. Is there any way to get them into my application layer? I hope to avoid needing to make changes to Spring Integration itself if I can.
Here is my integration configuration:
<int-xmpp:inbound-channel-adapter id="gcmIn"
channel="gcmInChannel"
xmpp-connection="gcmConnection"
auto-startup="true"
/>
<bean id="inboundBean" class="example.integration.GcmInputHandler"/>
<int:service-activator input-channel="gcmInChannel" output-channel="nullChannel" ref="inboundBean" method="handle"/>
Using the outbound-channel-adapter works fine. I can send messages over GCM 100% easily. But inbound does nothing, even though I know the messages are coming in.
Thanks
Not a very clean one, you would need to overwrite the ChatMessageListeningEndpoint, which drops all empty body messages.
This one needs then to be used as inbound-channel adapter in your config.
In addition you need to register the GCM package extension on the Smack Provider Manager, otherwise you lose the JSON message.
Working on a sample project -- so if you need more help let me know and I will post a link as soon it works somehow in a understandable way.
Here a sample GCM Input Adapter
public class GcmMessageListeningEndpoint extends ChatMessageListeningEndpoint {
private static final Logger LOG = LoggerFactory.getLogger(GcmMessageListeningEndpoint.class);
#Setter
protected PacketListener packetListener = new GcmPacketListener();
protected XmppHeaderMapper headerMapper = new DefaultXmppHeaderMapper();
public GcmMessageListeningEndpoint(XMPPConnection connection) {
super(connection);
ProviderManager.addExtensionProvider(GcmPacketExtension.GCM_ELEMENT_NAME, GcmPacketExtension.GCM_NAMESPACE,
new PacketExtensionProvider() {
#Override
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
String json = parser.nextText();
return new GcmPacketExtension(json);
}
});
}
#Override
public void setHeaderMapper(XmppHeaderMapper headerMapper) {
super.setHeaderMapper(headerMapper);
this.headerMapper = headerMapper;
if (this.headerMapper == null) throw new IllegalArgumentException("Null XmppHeaderMapper isn't supported!");
}
public String getComponentType() {
return "xmpp:inbound-channel-adapter-gcm";
}
#Override
protected void doStart() {
Assert.isTrue(this.initialized, this.getComponentName() + " [" + this.getComponentType() + "] must be initialized");
this.xmppConnection.addPacketListener(this.packetListener, null);
}
#Override
protected void doStop() {
if (this.xmppConnection != null) {
this.xmppConnection.removePacketListener(this.packetListener);
}
}
class GcmPacketListener implements PacketListener {
#Override
public void processPacket(Packet packet) throws NotConnectedException {
if (packet instanceof org.jivesoftware.smack.packet.Message) {
org.jivesoftware.smack.packet.Message xmppMessage = (org.jivesoftware.smack.packet.Message) packet;
Map<String, ?> mappedHeaders = headerMapper.toHeadersFromRequest(xmppMessage);
sendMessage(MessageBuilder.withPayload(xmppMessage).copyHeaders(mappedHeaders).build());
} else {
LOG.warn("Unsuported Packet {}", packet);
}
}
}
}
And here the new configuration for the inbound-channel-adapter remove the one in XML:
#Bean
public GcmMessageListeningEndpoint inboundAdpater(XMPPConnection connection, MessageChannel gcmInChannel) {
GcmMessageListeningEndpoint endpoint = new GcmMessageListeningEndpoint(connection);
endpoint.setOutputChannel(gcmInChannel);
return endpoint;
}

How to launch Spring DM service consumer in OSGI

I started creating an OSGI project with Spring DM. I Created two bundles, the first one (bundle1) provides a service that changes the order of a recieved string. The seconde one (bundle2) consumes that service and prints the result in the console.
service implementation:
public final class Bundle1ServiceImpl implements Bundle1Service {
public Bundle1ServiceImpl() {
System.out.println("Bundle1ServiceImpl contructor...");
}
public String scramble(String text) {
List charList = new ArrayList();
char[] textChars = text.toCharArray();
for (int i = 0; i < textChars.length; i++) {
charList.add(new Character(textChars[i]));
}
Collections.shuffle(charList);
char[] mixedChars = new char[text.length()];
for (int i = 0; i < mixedChars.length; i++) {
mixedChars[i] = ((Character) charList.get(i)).charValue();
}
return new String(mixedChars);
}}
spring file for service provider :
bundle1-osgi.xml
<service ref="bundle1Service" interface="fr.thispro.bundle1.Bundle1Service" />
bundle1-context.xml
<bean id="bundle1Service" class="fr.thispro.bundle1.internal.Bundle1ServiceImpl">
</bean>
consumer :
public class Bundle2Consumer {
private final Bundle1Service service;
public Bundle2Consumer(Bundle1Service service) {
this.service = service;
}
public void start() {
System.out.println(service.scramble("Text"));
System.out.println("im started");
}
public void stop() {
System.out.println("im stopped");
}}
spring files for consumer:
bundle2-context.xml
<beans:bean id="consumer" class="fr.thispro.bundle2.Bundle2Consumer" init-method="start" destroy-method="stop" lazy-init="false" ><beans:constructor-arg ref="bundle1Service"/>
bundle2-osgi.xml
<reference id="bundle1Service" interface="fr.thispro.bundle1.Bundle1Service" />
The service is well registred referenced and discovered. But the consumer doesn't print anything even when i start it explicitly by start command.
Thanks in adanvance,
I found the problem. You bundle2 incldues an Activtor but you did not define the activator in the Manifest. So the bundle never actually starts up.
If you intended to start the bundle2 using spring dm then the problem is that the jar does not contain the spring xml files.

jBoss deployment of message-driven bean spec violation

I have an java EE application which has one message-driven bean and it runs fine on JBoss 4, however when I configure the project for JBoss 6 and deploy on it, I get this error;
WARN [org.jboss.ejb.deployers.EjbDeployer.verifier] EJB spec violation:
...
The message driven bean must declare one onMessage() method.
...
org.jboss.deployers.spi.DeploymentException: Verification of Enterprise Beans failed, see above for error messages.
But my bean HAS the onMessage method! It would not have worked on jboss 4 either then.
Why do I get this error!?
Edit:
The class in question looks like this
package ...
imports ...
public class MyMDB implements MessageDrivenBean, MessageListener {
AnotherSessionBean a;
OneMoreSessionBean b;
public MyMDB() {}
public void onMessage(Message message) {
if (message instanceof TextMessage) {
try {
//Lookup sessionBeans by jndi, create them
lookupABean();
// check message-type, then invokie
a.handle(message);
// else
b.handle(message);
} catch (SomeException e) {
//handling it
}
}
}
public void lookupABean() {
try {
// code to lookup session beans and create.
} catch (CreateException e) { // handling it and catching NamingException too }
}
}
Edit 2:
And this is the jboss.xml relevant parts
<message-driven>
<ejb-name>MyMDB</ejb-name>
<destination-jndi-name>topic/A_Topic</destination-jndi-name>
<local-jndi-name>A_Topic</local-jndi-name>
<mdb-user>user</mdb-user>
<mdb-passwd>pass</mdb-passwd>
<mdb-client-id>MyMessageBean</mdb-client-id>
<mdb-subscription-id>subid</mdb-subscription-id>
<resource-ref>
<res-ref-name>jms/TopicFactory</res-ref-name>
<jndi-name>jms/TopicFactory</jndi-name>
</resource-ref>
</message-driven>
Edit 3:
I just removed all my jars from the project, and only re-added relevant ones (from new versions also) to put out NoClassDefFound errors.
Still the problem remains.
Edit:
Any directions, what area should I look at? My project, or jboss-configration, or the deployment settings??
org.jboss.ejb.deployers.EjbDeployer.verifier
looks for
public void onMessage(javax.jms.Message)
via some code like this (this is from JBoss5):
/**
* Check if the given message is the onMessage() method
*/
public boolean isOnMessageMethod(Method m)
{
if ("onMessage".equals(m.getName()))
{
Class[] paramTypes = m.getParameterTypes();
if (paramTypes.length == 1)
{
if (Message.class.equals(paramTypes[0]))
return true;
}
}
return false;
}
It is important that the parameter type is javax.jms.Message and nothing else, for example some subclass or superclass or some implementing class.
Your signature is public void onMessage(Message message) which looks ok on first sight.
A Class is equal only in its ClassLoader. If for some reasons javax.jms.Message is available in different classloaders in the same JVM, strange things can happen, depending on the ClassLoader of the EjbDeployer.verifier. Maybe the EjbDeployer.verifer has a access to javax.jms.Message in another ClassLoader as MyMDB. As result, both javax.jms.Message are not equal to each other, although they are the same byte-code and literally exists. The EjbVerifier will warn about missing onMessage, because javax.jms.Message on ClassLoader A is not equal to javax.jms.Message on ClassLoader B.
This can happen when libraries with javax.jms.Message is copied on wrong places on the JBoss AS. So I guess - from a distance - that there is some jars containing javax.jms.Message in wrong places on the JBoss or the EAR. For example some wrong jbossallclient.jar in the EAR.
Make sure your EAR does not contain its own copies of the javax.ejb classes (or any javax classes at all, for that matter). JBoss 4 and 6 have rather different classloading semantics, and what works on one may not work on the other. For example, if your EAR's lib contained its own copies of Message or MessageListener, then it may no longer work.
I tried it out on "JBossAS [6.0.0.20100911-M5 "Neo"]" and Eclipse Helios
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenBean;
import javax.ejb.MessageDrivenContext;
import javax.jms.Message;
import javax.jms.MessageListener;
#MessageDriven(
activationConfig = { #ActivationConfigProperty(
propertyName = "destinationType", propertyValue = "javax.jms.Topic"
) },
mappedName = "topic/A_Topic",
messageListenerInterface = MessageListener.class)
public class MyMDB implements MessageListener, MessageDrivenBean {
private static final long serialVersionUID = -4923389997501209506L;
public MyMDB() {
// TODO Auto-generated constructor stub
}
#Override
public void ejbRemove() {
// TODO Auto-generated method stub
}
#Override
public void setMessageDrivenContext(MessageDrivenContext arg0) {
// TODO Auto-generated method stub
}
#Override
public void onMessage(Message message) {
// TODO Auto-generated method stub
}
}
And this setting works. Do you have the same imports for your bean (perhaps there was an automatic import gone wrong???)