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.camel.impl.converter;
018    
019    import java.beans.PropertyEditor;
020    import java.beans.PropertyEditorManager;
021    import java.util.HashMap;
022    import java.util.Map;
023    
024    import org.apache.camel.Exchange;
025    import org.apache.camel.TypeConverter;
026    import org.apache.camel.util.LRUSoftCache;
027    import org.apache.camel.util.ObjectHelper;
028    import org.slf4j.Logger;
029    import org.slf4j.LoggerFactory;
030    
031    /**
032     * Uses the {@link java.beans.PropertyEditor} conversion system to convert Objects to
033     * and from String values.
034     *
035     * @deprecated should be removed as it can cause side-effects when using 3rd party property editors
036     *
037     * @version 
038     */
039    @Deprecated
040    public class PropertyEditorTypeConverter implements TypeConverter {
041    
042        private static final Logger LOG = LoggerFactory.getLogger(PropertyEditorTypeConverter.class);
043        // use a soft bound cache to avoid using too much memory in case a lot of different classes
044        // is being converted to string
045        private final Map<Class<?>, Class<?>> misses = new LRUSoftCache<Class<?>, Class<?>>(1000);
046        // we don't anticipate so many property editors so we have unbounded map
047        private final Map<Class<?>, PropertyEditor> cache = new HashMap<Class<?>, PropertyEditor>();
048    
049        public void clear() {
050            cache.clear();
051            misses.clear();
052        }
053    
054        @Override
055        public <T> T convertTo(Class<T> type, Object value) {
056            // We can't convert null values since we can't figure out a property
057            // editor for it.
058            if (value == null) {
059                return null;
060            }
061    
062            if (value.getClass() == String.class) {
063                // No conversion needed.
064                if (type == String.class) {
065                    return ObjectHelper.cast(type, value);
066                }
067    
068                Class<?> key = type;
069                PropertyEditor editor = lookupEditor(key);
070                if (editor != null) {
071                    // we are essentially not thread safe as we use 2 calls to convert
072                    editor.setAsText(value.toString());
073                    return ObjectHelper.cast(type, editor.getValue());
074                }
075            } else if (type == String.class) {
076                Class<?> key = value.getClass();
077                PropertyEditor editor = lookupEditor(key);
078                if (editor != null) {
079                    // we are essentially not thread safe as we use 2 calls to convert
080                    editor.setValue(value);
081                    return ObjectHelper.cast(type, editor.getAsText());
082                }
083            }
084    
085            return null;
086        }
087    
088        private PropertyEditor lookupEditor(Class<?> type) {
089            // check misses first
090            if (misses.containsKey(type)) {
091                LOG.trace("No previously found property editor for type: {}", type);
092                return null;
093            }
094    
095            synchronized (cache) {
096                // not a miss then try to lookup the editor
097                PropertyEditor editor = cache.get(type);
098                if (editor == null) {
099                    // findEditor is synchronized and very slow so we want to only lookup once for a given key
100                    // and then we use our own local cache for faster lookup
101                    editor = PropertyEditorManager.findEditor(type);
102    
103                    // either we found an editor, or if not then register it as a miss
104                    if (editor != null) {
105                        LOG.trace("Found property editor for type: {} -> {}", type, editor);
106                        cache.put(type, editor);
107                    } else {
108                        LOG.trace("Cannot find property editor for type: {}", type);
109                        misses.put(type, type);
110                    }
111                }
112                return editor;
113            }
114        }
115    
116        @Override
117        public <T> T convertTo(Class<T> type, Exchange exchange, Object value) {
118            return convertTo(type, value);
119        }
120    
121        @Override
122        public <T> T mandatoryConvertTo(Class<T> type, Object value) {
123            return convertTo(type, value);
124        }
125    
126        @Override
127        public <T> T mandatoryConvertTo(Class<T> type, Exchange exchange, Object value) {
128            return convertTo(type, value);
129        }
130    
131        @Override
132        public <T> T tryConvertTo(Class<T> type, Exchange exchange, Object value) {
133            try {
134                return convertTo(type, exchange, value);
135            } catch (Exception e) {
136                return null;
137            }
138        }
139    
140        @Override
141        public <T> T tryConvertTo(Class<T> type, Object value) {
142            try {
143                return convertTo(type, null, value);
144            } catch (Exception e) {
145                return null;
146            }
147        }
148    }