/* * This file is part of FFMQ. * * FFMQ is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * FFMQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with FFMQ; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package net.timewalker.ffmq4; import java.io.PrintStream; import java.util.Hashtable; import java.util.Iterator; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.DeliveryMode; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import net.timewalker.ffmq4.transport.PacketTransportType; import net.timewalker.ffmq4.utils.Settings; import net.timewalker.ffmq4.utils.StringTools; /** * FFMQAdminClient */ public final class FFMQAdminClient implements Runnable { private Settings globalSettings; private Settings paramSettings; // Runtime private Connection connection; private Session session; // Output private PrintStream out; private PrintStream err; /** * Constructor */ public FFMQAdminClient( Settings globalSettings , Settings paramSettings , PrintStream out , PrintStream err ) { this.globalSettings = globalSettings; this.paramSettings = paramSettings; this.out = out; this.err = err; } private void logError( JMSException e ) { if (e.getErrorCode() != null) err.println("error={"+e.getErrorCode()+"} "+e.getMessage()); else err.println(e.getMessage()); if (e.getLinkedException() != null) { err.println("Linked exception was : "); e.getLinkedException().printStackTrace(err); } } /* (non-Javadoc) * @see java.lang.Runnable#run() */ @Override public void run() { String command = globalSettings.getStringProperty(FFMQAdminClientSettings.ADM_COMMAND, null); if (StringTools.isEmpty(command)) { err.println("No command specified"); return; } try { openSession(); processCommand(command); } catch (JMSException e) { logError(e); } finally { closeSession(); } } private void openSession() throws JMSException { String serverHost = globalSettings.getStringProperty(FFMQAdminClientSettings.SERVER_TCP_HOST, FFMQConstants.DEFAULT_SERVER_HOST); int serverPort = globalSettings.getIntProperty(FFMQAdminClientSettings.SERVER_TCP_PORT, FFMQConstants.DEFAULT_SERVER_PORT); String userName = globalSettings.getStringProperty(FFMQAdminClientSettings.ADMIN_USER_NAME,null); String userPassword = globalSettings.getStringProperty(FFMQAdminClientSettings.ADMIN_USER_PASSWORD,null); out.println("Opening connection to server "+serverHost+":"+serverPort+" for user "+userName); this.connection = getConnectionFactory(serverHost,serverPort).createConnection(userName, userPassword); this.connection.start(); this.session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); } private void closeSession() { if (session != null) { try { session.close(); } catch (JMSException e) { logError(e); } } if (connection != null) { try { connection.close(); } catch (JMSException e) { logError(e); } } } private Context getJNDIContext( String serverHost , int serverPort ) throws NamingException { Hashtable<String,Object> env = new Hashtable<>(); env.put(Context.INITIAL_CONTEXT_FACTORY, FFMQConstants.JNDI_CONTEXT_FACTORY); env.put(Context.PROVIDER_URL, PacketTransportType.TCP+"://"+serverHost+":"+serverPort); return new InitialContext(env); } private ConnectionFactory getConnectionFactory( String serverHost , int serverPort ) throws JMSException { try { Context context = getJNDIContext(serverHost,serverPort); return (ConnectionFactory)context.lookup(FFMQConstants.JNDI_CONNECTION_FACTORY_NAME); } catch (NamingException e) { throw new FFMQException("Cannot lookup connection factory in JNDI context","JNDI_ERROR",e); } } private void processCommand( String command ) throws JMSException { // Dispatch if (command.equals(FFMQAdminConstants.ADM_COMMAND_CREATE_QUEUE)) processCreateQueue(); else if (command.equals(FFMQAdminConstants.ADM_COMMAND_CREATE_TOPIC)) processCreateTopic(); else if (command.equals(FFMQAdminConstants.ADM_COMMAND_DELETE_QUEUE)) processDeleteQueue(); else if (command.equals(FFMQAdminConstants.ADM_COMMAND_DELETE_TOPIC)) processDeleteTopic(); else if (command.equals(FFMQAdminConstants.ADM_COMMAND_PURGE_QUEUE)) processPurgeQueue(); else if (command.equals(FFMQAdminConstants.ADM_COMMAND_SHUTDOWN)) processShutdown(); else throw new FFMQException("Unknown command : " + command,"INVALID_ADMIN_COMMAND"); } private void remoteExec( Message msg , boolean expectReply ) throws JMSException { // Send the request event Queue requestQueue = session.createQueue(FFMQConstants.ADM_REQUEST_QUEUE); MessageProducer producer = session.createProducer(requestQueue); producer.send(msg,DeliveryMode.NON_PERSISTENT,Message.DEFAULT_PRIORITY,Message.DEFAULT_TIME_TO_LIVE); String correlID = msg.getJMSMessageID(); producer.close(); if (expectReply) { Queue replyQueue = session.createQueue(FFMQConstants.ADM_REPLY_QUEUE); MessageConsumer consumer = session.createConsumer(replyQueue,"JMSCorrelationID='"+correlID+"'"); int requestTimeout = globalSettings.getIntProperty(FFMQAdminClientSettings.ADMIN_REQUEST_TIMEOUT, 30); Message responseMsg = consumer.receive(requestTimeout*1000L); consumer.close(); if (responseMsg == null) throw new FFMQException("Timeout waiting for server response after "+requestTimeout+" second(s)","NETWORK_ERROR"); String errorMsg = responseMsg.getStringProperty(FFMQAdminConstants.ADM_HEADER_ERRMSG); if (StringTools.isNotEmpty(errorMsg)) throw new FFMQException("Command failed : "+errorMsg,"NETWORK_ERROR"); out.println("Command sucessfully completed."); } else out.println("Command sucessfully sent."); } private Message createCommandMessage( String commandName ) throws JMSException { Message msg = session.createMessage(); msg.setStringProperty(FFMQAdminConstants.ADM_HEADER_COMMAND, commandName); Iterator<Object> keys = paramSettings.keySet().iterator(); while (keys.hasNext()) { String paramName = (String)keys.next(); String paramValue = paramSettings.getStringProperty(paramName); msg.setStringProperty(paramName,paramValue); } return msg; } private void processCreateQueue() throws JMSException { String destinationName = paramSettings.getStringProperty("name", null); if (StringTools.isEmpty(destinationName)) throw new FFMQException("Destination name not specified","INVALID_DESTINATION_NAME"); out.println("Creating queue "+destinationName); // Create message Message msg = createCommandMessage(FFMQAdminConstants.ADM_COMMAND_CREATE_QUEUE); // Send message remoteExec(msg,true); } private void processCreateTopic() throws JMSException { String destinationName = paramSettings.getStringProperty("name", null); if (StringTools.isEmpty(destinationName)) throw new FFMQException("Destination name not specified","INVALID_DESTINATION_NAME"); out.println("Creating topic "+destinationName); // Create message Message msg = createCommandMessage(FFMQAdminConstants.ADM_COMMAND_CREATE_TOPIC); // Send message remoteExec(msg,true); } private void processDeleteQueue() throws JMSException { String destinationName = paramSettings.getStringProperty("name", null); if (StringTools.isEmpty(destinationName)) throw new FFMQException("Destination name not specified","INVALID_DESTINATION_NAME"); out.println("Deleting queue "+destinationName); // Create message Message msg = createCommandMessage(FFMQAdminConstants.ADM_COMMAND_DELETE_QUEUE); // Send message remoteExec(msg,true); } private void processDeleteTopic() throws JMSException { String destinationName = paramSettings.getStringProperty("name", null); if (StringTools.isEmpty(destinationName)) throw new FFMQException("Destination name not specified","INVALID_DESTINATION_NAME"); out.println("Deleting topic "+destinationName); // Create message Message msg = createCommandMessage(FFMQAdminConstants.ADM_COMMAND_DELETE_TOPIC); // Send message remoteExec(msg,true); } private void processPurgeQueue() throws JMSException { String destinationName = paramSettings.getStringProperty("name", null); if (StringTools.isEmpty(destinationName)) throw new FFMQException("Destination name not specified","INVALID_DESTINATION_NAME"); out.println("Purging queue "+destinationName); // Create message Message msg = createCommandMessage(FFMQAdminConstants.ADM_COMMAND_PURGE_QUEUE); // Send message remoteExec(msg,true); } private void processShutdown() throws JMSException { out.println("Asking the server to shutdown"); // Create message Message msg = createCommandMessage(FFMQAdminConstants.ADM_COMMAND_SHUTDOWN); // Send message but do NOT wait for an answer remoteExec(msg,false); } }