QMan.java
001 /*
002  *
003  * Licensed to the Apache Software Foundation (ASF) under one
004  * or more contributor license agreements.  See the NOTICE file
005  * distributed with this work for additional information
006  * regarding copyright ownership.  The ASF licenses this file
007  * to you under the Apache License, Version 2.0 (the
008  * "License"); you may not use this file except in compliance
009  * with the License.  You may obtain a copy of the License at
010  *
011  *   http://www.apache.org/licenses/LICENSE-2.0
012  *
013  * Unless required by applicable law or agreed to in writing,
014  * software distributed under the License is distributed on an
015  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016  * KIND, either express or implied.  See the License for the
017  * specific language governing permissions and limitations
018  * under the License.
019  *
020  */
021 package org.apache.qpid.management.domain.services;
022 
023 import java.io.BufferedReader;
024 import java.io.IOException;
025 import java.io.InputStreamReader;
026 import java.util.ArrayList;
027 import java.util.List;
028 import java.util.UUID;
029 
030 import javax.management.Attribute;
031 import javax.management.AttributeList;
032 import javax.management.DynamicMBean;
033 import javax.management.MBeanException;
034 import javax.management.MBeanInfo;
035 import javax.management.MBeanOperationInfo;
036 import javax.management.MBeanParameterInfo;
037 import javax.management.Notification;
038 import javax.management.NotificationBroadcasterSupport;
039 import javax.management.NotificationListener;
040 import javax.management.ReflectionException;
041 
042 import org.apache.log4j.xml.DOMConfigurator;
043 import org.apache.qpid.management.Messages;
044 import org.apache.qpid.management.Names;
045 import org.apache.qpid.management.configuration.BrokerAlreadyConnectedException;
046 import org.apache.qpid.management.configuration.BrokerConnectionData;
047 import org.apache.qpid.management.configuration.BrokerConnectionException;
048 import org.apache.qpid.management.configuration.Configurator;
049 import org.apache.qpid.management.domain.model.JmxService;
050 import org.apache.qpid.transport.util.Logger;
051 
052 /**
053  * Main entry point for starting Q-Man application.
054  */
055 public class QMan extends NotificationBroadcasterSupport implements DynamicMBean, NotificationListener
056 {
057     private final static Logger LOGGER = Logger.get(QMan.class);
058     private final List<ManagementClient> managementClients = new ArrayList<ManagementClient>();
059     
060     private Configurator _configurator = new Configurator();
061     
062     /**
063      * Starts QMan.
064      @throws StartupFailureException when it's not possible to proceed with startup.
065      */
066     public void start() throws StartupFailureException
067     {
068         LOGGER.info(Messages.QMAN_000001_STARTING_QMAN);
069         LOGGER.info(Messages.QMAN_000002_READING_CONFIGURATION);
070 
071         try
072         {
073            registerQManService();
074            
075             _configurator.configure();            
076             
077             LOGGER.info(Messages.QMAN_000019_QMAN_STARTED);
078        catch(Exception exception) {
079             LOGGER.error(exception,Messages.QMAN_100018_UNABLE_TO_STARTUP_CORRECTLY );
080             throw new StartupFailureException(exception);
081         
082     }
083     
084   /**
085    * Connects Q-Man with a broker defined by the given parameter.
086    
087    @param host the hostname where the broker is running.
088    @param port the port where the broker is running.
089    @param username the username for connecting with the broker.
090    @param password the password for connecting with the broker.
091    @param virtualHost the virtual host.
092    @param initialPoolCapacity the number of the connection that must  be immediately opened.
093    @param maxPoolCapacity the maximum number of opened connection.
094    @param maxWaitTimeout the maximum amount of time that a client will wait for obtaining a connection.
095    @throws MBeanException when it's not possible to connect with the broker.
096    */
097   public void addBroker(
098       String host, 
099       int port, 
100       String username,
101       String password, 
102       String virtualHost, 
103       int initialPoolCapacity,
104       int maxPoolCapacity, 
105       long maxWaitTimeoutthrows BrokerAlreadyConnectedException, BrokerConnectionException
106   {
107     Configurator configurator = new Configurator();
108     try {
109       UUID brokerId = UUID.randomUUID();
110       BrokerConnectionData data = configurator.createAndReturnBrokerConnectionData(
111           brokerId,
112           host,
113           port, 
114           username,
115           password, 
116           virtualHost, 
117           initialPoolCapacity,
118           maxPoolCapacity, 
119           maxWaitTimeout);
120       createManagementClient(brokerId, data);
121     catch (BrokerAlreadyConnectedException exception
122     {
123       LOGGER.warn(Messages.QMAN_300003_BROKER_ALREADY_CONNECTED, exception.getBrokerConnectionData());
124       throw exception;
125     }
126   }
127   
128     /**
129      * Stop Qman
130      */
131     public void stop() 
132     {
133         LOGGER.info(Messages.QMAN_000020_SHUTTING_DOWN_QMAN);
134         try 
135         {
136             for (ManagementClient client : managementClients)
137             {   
138                 client.shutdown();  
139             }
140         catch(Exception exception)
141         {
142         }
143         LOGGER.info(Messages.QMAN_000021_SHUT_DOWN);                      
144     }
145     
146     /**
147      * Injects the configurator on this QMan instance.
148      * That configutator later will be responsible to manage the configuration.
149      
150      @param configurator the configurator to be injected.
151      */
152     public void setConfigurator(Configurator configurator){
153       this._configurator = configurator;
154     }
155     
156     /**
157      * Main method used for starting Q-Man.
158      
159      @param args the command line arguments.
160      */
161     public static void main (String[] args)
162     {  
163       if (args.length == 1
164       {
165         String logFileName = args[0];
166         DOMConfigurator.configureAndWatch(logFileName,5000);
167       }
168       
169     final QMan qman = new QMan();
170     
171     Thread hook = new Thread()
172         {
173             @Override
174             public void run ()
175             {
176               qman.stop();
177             }
178         };      
179     
180     Runtime.getRuntime().addShutdownHook(hook);
181     try 
182     {
183       qman.start();
184         
185       System.out.println("Type \"q\" to quit.");
186             BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
187             while !"q".equals(reader.readLine()) )
188             {
189               
190             }
191             Runtime.getRuntime().removeShutdownHook(hook);
192             qman.stop();
193       System.exit(-1);
194     catch (StartupFailureException exception
195     {
196       qman.stop();
197       System.exit(-1);
198     catch (IOException exception)
199     {
200       System.exit(-1);          
201     }
202     }
203     
204     /**
205      * Not implemented for this MBean.
206      */
207   public Object getAttribute(String attribute)
208   {
209     return null;
210   }
211 
212     /**
213      * Not implemented for this MBean.
214      */
215   public AttributeList getAttributes(String[] attributes
216   {
217     return null;
218   }
219 
220     /**
221      * Returns the metadata for this MBean
222      
223      @return the metadata for this MBean
224      */
225   public MBeanInfo getMBeanInfo() 
226   {
227     MBeanParameterInfo parameters [] new MBeanParameterInfo[8];
228     
229     parameters[0new MBeanParameterInfo(
230         "host",
231         String.class.getName(),
232         "The IP address or DNS name that Qpid Broker uses to listen for incoming connections.");
233     parameters[1new MBeanParameterInfo(
234         "port",
235         int.class.getName(),
236         "The port number that Qpid Broker uses to listen for incoming connections.");
237     parameters[2new MBeanParameterInfo(
238         "username",
239         String.class.getName(),
240         "The Qpid account name used in the physical connection.");
241     parameters[3new MBeanParameterInfo(
242         "password",
243         String.class.getName(),
244         "The Qpid account password used in the physical connection.");
245     parameters[4]new MBeanParameterInfo(
246         "virtualHost",
247         String.class.getName(),
248         "The virtualHost name.");
249     parameters[5]new MBeanParameterInfo(
250         "initialPoolCapacity",
251         int.class.getName(),
252         "The number of physical connections (between 0 and a positive 32-bit integer) to create when creating the (Qpid) connection pool.");
253     parameters[6]new MBeanParameterInfo(
254         "maxPoolCapacity",
255         int.class.getName(),
256         "The maximum number of physical database connections (between 0 and a positive 32-bit integer) that the (Qpid) connection pool can contain. ");
257     parameters[7]new MBeanParameterInfo(
258         "maxWaitTimeout",
259         long.class.getName(),
260         "The maximum amount of time to wait for an idle connection.A value of -1 indicates an illimted amount of time (i.e. forever)");
261         
262     MBeanOperationInfo operation = new MBeanOperationInfo(
263         "addBroker",
264         "Connects QMan with a broker.",
265         parameters,
266         void.class.getName(),
267         MBeanOperationInfo.ACTION);
268     
269     MBeanInfo mbean = new MBeanInfo(
270         QMan.class.getName(),
271         "QMan Management & Administration interface.",
272         null,
273         null,
274         new MBeanOperationInfo[]{operation},
275         null);
276     
277     return mbean;
278   }
279 
280   /**
281    * Invokes an operation on QMan (MBean).
282    
283    @param actionName the operation name.
284    @param params the operation parameters.
285    @param signature the operation signature.
286    @return the result of the invocation (if the operation is not void);
287    @exception MBeanException  Wraps a <CODE>java.lang.Exception</CODE> thrown by the MBean's invoked method.
288      @exception ReflectionException  Wraps a <CODE>java.lang.Exception</CODE> thrown while trying to invoke the method
289    */
290   public Object invoke(String actionName, Object[] params, String[] signaturethrows MBeanException, ReflectionException 
291   {
292     if (Names.ADD_BROKER_OPERATION_NAME.equals(actionName))
293     {
294       try 
295       {
296         addBroker(
297             (String)params[0]
298             (Integer)params[1]
299             (String)params[2]
300             (String)params[3]
301             (String)params[4]
302             (Integer)params[5]
303             (Integer)params[6]
304             (Long)params[7])
305       catch(Exception exception)
306       {
307         throw new MBeanException(exception);
308       }
309     else 
310     {
311       throw new ReflectionException(new NoSuchMethodException(actionName));
312     }
313     return null;
314   }
315 
316     /**
317      * Not implemented for this MBean.
318      */
319   public void setAttribute(Attribute attribute
320   {    
321   }
322 
323     /**
324      * Not implemented for this MBean.
325      */
326   public AttributeList setAttributes(AttributeList attributes
327   {
328     return null;
329   }    
330 
331   /**
332    * Simply dispatches the incoming notification to registered listeners.
333    
334    @param notification the incoming notification.
335    @param handback the context associated to this notification.
336    */
337   public void handleNotification(Notification notification, Object handback
338   {
339     sendNotification(notification);
340   }  
341   
342     /**
343      * Registers QMan as an MBean on MBeanServer.
344      
345      @throws MBeanException when it's not possible to proceeed with registration.
346      */
347     private void registerQManService() throws MBeanException 
348     {      
349       JmxService service = new JmxService()
350       service.registerQManService(this);
351       
352       LOGGER.info(Messages.QMAN_000023_QMAN_REGISTERED_AS_MBEAN);
353   }
354     
355   /**
356      * Creates a management client using the given data.
357      
358      @param brokerId the broker identifier.
359      @param data the broker connection data.
360      */
361     public void createManagementClient(UUID brokerId, BrokerConnectionData data)
362     {
363         try 
364         {
365             ManagementClient client = new ManagementClient(brokerId,data);
366             client.estabilishFirstConnectionWithBroker();
367             managementClients.add(client);
368             
369             LOGGER.info(Messages.QMAN_000004_MANAGEMENT_CLIENT_CONNECTED,brokerId);
370         catch(StartupFailureException exception) {
371             LOGGER.error(exception, Messages.QMAN_100017_UNABLE_TO_CONNECT,brokerId,data);
372         }
373     }    
374     
375     /**
376      * Returns the list of management clients currently handled by QMan.
377      
378      @return the list of management clients currently handled by QMan.
379      */
380     public List<ManagementClient> getManagementClients()
381     {
382       return managementClients;
383     }
384 }