Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.uima.examples.as; import java.net.URI; import java.util.HashSet; import java.util.Set; import javax.jms.Connection; import javax.jms.MessageConsumer; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import javax.jms.TemporaryQueue; import javax.jms.TextMessage; import javax.management.MBeanServerConnection; import javax.management.MBeanServerInvocationHandler; import javax.management.ObjectName; import javax.management.QueryExp; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.broker.jmx.QueueViewMBean; import org.apache.activemq.command.ActiveMQTextMessage; import org.apache.uima.aae.message.AsynchAEMessage; import org.apache.uima.aae.message.UIMAMessage; import org.springframework.jmx.JmxException; /** * This is a stand-alone utility class with a "main". * It is used to retrieve the meta information for a UIMA service, which is attached to a JMS Broker * * It is passed the broker URI and the service name, and optionally, a -verbose flag. */ public class GetMetaRequest { private static MBeanServerConnection brokerMBeanServer = null; private static String brokerName; private static JMXConnector jmxc = null; private static boolean initialized = false; private static enum QueueState { exists, existsnot, jmxnot }; private static String jmxPort; /** * retrieve meta information for a UIMA-AS Service attached to a broker * It uses the port 1099 as the JMX port on the broker, unless overridden * by defining the system property activemq.broker.jmx.port with a value of another port number * It uses the default JMX ActiveMQ Domain "org.apache.activemq", unless overridden * by defining the system property activemq.broker.jmx.domain with a value of the domain to use * This normally never needs to be done unless multiple brokers are run on the same node * as is sometimes done for unit tests. * @param args - brokerUri serviceName [-verbose] */ public static void main(String[] args) { if (args.length < 2) { System.err.println("Need arguments: brokerURI serviceName [-verbose]"); System.exit(1); } String brokerURI = args[0]; String queueName = args[1]; boolean printReply = false; if (args.length > 2) { if (args[2].equalsIgnoreCase("-verbose")) { printReply = true; } else { System.err.println("Unknown argument: " + args[2]); System.exit(1); } } final Connection connection; Session producerSession = null; Queue producerQueue = null; MessageProducer producer; MessageConsumer consumer; Session consumerSession = null; TemporaryQueue consumerDestination = null; long startTime = 0; // Check if JMX server port number was specified jmxPort = System.getProperty("activemq.broker.jmx.port"); if (jmxPort == null || jmxPort.trim().length() == 0) { jmxPort = "1099"; // default } try { // First create connection to a broker ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerURI); connection = factory.createConnection(); connection.start(); Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { public void run() { try { if (connection != null) { connection.close(); } if (jmxc != null) { jmxc.close(); } } catch (Exception ex) { } } })); URI target = new URI(brokerURI); String brokerHost = target.getHost(); attachToRemoteBrokerJMXServer(brokerURI); if (isQueueAvailable(queueName) == QueueState.exists) { System.out.println("Queue " + queueName + " found on " + brokerURI); System.out.println("Sending getMeta..."); } else if (isQueueAvailable(queueName) == QueueState.existsnot) { System.err.println("Queue " + queueName + " does not exist on " + brokerURI); System.exit(1); } else { System.out.println("Cannot see queues on JMX port " + brokerHost + ":" + jmxPort); System.out.println("Sending getMeta anyway..."); } producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); producerQueue = producerSession.createQueue(queueName); producer = producerSession.createProducer(producerQueue); consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); consumerDestination = consumerSession.createTemporaryQueue(); // ----------------------------------------------------------------------------- // Create message consumer. The consumer uses a selector to filter out messages other // then GetMeta replies. Currently UIMA AS service returns two messages for each request: // ServiceInfo message and GetMeta message. The ServiceInfo message is returned by the // service immediately upon receiving a message from a client. This serves dual purpose, // 1) to make sure the client reply destination exists // 2) informs the client which service is processing its request // ----------------------------------------------------------------------------- consumer = consumerSession.createConsumer(consumerDestination, "Command=2001"); TextMessage msg = producerSession.createTextMessage(); msg.setStringProperty(AsynchAEMessage.MessageFrom, consumerDestination.getQueueName()); msg.setStringProperty(UIMAMessage.ServerURI, brokerURI); msg.setIntProperty(AsynchAEMessage.MessageType, AsynchAEMessage.Request); msg.setIntProperty(AsynchAEMessage.Command, AsynchAEMessage.GetMeta); msg.setJMSReplyTo(consumerDestination); msg.setText(""); producer.send(msg); startTime = System.nanoTime(); System.out.println("Sent getMeta request to " + queueName + " at " + brokerURI); System.out.println("Waiting for getMeta reply..."); ActiveMQTextMessage reply = (ActiveMQTextMessage) consumer.receive(); long waitTime = (System.nanoTime() - startTime) / 1000000; System.out.println( "Reply from " + reply.getStringProperty("ServerIP") + " received in " + waitTime + " ms"); if (printReply) { System.out.println("Reply MessageText: " + reply.getText()); } } catch (Exception e) { System.err.println(e.toString()); } System.exit(0); } /** * Connects to this service Broker's JMX Server. If unable to connect, this method * fails silently. The method uses default JMX Port number 1099 to create a connection * to the Broker's JMX MBean server. The default can be overridden via System * property 'activemq.broker.jmx.port'. If connection cannot be established the * method silently fails. * */ private static void attachToRemoteBrokerJMXServer(String brokerUri) throws Exception { // Fetch AMQ jmx domain from system properties. This property is not required // and the default AMQ jmx is used. The only exception is when the service is // deployed in a jvm with multiple brokers deployed as it is the case with jUnit // tests. In such a case, each broker will register self with JMX using a different // domain. String jmxAMQDomain = System.getProperty("activemq.broker.jmx.domain"); if (jmxAMQDomain == null) { jmxAMQDomain = "org.apache.activemq"; // default } String brokerHostname = ""; URI target = new URI(brokerUri); brokerHostname = target.getHost(); initialize(jmxAMQDomain, brokerHostname, jmxPort); } /** * Creates a connection to an MBean Server identified by * <code>remoteJMXServerHostName and remoteJMXServerPort</code> * * @param remoteJMXServerHostName * - MBeanServer host name * @param remoteJMXServerPort * - MBeanServer port * @return - none * * @throws Exception */ private static void initialize(String jmxDomain, String remoteJMXServerHostname, String remoteJMXServerPort) throws Exception { // Construct connect string to the JMX MBeanServer String remoteJmxUrl = "service:jmx:rmi:///jndi/rmi://" + remoteJMXServerHostname + ":" + remoteJMXServerPort + "/jmxrmi"; try { JMXServiceURL url = new JMXServiceURL(remoteJmxUrl); jmxc = JMXConnectorFactory.connect(url, null); brokerMBeanServer = jmxc.getMBeanServerConnection(); // Its possible that the above code succeeds even though the broker runs // with no JMX Connector. At least on windows the above does not throw an // exception as expected. It appears that the broker registers self JVMs MBeanServer // but it does *not* register any Connections, nor Queues. The code below // checks if the MBean server we are connected to has any QueueMBeans registered. // A broker with jmx connector should have queue mbeans registered and thus // the code below should always succeed. Conversely, a broker with no jmx connector // reports no queue mbeans. // Query broker MBeanServer for QueueMBeans Set queueSet = brokerMBeanServer.queryNames(new ObjectName(jmxDomain + ":*,Type=Queue"), (QueryExp) null); if (queueSet.isEmpty()) { // No QueueMBeans, meaning no JMX support throw new JmxException("ActiveMQ Broker Not Configured With JMX Support"); } } catch (Exception e) { return; } // Query JMX Server for Broker MBean. We need the broker's name from an MBean to construct // queue query string. for (Object nameObject : brokerMBeanServer.queryNames(new ObjectName(jmxDomain + ":*,Type=Broker"), (QueryExp) null)) { ObjectName brokerObjectName = (ObjectName) nameObject; if (brokerObjectName.getCanonicalName().endsWith("Type=Broker")) { // Extract just the name from the canonical name brokerName = brokerObjectName.getCanonicalName().substring(0, brokerObjectName.getCanonicalName().indexOf(",")); initialized = true; break; // got the broker name } } } private static boolean isServerAvailable() { try { brokerMBeanServer.getMBeanCount(); return true; } catch (Exception e) { return false; } } private static QueueState isQueueAvailable(String queueName) throws Exception { if (!initialized) { return QueueState.jmxnot; } ObjectName uimaServiceQueuePattern = new ObjectName(brokerName + ",Type=Queue,Destination=" + queueName); // Tests if queue exists. If a client terminates, the reply queue will be removed and we // expect null from getQueueMBean() if (isServerAvailable() && getQueueMBean(queueName, uimaServiceQueuePattern) == null) { return QueueState.existsnot; } return QueueState.exists; } private static QueueViewMBean getQueueMBean(String key, ObjectName matchPattern) throws Exception { // Fetch queue names matching a given pattern. Set<ObjectName> queues = new HashSet<ObjectName>(brokerMBeanServer.queryNames(matchPattern, null)); for (ObjectName name : queues) { // Create and return a proxy to the queue's MBean return (QueueViewMBean) MBeanServerInvocationHandler.newProxyInstance(brokerMBeanServer, name, QueueViewMBean.class, true); } return null; } }