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