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