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     */
017    package org.apache.activemq.console.filter;
018    
019    import java.lang.reflect.Method;
020    import java.util.Enumeration;
021    import java.util.HashMap;
022    import java.util.Iterator;
023    import java.util.Map;
024    import java.util.Properties;
025    import java.util.Arrays;
026    
027    import javax.jms.DeliveryMode;
028    import javax.jms.JMSException;
029    import javax.management.Attribute;
030    import javax.management.AttributeList;
031    import javax.management.ObjectInstance;
032    import javax.management.ObjectName;
033    import javax.management.openmbean.CompositeDataSupport;
034    
035    import org.apache.activemq.command.ActiveMQBytesMessage;
036    import org.apache.activemq.command.ActiveMQDestination;
037    import org.apache.activemq.command.ActiveMQMapMessage;
038    import org.apache.activemq.command.ActiveMQMessage;
039    import org.apache.activemq.command.ActiveMQObjectMessage;
040    import org.apache.activemq.command.ActiveMQStreamMessage;
041    import org.apache.activemq.command.ActiveMQTextMessage;
042    import org.apache.activemq.console.util.AmqMessagesUtil;
043    
044    public 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    }