001    /*
002     * Copyright 2009 Red Hat, Inc.
003     * Red Hat licenses this file to you under the Apache License, version
004     * 2.0 (the "License"); you may not use this file except in compliance
005     * with the License.  You may obtain a copy of the License at
006     *    http://www.apache.org/licenses/LICENSE-2.0
007     * Unless required by applicable law or agreed to in writing, software
008     * distributed under the License is distributed on an "AS IS" BASIS,
009     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
010     * implied.  See the License for the specific language governing
011     * permissions and limitations under the License.
012     */
013    
014    package org.hornetq.api.core.management;
015    
016    import java.util.Collections;
017    import java.util.HashMap;
018    import java.util.Iterator;
019    import java.util.Map;
020    
021    import org.hornetq.api.core.Message;
022    import org.hornetq.api.core.SimpleString;
023    import org.hornetq.core.logging.Logger;
024    import org.hornetq.utils.json.JSONArray;
025    import org.hornetq.utils.json.JSONObject;
026    
027    /**
028     * Helper class to use HornetQ Core messages to manage server resources.
029     *
030     * @author <a href="mailto:jmesnil@redhat.com">Jeff Mesnil</a>
031     * @author <a href="mailto:tim.fox@jboss.com">Tim Fox</a>
032     *
033     * @version <tt>$Revision$</tt>
034     */
035    public class ManagementHelper
036    {
037       // Constants -----------------------------------------------------
038    
039       private static final Logger log = Logger.getLogger(ManagementHelper.class);
040    
041       public static final SimpleString HDR_RESOURCE_NAME = new SimpleString("_HQ_ResourceName");
042    
043       public static final SimpleString HDR_ATTRIBUTE = new SimpleString("_HQ_Attribute");
044    
045       public static final SimpleString HDR_OPERATION_NAME = new SimpleString("_HQ_OperationName");
046    
047       public static final SimpleString HDR_OPERATION_SUCCEEDED = new SimpleString("_HQ_OperationSucceeded");
048    
049       public static final SimpleString HDR_NOTIFICATION_TYPE = new SimpleString("_HQ_NotifType");
050    
051       public static final SimpleString HDR_NOTIFICATION_TIMESTAMP = new SimpleString("_HQ_NotifTimestamp");
052    
053       public static final SimpleString HDR_ROUTING_NAME = new SimpleString("_HQ_RoutingName");
054    
055       public static final SimpleString HDR_CLUSTER_NAME = new SimpleString("_HQ_ClusterName");
056    
057       public static final SimpleString HDR_ADDRESS = new SimpleString("_HQ_Address");
058    
059       public static final SimpleString HDR_BINDING_ID = new SimpleString("_HQ_Binding_ID");
060    
061       public static final SimpleString HDR_BINDING_TYPE = new SimpleString("_HQ_Binding_Type");
062    
063       public static final SimpleString HDR_FILTERSTRING = new SimpleString("_HQ_FilterString");
064    
065       public static final SimpleString HDR_DISTANCE = new SimpleString("_HQ_Distance");
066    
067       public static final SimpleString HDR_CONSUMER_COUNT = new SimpleString("_HQ_ConsumerCount");
068    
069       public static final SimpleString HDR_USER = new SimpleString("_HQ_User");
070    
071       public static final SimpleString HDR_CHECK_TYPE = new SimpleString("_HQ_CheckType");
072    
073       public static final SimpleString HDR_PROPOSAL_GROUP_ID = new SimpleString("_JBM_ProposalGroupId");
074    
075       public static final SimpleString HDR_PROPOSAL_VALUE = new SimpleString("_JBM_ProposalValue");
076    
077       public static final SimpleString HDR_PROPOSAL_ALT_VALUE = new SimpleString("_JBM_ProposalAltValue");
078    
079       // Attributes ----------------------------------------------------
080    
081       // Static --------------------------------------------------------
082    
083       /**
084        * Stores a resource attribute in a message to retrieve the value from the server resource.
085        *
086        * @param message message
087        * @param resourceName the name of the resource
088        * @param attribute the name of the attribute
089        *
090        * @see ResourceNames
091        */
092       public static void putAttribute(final Message message, final String resourceName, final String attribute)
093       {
094          message.putStringProperty(ManagementHelper.HDR_RESOURCE_NAME, new SimpleString(resourceName));
095          message.putStringProperty(ManagementHelper.HDR_ATTRIBUTE, new SimpleString(attribute));
096       }
097    
098       /**
099        * Stores a operation invocation in a message to invoke the corresponding operation the value from the server resource.
100        *
101        * @param message  message
102        * @param resourceName the name of the resource
103        * @param operationName the name of the operation to invoke on the resource
104        *
105        * @see ResourceNames
106        */
107       public static void putOperationInvocation(final Message message,
108                                                 final String resourceName,
109                                                 final String operationName) throws Exception
110       {
111          ManagementHelper.putOperationInvocation(message, resourceName, operationName, (Object[])null);
112       }
113    
114       /**
115        * Stores a operation invocation in a  message to invoke the corresponding operation the value from the server resource.
116        *
117        * @param message  message
118        * @param resourceName the name of the server resource
119        * @param operationName the name of the operation to invoke on the server resource
120        * @param parameters the parameters to use to invoke the server resource
121        *
122        * @see ResourceNames
123        */
124       public static void putOperationInvocation(final Message message,
125                                                 final String resourceName,
126                                                 final String operationName,
127                                                 final Object... parameters) throws Exception
128       {
129          // store the name of the operation in the headers
130          message.putStringProperty(ManagementHelper.HDR_RESOURCE_NAME, new SimpleString(resourceName));
131          message.putStringProperty(ManagementHelper.HDR_OPERATION_NAME, new SimpleString(operationName));
132    
133          // and the params go in the body, since might be too large for header
134    
135          String paramString;
136    
137          if (parameters != null)
138          {
139             JSONArray jsonArray = ManagementHelper.toJSONArray(parameters);
140    
141             paramString = jsonArray.toString();
142          }
143          else
144          {
145             paramString = null;
146          }
147    
148          message.getBodyBuffer().writeNullableSimpleString(SimpleString.toSimpleString(paramString));
149       }
150    
151       private static JSONArray toJSONArray(final Object[] array) throws Exception
152       {
153          JSONArray jsonArray = new JSONArray();
154    
155          for (Object parameter : array)
156          {
157             if (parameter instanceof Map)
158             {
159                Map<String, Object> map = (Map<String, Object>)parameter;
160    
161                JSONObject jsonObject = new JSONObject();
162    
163                for (Map.Entry<String, Object> entry : map.entrySet())
164                {
165                   String key = entry.getKey();
166    
167                   Object val = entry.getValue();
168    
169                   if (val != null)
170                   {
171                      if (val.getClass().isArray())
172                      {
173                         val = ManagementHelper.toJSONArray((Object[])val);
174                      }
175                      else
176                      {
177                         ManagementHelper.checkType(val);
178                      }
179                   }
180    
181                   jsonObject.put(key, val);
182                }
183    
184                jsonArray.put(jsonObject);
185             }
186             else
187             {
188                if (parameter != null)
189                {
190                   Class clz = parameter.getClass();
191    
192                   if (clz.isArray())
193                   {
194                      Object[] innerArray = (Object[])parameter;
195    
196                      jsonArray.put(ManagementHelper.toJSONArray(innerArray));
197                   }
198                   else
199                   {
200                      ManagementHelper.checkType(parameter);
201    
202                      jsonArray.put(parameter);
203                   }
204                }
205                else
206                {
207                   jsonArray.put((Object)null);
208                }
209             }
210          }
211    
212          return jsonArray;
213       }
214    
215       private static Object[] fromJSONArray(final JSONArray jsonArray) throws Exception
216       {
217          Object[] array = new Object[jsonArray.length()];
218    
219          for (int i = 0; i < jsonArray.length(); i++)
220          {
221             Object val = jsonArray.get(i);
222    
223             if (val instanceof JSONArray)
224             {
225                Object[] inner = ManagementHelper.fromJSONArray((JSONArray)val);
226    
227                array[i] = inner;
228             }
229             else if (val instanceof JSONObject)
230             {
231                JSONObject jsonObject = (JSONObject)val;
232    
233                Map<String, Object> map = new HashMap<String, Object>();
234    
235                Iterator<String> iter = jsonObject.keys();
236    
237                while (iter.hasNext())
238                {
239                   String key = iter.next();
240    
241                   Object innerVal = jsonObject.get(key);
242    
243                   if (innerVal instanceof JSONArray)
244                   {
245                      innerVal = ManagementHelper.fromJSONArray(((JSONArray)innerVal));
246                   }
247                   else if (innerVal instanceof JSONObject)
248                   {
249                      Map<String, Object> innerMap = new HashMap<String, Object>();
250                      JSONObject o = (JSONObject)innerVal;
251                      Iterator it = o.keys();
252                      while (it.hasNext())
253                      {
254                         String k = (String)it.next();
255                         innerMap.put(k, o.get(k));
256                      }
257                      innerVal = innerMap;
258                   }
259                   else if (innerVal instanceof Integer)
260                   {
261                      innerVal = ((Integer)innerVal).longValue();
262                   }
263    
264                   map.put(key, innerVal);
265                }
266    
267                array[i] = map;
268             }
269             else
270             {
271                if (val == JSONObject.NULL)
272                {
273                   array[i] = null;
274                }
275                else
276                {
277                   array[i] = val;
278                }
279             }
280          }
281    
282          return array;
283       }
284    
285       private static void checkType(final Object param)
286       {
287          if (param instanceof Integer == false && param instanceof Long == false &&
288              param instanceof Double == false &&
289              param instanceof String == false &&
290              param instanceof Boolean == false &&
291              param instanceof Map == false &&
292              param instanceof Byte == false &&
293              param instanceof Short == false)
294          {
295             throw new IllegalArgumentException("Params for management operations must be of the following type: " + "int long double String boolean Map or array thereof " +
296                                                " but found " +
297                                                param.getClass().getName());
298          }
299       }
300    
301       /**
302        * Used by HornetQ management service.
303        */
304       public static Object[] retrieveOperationParameters(final Message message) throws Exception
305       {
306          SimpleString sstring = message.getBodyBuffer().readNullableSimpleString();
307          String jsonString = (sstring == null) ? null : sstring.toString();
308    
309          if (jsonString != null)
310          {
311             JSONArray jsonArray = new JSONArray(jsonString);
312    
313             return ManagementHelper.fromJSONArray(jsonArray);
314          }
315          else
316          {
317             return null;
318          }
319       }
320    
321       /**
322        * Returns whether the JMS message corresponds to the result of a management operation invocation.
323        */
324       public static boolean isOperationResult(final Message message)
325       {
326          return message.containsProperty(ManagementHelper.HDR_OPERATION_SUCCEEDED);
327       }
328    
329       /**
330        * Returns whether the JMS message corresponds to the result of a management attribute value.
331        */
332       public static boolean isAttributesResult(final Message message)
333       {
334          return !ManagementHelper.isOperationResult(message);
335       }
336    
337       /**
338        * Used by HornetQ management service.
339        */
340       public static void storeResult(final Message message, final Object result) throws Exception
341       {
342          String resultString;
343    
344          if (result != null)
345          {
346             // Result is stored in body, also encoded as JSON array of length 1
347    
348             JSONArray jsonArray = ManagementHelper.toJSONArray(new Object[] { result });
349    
350             resultString = jsonArray.toString();
351          }
352          else
353          {
354             resultString = null;
355          }
356    
357          message.getBodyBuffer().writeNullableSimpleString(SimpleString.toSimpleString(resultString));
358       }
359    
360       /**
361        * Returns the result of an operation invocation or an attribute value.
362        * <br>
363        * If an error occurred on the server, {@link #hasOperationSucceeded(Message)} will return {@code false}.
364        * and the result will be a String corresponding to the server exception.
365        */
366       public static Object[] getResults(final Message message) throws Exception
367       {
368          SimpleString sstring = message.getBodyBuffer().readNullableSimpleString();
369          String jsonString = (sstring == null) ? null : sstring.toString();
370                                               ;
371          if (jsonString != null)
372          {
373             JSONArray jsonArray = new JSONArray(jsonString);
374    
375             Object[] res = ManagementHelper.fromJSONArray(jsonArray);
376    
377             return res;
378          }
379          else
380          {
381             return null;
382          }
383       }
384    
385       /**
386        * Returns the result of an operation invocation or an attribute value.
387        * <br>
388        * If an error occurred on the server, {@link #hasOperationSucceeded(Message)} will return {@code false}.
389        * and the result will be a String corresponding to the server exception.
390        */
391       public static Object getResult(final Message message) throws Exception
392       {
393          Object[] res = ManagementHelper.getResults(message);
394    
395          if (res != null)
396          {
397             return res[0];
398          }
399          else
400          {
401             return null;
402          }
403       }
404    
405       /**
406        * Returns whether the invocation of the management operation on the server resource succeeded.
407        */
408       public static boolean hasOperationSucceeded(final Message message)
409       {
410          if (!ManagementHelper.isOperationResult(message))
411          {
412             return false;
413          }
414          if (message.containsProperty(ManagementHelper.HDR_OPERATION_SUCCEEDED))
415          {
416             return message.getBooleanProperty(ManagementHelper.HDR_OPERATION_SUCCEEDED);
417          }
418          return false;
419       }
420    
421       /**
422        * Used by HornetQ management service.
423        */
424       public static Map<String, Object> fromCommaSeparatedKeyValues(final String str) throws Exception
425       {
426          if (str == null || str.trim().length() == 0)
427          {
428             return Collections.emptyMap();
429          }
430    
431          // create a JSON array with 1 object:
432          JSONArray array = new JSONArray("[{" + str + "}]");
433          Map<String, Object> params = (Map<String, Object>)ManagementHelper.fromJSONArray(array)[0];
434          return params;
435       }
436    
437       /**
438        * Used by HornetQ management service.
439        */
440       public static Object[] fromCommaSeparatedArrayOfCommaSeparatedKeyValues(final String str) throws Exception
441       {
442          if (str == null || str.trim().length() == 0)
443          {
444             return new Object[0];
445          }
446    
447          String s = str;
448    
449          // if there is a single item, we wrap it in to make it a JSON object
450          if (!s.trim().startsWith("{"))
451          {
452             s = "{" + s + "}";
453          }
454          JSONArray array = new JSONArray("[" + s + "]");
455          return ManagementHelper.fromJSONArray(array);
456       }
457    
458       // Constructors --------------------------------------------------
459    
460       private ManagementHelper()
461       {
462       }
463    
464       // Public --------------------------------------------------------
465    
466       // Package protected ---------------------------------------------
467    
468       // Protected -----------------------------------------------------
469    
470       // Private -------------------------------------------------------
471    
472       // Inner classes -------------------------------------------------
473    }