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.util;
018    
019    import java.net.URI;
020    import java.net.URISyntaxException;
021    import java.util.Date;
022    import java.util.HashMap;
023    import java.util.Map;
024    
025    import org.apache.activemq.command.ActiveMQDestination;
026    import org.fusesource.hawtbuf.UTF8Buffer;
027    
028    /**
029     * Type conversion support for ActiveMQ.
030     */
031    public final class TypeConversionSupport {
032    
033        private static final Converter IDENTITY_CONVERTER = new Converter() {
034            @Override
035            public Object convert(Object value) {
036                return value;
037            }
038        };
039    
040        private static class ConversionKey {
041            final Class<?> from;
042            final Class<?> to;
043            final int hashCode;
044    
045            public ConversionKey(Class<?> from, Class<?> to) {
046                this.from = from;
047                this.to = to;
048                this.hashCode = from.hashCode() ^ (to.hashCode() << 1);
049            }
050    
051            @Override
052            public boolean equals(Object o) {
053                ConversionKey x = (ConversionKey)o;
054                return x.from == from && x.to == to;
055            }
056    
057            @Override
058            public int hashCode() {
059                return hashCode;
060            }
061        }
062    
063        public interface Converter {
064            Object convert(Object value);
065        }
066    
067        private static final Map<ConversionKey, Converter> CONVERSION_MAP = new HashMap<ConversionKey, Converter>();
068        static {
069            Converter toStringConverter = new Converter() {
070                @Override
071                public Object convert(Object value) {
072                    return value.toString();
073                }
074            };
075            CONVERSION_MAP.put(new ConversionKey(Boolean.class, String.class), toStringConverter);
076            CONVERSION_MAP.put(new ConversionKey(Byte.class, String.class), toStringConverter);
077            CONVERSION_MAP.put(new ConversionKey(Short.class, String.class), toStringConverter);
078            CONVERSION_MAP.put(new ConversionKey(Integer.class, String.class), toStringConverter);
079            CONVERSION_MAP.put(new ConversionKey(Long.class, String.class), toStringConverter);
080            CONVERSION_MAP.put(new ConversionKey(Float.class, String.class), toStringConverter);
081            CONVERSION_MAP.put(new ConversionKey(Double.class, String.class), toStringConverter);
082            CONVERSION_MAP.put(new ConversionKey(UTF8Buffer.class, String.class), toStringConverter);
083    
084            CONVERSION_MAP.put(new ConversionKey(String.class, Boolean.class), new Converter() {
085                @Override
086                public Object convert(Object value) {
087                    return Boolean.valueOf((String)value);
088                }
089            });
090            CONVERSION_MAP.put(new ConversionKey(String.class, Byte.class), new Converter() {
091                @Override
092                public Object convert(Object value) {
093                    return Byte.valueOf((String)value);
094                }
095            });
096            CONVERSION_MAP.put(new ConversionKey(String.class, Short.class), new Converter() {
097                @Override
098                public Object convert(Object value) {
099                    return Short.valueOf((String)value);
100                }
101            });
102            CONVERSION_MAP.put(new ConversionKey(String.class, Integer.class), new Converter() {
103                @Override
104                public Object convert(Object value) {
105                    return Integer.valueOf((String)value);
106                }
107            });
108            CONVERSION_MAP.put(new ConversionKey(String.class, Long.class), new Converter() {
109                @Override
110                public Object convert(Object value) {
111                    return Long.valueOf((String)value);
112                }
113            });
114            CONVERSION_MAP.put(new ConversionKey(String.class, Float.class), new Converter() {
115                @Override
116                public Object convert(Object value) {
117                    return Float.valueOf((String)value);
118                }
119            });
120            CONVERSION_MAP.put(new ConversionKey(String.class, Double.class), new Converter() {
121                @Override
122                public Object convert(Object value) {
123                    return Double.valueOf((String)value);
124                }
125            });
126    
127            Converter longConverter = new Converter() {
128                @Override
129                public Object convert(Object value) {
130                    return Long.valueOf(((Number)value).longValue());
131                }
132            };
133            CONVERSION_MAP.put(new ConversionKey(Byte.class, Long.class), longConverter);
134            CONVERSION_MAP.put(new ConversionKey(Short.class, Long.class), longConverter);
135            CONVERSION_MAP.put(new ConversionKey(Integer.class, Long.class), longConverter);
136            CONVERSION_MAP.put(new ConversionKey(Date.class, Long.class), new Converter() {
137                @Override
138                public Object convert(Object value) {
139                    return Long.valueOf(((Date)value).getTime());
140                }
141            });
142    
143            Converter intConverter = new Converter() {
144                @Override
145                public Object convert(Object value) {
146                    return Integer.valueOf(((Number)value).intValue());
147                }
148            };
149            CONVERSION_MAP.put(new ConversionKey(Byte.class, Integer.class), intConverter);
150            CONVERSION_MAP.put(new ConversionKey(Short.class, Integer.class), intConverter);
151    
152            CONVERSION_MAP.put(new ConversionKey(Byte.class, Short.class), new Converter() {
153                @Override
154                public Object convert(Object value) {
155                    return Short.valueOf(((Number)value).shortValue());
156                }
157            });
158    
159            CONVERSION_MAP.put(new ConversionKey(Float.class, Double.class), new Converter() {
160                @Override
161                public Object convert(Object value) {
162                    return new Double(((Number)value).doubleValue());
163                }
164            });
165            CONVERSION_MAP.put(new ConversionKey(String.class, ActiveMQDestination.class), new Converter() {
166                @Override
167                public Object convert(Object value) {
168                    return ActiveMQDestination.createDestination((String)value, ActiveMQDestination.QUEUE_TYPE);
169                }
170            });
171            CONVERSION_MAP.put(new ConversionKey(String.class, URI.class), new Converter() {
172                @Override
173                public Object convert(Object value) {
174                    String text = value.toString();
175                    try {
176                        return new URI(text);
177                    } catch (URISyntaxException e) {
178                        throw new RuntimeException(e);
179                    }
180                }
181            });
182        }
183    
184        private TypeConversionSupport() {
185        }
186    
187        public static Object convert(Object value, Class<?> to) {
188            if (value == null) {
189                // lets avoid NullPointerException when converting to boolean for null values
190                if (boolean.class.isAssignableFrom(to)) {
191                    return Boolean.FALSE;
192                }
193                return null;
194            }
195    
196            // eager same instance type test to avoid the overhead of invoking the type converter
197            // if already same type
198            if (to.isInstance(value)) {
199                return to.cast(value);
200            }
201    
202            // lookup converter
203            Converter c = lookupConverter(value.getClass(), to);
204            if (c != null) {
205                return c.convert(value);
206            } else {
207                return null;
208            }
209        }
210    
211        public static Converter lookupConverter(Class<?> from, Class<?> to) {
212            // use wrapped type for primitives
213            if (from.isPrimitive()) {
214                from = convertPrimitiveTypeToWrapperType(from);
215            }
216            if (to.isPrimitive()) {
217                to = convertPrimitiveTypeToWrapperType(to);
218            }
219    
220            if (from.equals(to)) {
221                return IDENTITY_CONVERTER;
222            }
223    
224            return CONVERSION_MAP.get(new ConversionKey(from, to));
225        }
226    
227        /**
228         * Converts primitive types such as int to its wrapper type like
229         * {@link Integer}
230         */
231        private static Class<?> convertPrimitiveTypeToWrapperType(Class<?> type) {
232            Class<?> rc = type;
233            if (type.isPrimitive()) {
234                if (type == int.class) {
235                    rc = Integer.class;
236                } else if (type == long.class) {
237                    rc = Long.class;
238                } else if (type == double.class) {
239                    rc = Double.class;
240                } else if (type == float.class) {
241                    rc = Float.class;
242                } else if (type == short.class) {
243                    rc = Short.class;
244                } else if (type == byte.class) {
245                    rc = Byte.class;
246                } else if (type == boolean.class) {
247                    rc = Boolean.class;
248                }
249            }
250            return rc;
251        }
252    }