You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2010/09/15 13:57:27 UTC

svn commit: r997297 - in /camel/trunk/camel-core/src: main/java/org/apache/camel/impl/converter/ test/java/org/apache/camel/converter/

Author: davsclaus
Date: Wed Sep 15 11:57:26 2010
New Revision: 997297

URL: http://svn.apache.org/viewvc?rev=997297&view=rev
Log:
CAMEL-3123: Improved performance of PropertyEditorTypeConverter.

Added:
    camel/trunk/camel-core/src/test/java/org/apache/camel/converter/PropertyEditorTypeConverterIssueTest.java
Modified:
    camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/DefaultTypeConverter.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/PropertyEditorTypeConverter.java

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/DefaultTypeConverter.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/DefaultTypeConverter.java?rev=997297&r1=997296&r2=997297&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/DefaultTypeConverter.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/DefaultTypeConverter.java Wed Sep 15 11:57:26 2010
@@ -38,6 +38,7 @@ import org.apache.camel.spi.PackageScanC
 import org.apache.camel.spi.TypeConverterAware;
 import org.apache.camel.spi.TypeConverterRegistry;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.ServiceHelper;
 import org.apache.camel.util.StopWatch;
 import org.apache.camel.util.TimeUtils;
 import org.apache.commons.logging.Log;
@@ -57,6 +58,7 @@ public class DefaultTypeConverter extend
     private final List<FallbackTypeConverter> fallbackConverters = new ArrayList<FallbackTypeConverter>();
     private Injector injector;
     private final FactoryFinder factoryFinder;
+    private final PropertyEditorTypeConverter propertyEditorTypeConverter = new PropertyEditorTypeConverter();
 
     public DefaultTypeConverter(PackageScanClassResolver resolver, Injector injector, FactoryFinder factoryFinder) {
         this.injector = injector;
@@ -68,7 +70,7 @@ public class DefaultTypeConverter extend
         // ToStringTypeConverter should NOT allow to be promoted
         addFallbackTypeConverter(new ToStringTypeConverter(), false);
         // do not assume property editor as it has a String converter
-        addFallbackTypeConverter(new PropertyEditorTypeConverter(), false);
+        addFallbackTypeConverter(propertyEditorTypeConverter, false);
         // enum is okay to be promoted
         addFallbackTypeConverter(new EnumTypeConverter(), true);
         // arrays is okay to be promoted
@@ -415,6 +417,7 @@ public class DefaultTypeConverter extend
 
     @Override
     protected void doStart() throws Exception {
+        ServiceHelper.startService(propertyEditorTypeConverter);
         loadTypeConverters();
     }
 
@@ -422,6 +425,8 @@ public class DefaultTypeConverter extend
     protected void doStop() throws Exception {
         typeMappings.clear();
         misses.clear();
+        // let property editor type converter stop and cleanup resources
+        ServiceHelper.stopService(propertyEditorTypeConverter);
     }
 
     /**

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/PropertyEditorTypeConverter.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/PropertyEditorTypeConverter.java?rev=997297&r1=997296&r2=997297&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/PropertyEditorTypeConverter.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/PropertyEditorTypeConverter.java Wed Sep 15 11:57:26 2010
@@ -18,9 +18,13 @@ package org.apache.camel.impl.converter;
 
 import java.beans.PropertyEditor;
 import java.beans.PropertyEditorManager;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.camel.Exchange;
+import org.apache.camel.Service;
 import org.apache.camel.TypeConverter;
+import org.apache.camel.util.LRUCache;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -31,9 +35,14 @@ import org.apache.commons.logging.LogFac
  *
  * @version $Revision$
  */
-public class PropertyEditorTypeConverter implements TypeConverter {
+public class PropertyEditorTypeConverter implements TypeConverter, Service {
 
     private static final Log LOG = LogFactory.getLog(PropertyEditorTypeConverter.class);
+    // use a bound cache to avoid using too much memory in case a lot of different classes
+    // is being converted to string
+    private final Map<Class, Class> misses = new LRUCache<Class, Class>(1000);
+    // we don't anticipate so many property editors so we have unbounded map
+    private final Map<Class, PropertyEditor> cache = new HashMap<Class, PropertyEditor>();
 
     public <T> T convertTo(Class<T> type, Object value) {
         // We can't convert null values since we can't figure out a property
@@ -48,21 +57,13 @@ public class PropertyEditorTypeConverter
                 return ObjectHelper.cast(type, value);
             }
 
-            // TODO: findEditor is synchronized so we want to avoid calling it
-            // we should have a local hit cache
-            PropertyEditor editor = PropertyEditorManager.findEditor(type);
-            if (LOG.isTraceEnabled()) {
-                LOG.trace("Finding property editor for type: " + type + " -> " + editor);
-            }
+            PropertyEditor editor = lookupEditor(type, value);
             if (editor != null) {
                 editor.setAsText(value.toString());
                 return ObjectHelper.cast(type, editor.getValue());
             }
         } else if (type == String.class) {
-            PropertyEditor editor = PropertyEditorManager.findEditor(value.getClass());
-            if (LOG.isTraceEnabled()) {
-                LOG.trace("Finding property editor for type: " + type + " -> " + editor);
-            }
+            PropertyEditor editor = lookupEditor(type, value);
             if (editor != null) {
                 editor.setValue(value);
                 return ObjectHelper.cast(type, editor.getAsText());
@@ -72,6 +73,42 @@ public class PropertyEditorTypeConverter
         return null;
     }
 
+    private <T> PropertyEditor lookupEditor(Class<T> type, Object value) {
+        Class key = value.getClass();
+
+        // check misses first
+        if (misses.containsKey(key)) {
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("No previously found property editor for type: " + type);
+            }
+            return null;
+        }
+
+        synchronized (cache) {
+            // not a miss then try to lookup the editor
+            PropertyEditor editor = cache.get(key);
+            if (editor == null) {
+                // findEditor is synchronized and very slow so we want to only lookup once for a given key
+                // and then we use our own local cache for faster lookup
+                editor = PropertyEditorManager.findEditor(key);
+
+                // either we found an editor, or if not then register it as a miss
+                if (editor != null) {
+                    if (LOG.isTraceEnabled()) {
+                        LOG.trace("Found property editor for type: " + type + " -> " + editor);
+                    }
+                    cache.put(key, editor);
+                } else {
+                    if (LOG.isTraceEnabled()) {
+                        LOG.trace("Cannot find property editor for type: " + type);
+                    }
+                    misses.put(key, key);
+                }
+            }
+            return editor;
+        }
+    }
+
     public <T> T convertTo(Class<T> type, Exchange exchange, Object value) {
         return convertTo(type, value);
     }
@@ -84,4 +121,12 @@ public class PropertyEditorTypeConverter
         return convertTo(type, value);
     }
 
+    public void start() throws Exception {
+    }
+
+    public void stop() throws Exception {
+        cache.clear();
+        misses.clear();
+    }
+
 }

Added: camel/trunk/camel-core/src/test/java/org/apache/camel/converter/PropertyEditorTypeConverterIssueTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/converter/PropertyEditorTypeConverterIssueTest.java?rev=997297&view=auto
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/converter/PropertyEditorTypeConverterIssueTest.java (added)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/converter/PropertyEditorTypeConverterIssueTest.java Wed Sep 15 11:57:26 2010
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.converter;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.util.StopWatch;
+
+/**
+ * @version $Revision$
+ */
+public class PropertyEditorTypeConverterIssueTest extends ContextTestSupport {
+
+    public void testPropertyEditorTypeConverter() throws Exception {
+        // test that converters a custom object (MyBean) to a String which causes
+        // PropertyEditorTypeConverter to be used. And this test times how fast
+        // this is. As we want to optimize PropertyEditorTypeConverter to be faster
+        MyBean bean = new MyBean();
+        bean.setBar("Hello");
+
+        StopWatch watch = new StopWatch();
+        for (int i = 0; i < 500; i++) {
+            assertNotNull(context.getTypeConverter().convertTo(String.class, bean));
+        }
+        log.info("Time taken: " + watch.stop());
+    }
+
+}