Facing issues while setting JVM properties for JMX remote management - java

When I export my JMX agent for remote management, and set the following parameters as VM arguments
-Dcom.sun.management.jmxremote=true
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.ssl=false
It works fine as my JMX client is able to easily establish connection with the MBean at port 9999.
Now, I want to set these properties at run time via my configuration file.
I tried setting it via System.setProperty("com.sun.management.jmxremote.port","9999"); and other properties similarly but to no avail.
The JMX Agent doesn't get exposed for remote management in this way.
I even tried creating a registry on the port 9999 but still doesn't seem enough.
private void init() {
try {
LocateRegistry.createRegistry(9999);
System.setProperty("com.sun.management.jmxremote", "true");
System.setProperty("com.sun.management.jmxremote.authenticate", "false");
System.setProperty("com.sun.management.jmxremote.port", "9999");
System.setProperty("com.sun.management.jmxremote.ssl", "false");
} catch (RemoteException e) {
e.printStackTrace();
}
}
I just don't understand why setting these properties via VM arguments works and not while setting the same properties programatically as I described above.

This is what works for me. I am assuming you already know how to right SimpleMXBean used in below example.
Reference Oracle JMX Tutorial. (See section Mimicking Out-of-the-Box Management Using the JMX Remote API.)
package sample;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.rmi.registry.LocateRegistry;
import java.util.HashMap;
import java.util.Map;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
public class MBServerTest {
public static void loadJMXAgent(int port, MBeanServer mbs) throws IOException {
LocateRegistry.createRegistry(port);
System.out.println("Initialize the environment map");
Map<String,Object> env = new HashMap<String,Object>();
env.put("com.sun.management.jmxremote.authenticate", "false");
env.put("com.sun.management.jmxremote.ssl", "false");
System.out.println("Create an RMI connector server");
JMXServiceURL url =
new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:"+port+"/jmxrmi");
JMXConnectorServer cs =
JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
// Start the RMI connector server.
//
System.out.println("Start the RMI connector server");
cs.start();
}
public static void main(String[] args) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
loadJMXAgent(1199,mbs);
SimpleStandard cache = new SimpleStandard();
ObjectName name = new ObjectName(
"org.javalobby.tnt.jmx:type=ApplicationCacheMBean");
mbs.registerMBean(cache, name);
imitateActivity(cache);
}
private static void imitateActivity(SimpleStandard cache) {
while (true) {
try {
cache.cacheObject("hello");
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}

Setting the system properties from your application is a bit too late. The JMX agent has already been loaded and initialized.
You can use a JMX configuration file to store the properties in one external file. While it does not allow you read the properties from one shared configuration file it enabled you at least externalize the settings into a different user properties file.

Just providing the property probably does not trigger the creation of an RMI connector on the port that you provided. If you want to enable remote monitoring at runtime then I think you also have to create the connector on the MBean server yourself.
Check out the chapter "Mimicking Out-of-the-Box Management" of the Oracle JMX tutorial. In particular this last bit of the sample code, which uses port 3000 for the RMI server. This is where you want to put the port of your choice:
LocateRegistry.createRegistry(3000);
Map<String,Object> env = new HashMap<String,Object>();
env.put("com.sun.management.jmxremote.authenticate", "false");
env.put("com.sun.management.jmxremote.ssl", "false");
// Create an RMI connector server.
//
// specified in the JMXServiceURL the RMIServer stub will be
// registered in the RMI registry running in the local host on
// port 3000 with the name "jmxrmi". This is the same name the
// out-of-the-box management agent uses to register the RMIServer
// stub too.
//
System.out.println("Create an RMI connector server");
JMXServiceURL url =
new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:3000/jmxrmi");
JMXConnectorServer cs =
JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
// Start the RMI connector server.
//
System.out.println("Start the RMI connector server");
cs.start();

Try to set properties in a static block.
static {
System.setProperty("com.sun.management.jmxremote.port", "9999");
System.setProperty("com.sun.management.jmxremote.authenticate", "false");
System.setProperty("com.sun.management.jmxremote.ssl", "false");
}

Related

JMS connection to a remote MQ with bindings

I want to configure a Java application to work with a JMS IBM MQ queue using the bindings file.
I am using the JMSDEMO application provided by IBM.
It works with a local MQ manager but I cannot make it connect to a remote one.
I've generated the bindings file on the remote machine and copied it to my machine.
I've changed the "localhost" in the bindings file to the remote machine name.
However, the app still thinks it should connect to a local QM.
(actually it ignores the hostname settings).
Here's the IBM demo code:
public static final String cfLookup = "JMSDEMOCF";
public static final String JNDITopic = "JMSDEMOTopic";
public static final String JNDIQueue = "JMSDEMOQueue";
public static final String icf ="com.sun.jndi.fscontext.RefFSContextFactory";
........
static String url = "file:C:\\JMSDEMO\\JNDI";
..........
Hashtable environment = new Hashtable();
environment.put(Context.INITIAL_CONTEXT_FACTORY, icf);
environment.put(Context.PROVIDER_URL, url);
ctx = new InitialDirContext( environment );
connFactory = (ConnectionFactory)ctx.lookup( cfLookup );
connection = connFactory.createConnection();
connection.start();
Here are some fragments of the bindings file (JMSDEMOCF is the name of the connection factory)
JMSDEMOCF/RefAddr/3/Content=<the remote machine name or IP; both ignored>
JMSDEMOCF/RefAddr/29/Content=<the remote machine name or IP; both ignored>(the remote port)
It also has the following line:
JMSDEMOCF/RefAddr/116/Type=XMSC_WMQ_LOCAL_ADDRESS
but deleting it changes nothing.
Create a new connection factory in your "bindings file" with MQ Explorer (why are you trying to edit the file by hand?), and specify the Transport option as MQ Client on this new connection factory (the default is Bindings, which is the local connection mode).
On the Connection tab specify the address of the QM, and on the Channels tab the server connection channel to be used to connect to the QM.
Use the new connection factory in your application when connecting from a remote host. You may need to include some additional MQ JARs in the classpath.

Communicating with AMQP 1.0 broker over SSL using Qpid

I am using ActiveMQ 5.8.0, which supports AMQP 1.0 as a queue broker. I am trying to communicate with this from a Java client using the Qpid AMQP1.0 client jms library but do not see a method of specifying keystore and truststore information.
I have successfully configured a client by passing in the SSL credentials via the Java VM options (e.g. -Djavax.net.ssl.keyStore), however this is not an acceptable method for my final solution... I need to be able to specify this information from within the code.
I am currently using the createFromURL method to generate the connection from a URL that includes SSL parameters as defined here, but the keystore information (and potentially failover params) do not appear to be parsed from the URL.
String connectionUrl = "amqps://localhost/?brokerlist='tcp://localhost:5671?ssl='true'&key_store='C:/apache-activemq-5.8.0/conf/client.ks'&key_store_password='password'&trust_store='C:/apache-activemq-5.8.0/conf/client.ts'&trust_store_password='password'";
ConnectionFactoryImpl connectionFactory = ConnectionFactoryImpl.createFromURL(connectionUrl);
Does anyone know a better way of providing the security information into the connection?
Update:
Right, so doing some digging through the API I have identified that the library uses the Default SSLSocketFactory
See: org.apache.qpid.amqp_1_0.client.Connection
final Socket s;
if(ssl)
{
s = SSLSocketFactory.getDefault().createSocket(address, port);
}
Therefore, there seems no way of specifying this information outside of the JVM options to set the default values... at least in the current version of the Qpid client library.
The connection URL parameters for the QPID JMS AMQP 1.0 client are a little bit different than the parameters for the previous AMQP version.
Here is an example for a connection URL that works for the 1.0 client:
amqp://myhost:myport?ssl=true&ssl-cert-alias=myalias&clientid=myclientid&remote-host=default&sync-publish=false&trust-store=C:/trusstore.ts&trust-store-password=mytrustkeypass&key-store=C:/keystore.ks&key-store-password=mykeypass
see also this link
Is the URL the right place to put the SSL parameters?
Should the ConnectionFactory not be getting a javax.net.ssl.SSLContext and then creating the connection?
(I'm not familiar with the particulars of the ActiveMQ API.)
For version 0.9.0 of QPid, which supports AMQP version 1.0.0, the client configuration page at QPID can also help with doing this programmatically.
I've also provided sample code of a successful program (NOTE: config is a class I created that stores all my configuration values):
String ampqProtocol = "amqp";
List<String> queryVariables = new ArrayList<String>();
if(config.isUseSSL()) {
queryVariables.add("transport.keyStoreLocation="+config.getKeyStorePath());
queryVariables.add("transport.keyStorePassword="+config.getKeyStorePassword());
queryVariables.add("transport.trustStoreLocation="+config.getTrustStorePath());
queryVariables.add("transport.trustStorePassword="+config.getTrustStorePassword());
queryVariables.add("transport.keyAlias="+config.getKeyStoreAlias());
queryVariables.add("transport.contextProtocol="+config.getSslProtocol());
queryVariables.add("transport.verifyHost="+!config.isDontValidateSSLHostname());
ampqProtocol = "amqps";
}
String connectionString = ampqProtocol+"://"+config.getAddress()+":"+config.getPort();
if(!queryVariables.isEmpty()) {
try {
connectionString += "?"+URLEncoder.encode(StringUtils.join(queryVariables, "&"), StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
Hashtable<Object, Object> env = new Hashtable<Object, Object>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.qpid.jms.jndi.JmsInitialContextFactory");
env.put("connectionfactory.myFactoryLookup", connectionString);
Context context = null;
ConnectionFactory connectionFactory = null;
try {
context = new InitialContext(env);
connectionFactory = (ConnectionFactory) context.lookup("myFactoryLookup");
} catch (NamingException e) {
e.printStackTrace();
}
Connection connection = null;
try {
connection = connectionFactory.createConnection();
connection.start();
} catch (JMSException e) {
e.printStackTrace();
}

How to set specify proxy for load server application in JVM & Jboss?

I have a load server application which switches between two applications, App1 & App2. Each App has its own IFrame which talks to a bank, but when the bank returns back data, the load server cannot distinguish which app was that. I investigated on that, then I found out that it is the proxy issue.
As a result, I tried to force the application to use proxyHost & proxyport but it did n't work, then I forced the Jboss to use the specific proxyHost & proxyport but it did n't work either. It use a default proxy on the box and it does n't care about my configuration.
Setting the proxyHost & proxyPort at the Jboss startup script (bin\run.bat):
the Jboss logs showed that it had accepted the java VM arguments (e.g. -Dhttp.proxyHost=XX.XX.XX.XX -Dhttp.proxyPort=8080), when we ran
the application, it would still go through the default proxy settings on the box.
I searched in google & stackoverflow and tried different ideas but didn't work.
Could someone please shed some light on it?
Could you try running your apps with the following JVM args: -Dsun.net.inetaddr.ttl=0 -Dnetworkaddress.cache.ttl=0?
The DNS settings get cached after a successful request, these parameters will disable the caching.
You can force an application to ignore any VM arguments for proxyHost and
just use the default proxy of the box it’s running on. You can write a small java program which just prints the default proxy and ran it on the specific box (like this one):
import java.net.InetSocketAddress;
import java.net.ProxySelector;
import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.List;
import java.net.URI;
public class PrintDefaultProxy {
public static void main(String[] args) {
// If you clear these 2 properties then set java.net.useSystemProxies to true, it
// will use the default System Proxy and ignore any settings given to the VM
// e.g. http.proxyHost & http.proxyPort
System.setProperty("http.proxyHost", "");
System.setProperty("http.proxyPort", "");
System.setProperty("java.net.useSystemProxies", "true");
System.out.println("detecting proxies");
List l = null;
try {
String url = "http://google.com.au/";
l = ProxySelector.getDefault().select(new URI(url));
}
catch (URISyntaxException e) {
e.printStackTrace();
}
if (l != null) {
for (Iterator iter = l.iterator(); iter.hasNext();) {
java.net.Proxy proxy = (java.net.Proxy) iter.next();
System.out.println("proxy Type : " + proxy.type());
InetSocketAddress addr = (InetSocketAddress) proxy.address();
if (addr == null) {
System.out.println("No Proxy");
} else {
System.out.println("proxy hostname : " + addr.getHostName());
System.setProperty("http.proxyHost", addr.getHostName());
System.out.println("proxy port : " + addr.getPort());
System.setProperty("http.proxyPort", Integer.toString(addr.getPort()));
}
}
}
}
}
Basically in the code, if you clear the http.proxyHost and http.proxyPort and then set java.net.useSystemProxies to true, it will use
the system default proxy (if any) and ignore any VM arguments.
System.setProperty("http.proxyHost", "");
System.setProperty("http.proxyPort", "");
System.setProperty("java.net.useSystemProxies", "true");
System.out.println("detecting proxies");
Then you run this on your box and passed it some bogus proxy addresss:
C:\t>"C:\Program Files\Java\jdk1.6.0_19\bin\java.exe" -Dhttp.proxyHost=99.0.0.99.9 -Dhttp.proxyPort=8080 PrintDefaultProxy
detecting proxies
proxy Type : DIRECT
No Proxy
Note, if you do not clear those 2 properties, it will use the arguments you pass to the JVM – but from my understanding it’s not what your application seems to be doing. This is a way that the application should ‘just work’ without having to specifically set the proxyHost – and this is most likely why it ignores whatever setting you provide it at the JVM/Jboss level.
When the behaviour is consistent with what you’ve experienced trying to change those settings in Jboss, it means you can’t configure it in an application or Jboss level to use a proxyHost and most likely needs to be done at a Network level.

Jetty servlet url and port

What is the method call to figure out what is the url and port a jetty servlet is running on? So that I can just print it on the screen, and use it in the client to connect:
url = new URL("trying to figure this out");
I am running both the client and the server locally, in eclipse, this is a school project.
Relevant code:
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
public class ServerMain {
public static void main(String[] args){
Server server = new Server();
ServletContextHandler context =
new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("Servlet");
context.setResourceBase("etc/docroot");
server.setHandler(context);
context.addServlet(new ServletHolder(new MyServer()), "/game");
DefaultServlet staticFileServlet = new DefaultServlet();
context.addServlet(new ServletHolder(staticFileServlet), "/*");
System.out.println("context: " + context.getContextPath());
//System.out.println("One valid Port = "
+ context.getServer().getConnectors()[0].getPort());
try {
server.start();
server.join();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Since you are doing this embedded you have a couple of options.
Server server = new Server(8080);
This will start the server on port 8080, which is fine if that is what you want but in unit tests you generally want this to be a random port to avoid issues with things like CI's or parallel tests tripping on each other.
Server server = new Server(0);
This will start the connector on a random port, but how to get that port?
server.getConnectors()[0].getLocalPort();
The port is really coming from the connector, and typically you only are setting up one connector here, so this gets you that port.
Now localhost works for testing well, but if you wanted the name of the host that the connector is on you can use this:
server.getConnectors()[0].getHost();
Chain that stuff up and you get how we do most of our unit testing in jetty itself, spinning up the server itself, wiring up whatever handler or webapps we want and then assert behaviors, requests, responses, etc.
We have a number of embedded examples here that you can look at for different ways to wire up jetty inside code, and the jetty.xml format is just a thin layer of xml over java so you can map the startup of jetty easily through the code by reading the xml file with a java hat on. There is an embedded example in here for bootstrapping jetty based on that xml format as well if you want to keep the config there.
http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded
For a good page on embedding jetty, look here: http://www.eclipse.org/jetty/documentation/current/embedding-jetty.html
Most likely the jetty server is running on 8080 as default. If not you can go and check the server.xml file which should tell you what the port configuration is.
I'm not sure what you're asking here but if you had some servlet i.e Hello :
public final class Hello extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println("URL is " + request.getRequestURL() + " port is " request.getServerPort());
}
}
Additionally if this is not info what you're looking for please see this :
http://docs.oracle.com/javaee/1.4/api/javax/servlet/http/HttpServletRequest.html
http://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/1.6/api/javax/servlet/http/HttpServletRequest.html

Java client listening to WebSphere MQ Server?

I need to write a Java client listening to WebSphere MQ Server. Message is put into a queue in the server.
I developed this code, but am not sure it is correct or not. If correct, then how can I test it?
This is a standalone Java project, no application server support. Which jars I should put into classpath?
I have the MQ settings, where I should put into my codes? Standard JMS can skip these settings? confusing ....
import javax.jms.Destination;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class Main {
Context jndiContext = null;
QueueConnectionFactory queueConnectionFactory = null;
QueueConnection queueConnection = null;
QueueSession queueSession = null;
Queue controlQueue = null;
QueueReceiver queueReceiver = null;
private String queueSubject = "";
private void start() {
try {
queueConnection.start();
queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = queueSession.createQueue(queueSubject);
MessageConsumer consumer = queueSession.createConsumer(destination);
consumer.setMessageListener(new MyListener());
} catch (Exception e) {
e.printStackTrace();
}
}
private void close() {
try {
queueSession.close();
queueConnection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private void init() {
try {
jndiContext = new InitialContext();
queueConnectionFactory = (QueueConnectionFactory) this.jndiLookup("QueueConnectionFactory");
queueConnection = queueConnectionFactory.createQueueConnection();
queueConnection.start();
} catch (Exception e) {
System.err.println("Could not create JNDI API " + "context: " + e.toString());
System.exit(1);
}
}
private class MyListener implements MessageListener {
#Override
public void onMessage(Message message) {
System.out.println("get message:" + message);
}
}
private Object jndiLookup(String name) throws NamingException {
Object obj = null;
if (jndiContext == null) {
try {
jndiContext = new InitialContext();
} catch (NamingException e) {
System.err.println("Could not create JNDI API " + "context: " + e.toString());
throw e;
}
}
try {
obj = jndiContext.lookup(name);
} catch (NamingException e) {
System.err.println("JNDI API lookup failed: " + e.toString());
throw e;
}
return obj;
}
public Main() {
}
public static void main(String[] args) {
new Main();
}
}
MQ Queue setting
<queue-manager>
<name>AAA</name>
<port>1423</port>
<hostname>ddd</hostname>
<clientChannel>EEE.CLIENTS.00</clientChannel>
<securityClass>PKIJCExit</securityClass>
<transportType>1</transportType>
<targetClientMatching>1</targetClientMatching>
</queue-manager>
<queues>
<queue-details id="queue-1">
<name>GGGG.NY.00</name>
<transacted>false</transacted>
<acknowledgeMode>1</acknowledgeMode>
<targetClient>1</targetClient>
</queue-details>
</queues>
There is an article with sample code Running a standalone Java application on WebSphere MQ V6.0 which walks you through most of your questions, including how you might test with a free WMQ trial install. The main difference (as discussed in the comments) to v7 or v7.1 is that there is no broker component to start if you want to use topics. Other than that, the article should work fine with the current WMQ client and/or server.
In addition, please refer to the WebSphere MQ Using Java manual (v7.0 client) or the Using WebSphere MQ Classes for Java manual (v7.1 client) for the appropriate CLASSPATH and other settings for your client. Remember to use the Infocenter appropriate to your client version and not to the server version. You can mix and match client and server version but you get only the features supported by the server. For example, using the WMQ v7.1 client with the WMQ v7.0 server is perfectly valid.
Finally, there are a number of sample programs supplied with the free client download that do exactly what you are describing. Some use JNDI to lookup the WMQ resources, others use Java methods and can be populated with standard Java property files. The ones with a -nojndi option show how to initialize your WMQ objects in the code at run time. These are under
[WMQ Install path]\tools\wmqjava\samples
...in the latest Windows client install (SupportPac MQC71). You can also use the v7.0 client (SupportPac MQC7). I would recommend using the samples to get started rather than starting from scratch. Why reinvent the wheel, right?
In addition to the many sample programs, the vendor install includes all of the requisite jar files. Note that what goes in the CLASSPATH changes by WMQ client version so refer to the Infocenter. The later versions are much simpler and require only a couple of jar files in the CLASSPATH.
If you want to download the WMQ trial for testing and do not have Administrator rights on your Windows workstation, you can install it easily on a RedHat or SUSE virtual machine. With a bit of massaging you can also easily install on Ubuntu as described in an Andy Piper blog post.
If you have the option, I would recommend that you introduce the Spring Framework to handle the JMS communication. That way you only need to write your business logic and can leave the error handling up to Spring.
Spring JMS
Download the latest Spring JARS and look at configuring a DefaultMessageListenerContainer for your application. You will then write your own POJO (plain old java object) with an onMessage() event that gets called everytime a new message arrives.
I found this tutorial that you may find useful to start with
There is a small client application that I developed in JavaFx2 for windows and Mac osx. It's available on source forge (https://sourceforge.net/projects/mqconsole).
You can see an example of listening to a queue for new messages.
The program lists the queues, the messages in each queue, view the details of the message and send a message to a queue and listen to the response.
You can check out the code, use it and improve it.

Categories

Resources