001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.console.filter; 018 019import java.lang.reflect.Array; 020import java.lang.reflect.Method; 021import java.util.Enumeration; 022import java.util.HashMap; 023import java.util.Iterator; 024import java.util.Map; 025import java.util.Properties; 026import java.util.Arrays; 027 028import javax.jms.DeliveryMode; 029import javax.jms.JMSException; 030import javax.management.Attribute; 031import javax.management.AttributeList; 032import javax.management.ObjectInstance; 033import javax.management.ObjectName; 034import javax.management.openmbean.CompositeDataSupport; 035 036import org.apache.activemq.command.ActiveMQBytesMessage; 037import org.apache.activemq.command.ActiveMQDestination; 038import org.apache.activemq.command.ActiveMQMapMessage; 039import org.apache.activemq.command.ActiveMQMessage; 040import org.apache.activemq.command.ActiveMQObjectMessage; 041import org.apache.activemq.command.ActiveMQStreamMessage; 042import org.apache.activemq.command.ActiveMQTextMessage; 043import org.apache.activemq.console.util.AmqMessagesUtil; 044 045public class MapTransformFilter extends ResultTransformFilter { 046 /** 047 * Creates a Map transform filter that is able to transform a variety of 048 * objects to a properties map object 049 * 050 * @param next - the next query filter 051 */ 052 public MapTransformFilter(QueryFilter next) { 053 super(next); 054 } 055 056 /** 057 * Transform the given object to a Map object 058 * 059 * @param object - object to transform 060 * @return map object 061 */ 062 protected Object transformElement(Object object) throws Exception { 063 // Use reflection to determine how the object should be transformed 064 try { 065 Method method = this.getClass().getDeclaredMethod("transformToMap", new Class[] { 066 object.getClass() 067 }); 068 return (Map)method.invoke(this, new Object[] { 069 object 070 }); 071 } catch (NoSuchMethodException e) { 072// CommandContext.print("Unable to transform mbean of type: " + object.getClass().getName() + ". No corresponding transformToMap method found."); 073 return null; 074 } 075 } 076 077 /** 078 * Transform an ObjectInstance mbean to a Map 079 * 080 * @param obj - ObjectInstance format of an mbean 081 * @return map object 082 */ 083 protected Map transformToMap(ObjectInstance obj) { 084 return transformToMap(obj.getObjectName()); 085 } 086 087 /** 088 * Transform an ObjectName mbean to a Map 089 * 090 * @param objname - ObjectName format of an mbean 091 * @return map object 092 */ 093 protected Map transformToMap(ObjectName objname) { 094 Properties props = new Properties(); 095 096 // Parse object properties 097 Map objProps = objname.getKeyPropertyList(); 098 for (Iterator i = objProps.keySet().iterator(); i.hasNext();) { 099 Object key = i.next(); 100 Object val = objProps.get(key); 101 if (val != null) { 102 props.setProperty(key.toString(), getDisplayString(val)); 103 } 104 } 105 106 return props; 107 } 108 109 /** 110 * Transform an Attribute List format of an mbean to a Map 111 * 112 * @param list - AttributeList format of an mbean 113 * @return map object 114 */ 115 protected Map transformToMap(AttributeList list) { 116 Properties props = new Properties(); 117 for (Iterator i = list.iterator(); i.hasNext();) { 118 Attribute attrib = (Attribute)i.next(); 119 120 // If attribute is an ObjectName 121 if (attrib.getName().equals(MBeansAttributeQueryFilter.KEY_OBJECT_NAME_ATTRIBUTE)) { 122 props.putAll(transformToMap((ObjectName)attrib.getValue())); 123 } else { 124 if (attrib.getValue() != null) { 125 props.setProperty(attrib.getName(), getDisplayString(attrib.getValue())); 126 } 127 } 128 } 129 130 return props; 131 } 132 133 /** 134 * Transform an ActiveMQTextMessage to a Map 135 * 136 * @param msg - text message to trasnform 137 * @return map object 138 * @throws JMSException 139 */ 140 protected Map transformToMap(ActiveMQTextMessage msg) throws JMSException { 141 Properties props = new Properties(); 142 143 props.putAll(transformToMap((ActiveMQMessage)msg)); 144 if (msg.getText() != null) { 145 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_BODY_PREFIX + "JMSText", msg.getText()); 146 } 147 148 return props; 149 } 150 151 /** 152 * Transform an ActiveMQBytesMessage to a Map 153 * 154 * @param msg - bytes message to transform 155 * @return map object 156 * @throws JMSException 157 */ 158 protected Map transformToMap(ActiveMQBytesMessage msg) throws JMSException { 159 Properties props = new Properties(); 160 161 props.putAll(transformToMap((ActiveMQMessage)msg)); 162 163 long bodyLength = msg.getBodyLength(); 164 byte[] msgBody; 165 int i = 0; 166 // Create separate bytes messages 167 for (i = 0; i < (bodyLength / Integer.MAX_VALUE); i++) { 168 msgBody = new byte[Integer.MAX_VALUE]; 169 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_BODY_PREFIX + "JMSBytes:" + (i + 1), new String(msgBody)); 170 } 171 msgBody = new byte[(int)(bodyLength % Integer.MAX_VALUE)]; 172 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_BODY_PREFIX + "JMSBytes:" + (i + 1), new String(msgBody)); 173 174 return props; 175 } 176 177 /** 178 * Transform an ActiveMQMessage to a Map 179 * 180 * @param msg - object message to transform 181 * @return map object 182 * @throws JMSException 183 */ 184 protected Map transformToMap(ActiveMQObjectMessage msg) throws JMSException { 185 Properties props = new Properties(); 186 187 props.putAll(transformToMap((ActiveMQMessage)msg)); 188 if (msg.getObject() != null) { 189 // Just add the class name and toString value of the object 190 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_BODY_PREFIX + "JMSObjectClass", msg.getObject().getClass().getName()); 191 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_BODY_PREFIX + "JMSObjectString", getDisplayString(msg.getObject())); 192 } 193 return props; 194 } 195 196 /** 197 * Transform an ActiveMQMapMessage to a Map 198 * 199 * @param msg - map message to transform 200 * @return map object 201 * @throws JMSException 202 */ 203 protected Map transformToMap(ActiveMQMapMessage msg) throws JMSException { 204 Properties props = new Properties(); 205 206 props.putAll(transformToMap((ActiveMQMessage)msg)); 207 208 // Get map properties 209 Enumeration e = msg.getMapNames(); 210 while (e.hasMoreElements()) { 211 String key = (String)e.nextElement(); 212 Object val = msg.getObject(key); 213 if (val != null) { 214 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_BODY_PREFIX + key, getDisplayString(val)); 215 } 216 } 217 218 return props; 219 } 220 221 /** 222 * Transform an ActiveMQStreamMessage to a Map 223 * 224 * @param msg - stream message to transform 225 * @return map object 226 * @throws JMSException 227 */ 228 protected Map transformToMap(ActiveMQStreamMessage msg) throws JMSException { 229 Properties props = new Properties(); 230 231 props.putAll(transformToMap((ActiveMQMessage)msg)); 232 // Just set the toString of the message as the body of the stream 233 // message 234 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_BODY_PREFIX + "JMSStreamMessage", getDisplayString(msg)); 235 236 return props; 237 } 238 239 /** 240 * Transform an ActiveMQMessage to a Map 241 * 242 * @param msg - message to transform 243 * @return map object 244 * @throws JMSException 245 */ 246 protected Map<String, String> transformToMap(ActiveMQMessage msg) throws JMSException { 247 Map<String, String> props = new HashMap<String, String>(); 248 249 // Get JMS properties 250 if (msg.getJMSCorrelationID() != null) { 251 props.put(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSCorrelationID", msg.getJMSCorrelationID()); 252 } 253 props.put(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSDeliveryMode", (msg.getJMSDeliveryMode() == DeliveryMode.PERSISTENT) ? "persistent" : "non-persistent"); 254 if (msg.getJMSDestination() != null) { 255 props.put(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSDestination", ((ActiveMQDestination)msg.getJMSDestination()).getPhysicalName()); 256 } 257 props.put(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSExpiration", Long.toString(msg.getJMSExpiration())); 258 props.put(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSMessageID", msg.getJMSMessageID()); 259 props.put(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSPriority", Integer.toString(msg.getJMSPriority())); 260 props.put(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSRedelivered", Boolean.toString(msg.getJMSRedelivered())); 261 if (msg.getJMSReplyTo() != null) { 262 props.put(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSReplyTo", ((ActiveMQDestination)msg.getJMSReplyTo()).getPhysicalName()); 263 } 264 props.put(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSTimestamp", Long.toString(msg.getJMSTimestamp())); 265 if (msg.getJMSType() != null) { 266 props.put(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSType", msg.getJMSType()); 267 } 268 if (msg.getOriginalDestination() != null) { 269 props.put(AmqMessagesUtil.JMS_MESSAGE_CUSTOM_PREFIX + "OriginalDestination", msg.getOriginalDestination().getPhysicalName()); 270 } 271 // Get custom properties 272 Enumeration e = msg.getPropertyNames(); 273 while (e.hasMoreElements()) { 274 String name = (String)e.nextElement(); 275 if (msg.getObjectProperty(name) != null) { 276 props.put(AmqMessagesUtil.JMS_MESSAGE_CUSTOM_PREFIX + name, getDisplayString(msg.getObjectProperty(name))); 277 } 278 } 279 280 return props; 281 } 282 283 /** 284 * Transform an openMBean composite data to a Map 285 * 286 * @param data - composite data to transform 287 * @return map object 288 */ 289 protected Map transformToMap(CompositeDataSupport data) { 290 Properties props = new Properties(); 291 292 String typeName = data.getCompositeType().getTypeName(); 293 294 // Retrieve text message 295 if (typeName.equals(ActiveMQTextMessage.class.getName())) { 296 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_BODY_PREFIX + "Text", data.get("Text").toString()); 297 298 // Retrieve byte preview 299 } else if (typeName.equals(ActiveMQBytesMessage.class.getName())) { 300 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_BODY_PREFIX + "BodyLength", data.get("BodyLength").toString()); 301 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_BODY_PREFIX + "BodyPreview", new String((byte[])data.get("BodyPreview"))); 302 303 // Expand content map 304 } else if (typeName.equals(ActiveMQMapMessage.class.getName())) { 305 Map contentMap = (Map)data.get("ContentMap"); 306 for (Iterator i = contentMap.keySet().iterator(); i.hasNext();) { 307 String key = (String)i.next(); 308 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_BODY_PREFIX + key, contentMap.get(key).toString()); 309 } 310 311 // Do nothing 312 } else if (typeName.equals(ActiveMQObjectMessage.class.getName()) || typeName.equals(ActiveMQStreamMessage.class.getName()) || typeName.equals(ActiveMQMessage.class.getName())) { 313 314 // Unrecognized composite data. Throw exception. 315 } else { 316 throw new IllegalArgumentException("Unrecognized composite data to transform. composite type: " + typeName); 317 } 318 319 // Process the JMS message header values 320 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSCorrelationID", "" + data.get("JMSCorrelationID")); 321 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSDestination", "" + data.get("JMSDestination")); 322 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSMessageID", "" + data.get("JMSMessageID")); 323 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSReplyTo", "" + data.get("JMSReplyTo")); 324 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSType", "" + data.get("JMSType")); 325 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSDeliveryMode", "" + data.get("JMSDeliveryMode")); 326 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSExpiration", "" + data.get("JMSExpiration")); 327 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSPriority", "" + data.get("JMSPriority")); 328 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSRedelivered", "" + data.get("JMSRedelivered")); 329 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + "JMSTimestamp", "" + data.get("JMSTimestamp")); 330 331 // Process the JMS custom message properties 332 props.setProperty(AmqMessagesUtil.JMS_MESSAGE_CUSTOM_PREFIX + "Properties", "" + data.get("Properties")); 333 334 return props; 335 } 336 337 @SuppressWarnings("unchecked") 338 protected String getDisplayString(Object obj) { 339 if (null == obj) 340 return "null"; 341 342 if (obj != null && obj.getClass().isArray()) { 343 Class type = obj.getClass().getComponentType(); 344 if (!type.isPrimitive()) { 345 obj = Arrays.asList((Object[]) obj); 346 } else { 347 // for primitives, we can't use Arrays.toString(), so we have to roll something similar. 348 int len = Array.getLength(obj); 349 if (0 == len) 350 return "[]"; 351 StringBuilder bldr = new StringBuilder(); 352 bldr.append("["); 353 for (int i = 0; i <= len; i++) { 354 bldr.append(Array.get(obj, i)); 355 if (i + 1 >= len) 356 return bldr.append("]").toString(); 357 bldr.append(","); 358 } 359 } 360 361 } 362 363 return obj.toString(); 364 } 365}