Author: davsclaus Date: Mon Apr 16 07:10:04 2012 New Revision: 1326514 URL: http://svn.apache.org/viewvc?rev=1326514&view=rev Log: CAMEL-5175: Added utilization stats to type converter registry which is also accessible from JMX.
Added: camel/trunk/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedTypeConverterRegistryMBean.java camel/trunk/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedTypeConverterRegistry.java camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedTypeConverterRegistryTest.java - copied, changed from r1326471, camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedLoadBalancerTest.java Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java camel/trunk/camel-core/src/main/java/org/apache/camel/management/DefaultManagementLifecycleStrategy.java camel/trunk/camel-core/src/main/java/org/apache/camel/spi/TypeConverterRegistry.java Added: camel/trunk/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedTypeConverterRegistryMBean.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedTypeConverterRegistryMBean.java?rev=1326514&view=auto ============================================================================== --- camel/trunk/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedTypeConverterRegistryMBean.java (added) +++ camel/trunk/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedTypeConverterRegistryMBean.java Mon Apr 16 07:10:04 2012 @@ -0,0 +1,42 @@ +/** + * 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.api.management.mbean; + +import org.apache.camel.api.management.ManagedAttribute; +import org.apache.camel.api.management.ManagedOperation; + +/** + * + */ +public interface ManagedTypeConverterRegistryMBean extends ManagedServiceMBean { + + @ManagedAttribute(description = "Number of type conversion attempts") + long getAttemptCounter(); + + @ManagedAttribute(description = "Number of type conversion hits (successful conversions)") + long getHitCounter(); + + @ManagedAttribute(description = "Number of type conversion misses (no suitable type converter)") + long getMissCounter(); + + @ManagedAttribute(description = "Number of type conversion failures (failed conversions)") + long getFailedCounter(); + + @ManagedOperation(description = "Resets the type conversion counters") + void resetTypeConversionCounters(); + +} Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java?rev=1326514&r1=1326513&r2=1326514&view=diff ============================================================================== --- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java (original) +++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java Mon Apr 16 07:10:04 2012 @@ -26,6 +26,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicLong; import org.apache.camel.CamelExecutionException; import org.apache.camel.Exchange; @@ -41,7 +42,6 @@ import org.apache.camel.spi.TypeConverte import org.apache.camel.spi.TypeConverterRegistry; import org.apache.camel.support.ServiceSupport; import org.apache.camel.util.ObjectHelper; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,6 +61,11 @@ public abstract class BaseTypeConverterR protected Injector injector; protected final FactoryFinder factoryFinder; protected final PropertyEditorTypeConverter propertyEditorTypeConverter = new PropertyEditorTypeConverter(); + protected final Statistics statistics = new UtilizationStatistics(); + protected final AtomicLong attemptCounter = new AtomicLong(); + protected final AtomicLong missCounter = new AtomicLong(); + protected final AtomicLong hitCounter = new AtomicLong(); + protected final AtomicLong failedCounter = new AtomicLong(); public BaseTypeConverterRegistry(PackageScanClassResolver resolver, Injector injector, FactoryFinder factoryFinder) { this.resolver = resolver; @@ -102,8 +107,10 @@ public abstract class BaseTypeConverterR Object answer; try { + attemptCounter.incrementAndGet(); answer = doConvertTo(type, exchange, value, false); } catch (Exception e) { + failedCounter.incrementAndGet(); // if its a ExecutionException then we have rethrow it as its not due to failed conversion // this is special for FutureTypeConverter boolean execution = ObjectHelper.getException(ExecutionException.class, e) != null @@ -117,8 +124,11 @@ public abstract class BaseTypeConverterR } if (answer == Void.TYPE) { // Could not find suitable conversion + missCounter.incrementAndGet(); + // Could not find suitable conversion return null; } else { + hitCounter.incrementAndGet(); return (T) answer; } } @@ -137,15 +147,20 @@ public abstract class BaseTypeConverterR Object answer; try { + attemptCounter.incrementAndGet(); answer = doConvertTo(type, exchange, value, false); } catch (Exception e) { + failedCounter.incrementAndGet(); // error occurred during type conversion throw new TypeConversionException(value, type, e); } if (answer == Void.TYPE || value == null) { // Could not find suitable conversion + missCounter.incrementAndGet(); + // Could not find suitable conversion throw new NoTypeConversionAvailableException(value, type); } else { + hitCounter.incrementAndGet(); return (T) answer; } } @@ -452,15 +467,66 @@ public abstract class BaseTypeConverterR } @Override + public Statistics getStatistics() { + return statistics; + } + + @Override protected void doStart() throws Exception { // noop } @Override protected void doStop() throws Exception { + // log utilization statistics when stopping, including mappings + String info = statistics.toString(); + info += String.format(" mappings[total=%s, misses=%s]", typeMappings.size(), misses.size()); + log.info(info); + typeMappings.clear(); misses.clear(); propertyEditorTypeConverter.clear(); + statistics.reset(); + } + + /** + * Represents utilization statistics + */ + private final class UtilizationStatistics implements Statistics { + + @Override + public long getAttemptCounter() { + return attemptCounter.get(); + } + + @Override + public long getHitCounter() { + return hitCounter.get(); + } + + @Override + public long getMissCounter() { + return missCounter.get(); + } + + @Override + public long getFailedCounter() { + return failedCounter.get(); + } + + @Override + public void reset() { + attemptCounter.set(0); + hitCounter.set(0); + missCounter.set(0); + failedCounter.set(0); + } + + @Override + public String toString() { + return String.format("TypeConverterRegistry utilization[attempts=%s, hits=%s, misses=%s, failures=%s]", + getAttemptCounter(), getHitCounter(), getMissCounter(), getFailedCounter()); + } } /** Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/management/DefaultManagementLifecycleStrategy.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/management/DefaultManagementLifecycleStrategy.java?rev=1326514&r1=1326513&r2=1326514&view=diff ============================================================================== --- camel/trunk/camel-core/src/main/java/org/apache/camel/management/DefaultManagementLifecycleStrategy.java (original) +++ camel/trunk/camel-core/src/main/java/org/apache/camel/management/DefaultManagementLifecycleStrategy.java Mon Apr 16 07:10:04 2012 @@ -58,6 +58,7 @@ import org.apache.camel.management.mbean import org.apache.camel.management.mbean.ManagedService; import org.apache.camel.management.mbean.ManagedThrottlingInflightRoutePolicy; import org.apache.camel.management.mbean.ManagedTracer; +import org.apache.camel.management.mbean.ManagedTypeConverterRegistry; import org.apache.camel.model.AOPDefinition; import org.apache.camel.model.InterceptDefinition; import org.apache.camel.model.OnCompletionDefinition; @@ -75,6 +76,7 @@ import org.apache.camel.spi.ManagementNa import org.apache.camel.spi.ManagementObjectStrategy; import org.apache.camel.spi.ManagementStrategy; import org.apache.camel.spi.RouteContext; +import org.apache.camel.spi.TypeConverterRegistry; import org.apache.camel.spi.UnitOfWork; import org.apache.camel.support.ServiceSupport; import org.apache.camel.support.TimerListenerManager; @@ -418,6 +420,8 @@ public class DefaultManagementLifecycleS answer = new ManagedProducerCache(context, (ProducerCache) service); } else if (service instanceof EndpointRegistry) { answer = new ManagedEndpointRegistry(context, (EndpointRegistry) service); + } else if (service instanceof TypeConverterRegistry) { + answer = new ManagedTypeConverterRegistry(context, (TypeConverterRegistry) service); } else if (service != null) { // fallback as generic service answer = getManagementObjectStrategy().getManagedObjectForService(context, service); Added: camel/trunk/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedTypeConverterRegistry.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedTypeConverterRegistry.java?rev=1326514&view=auto ============================================================================== --- camel/trunk/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedTypeConverterRegistry.java (added) +++ camel/trunk/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedTypeConverterRegistry.java Mon Apr 16 07:10:04 2012 @@ -0,0 +1,60 @@ +/** + * 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.management.mbean; + +import org.apache.camel.CamelContext; +import org.apache.camel.api.management.ManagedResource; +import org.apache.camel.api.management.mbean.ManagedTypeConverterRegistryMBean; +import org.apache.camel.spi.TypeConverterRegistry; + +/** + * + */ +@ManagedResource(description = "Managed TypeConverterRegistry") +public class ManagedTypeConverterRegistry extends ManagedService implements ManagedTypeConverterRegistryMBean { + + private final TypeConverterRegistry registry; + + public ManagedTypeConverterRegistry(CamelContext context, TypeConverterRegistry registry) { + super(context, registry); + this.registry = registry; + } + + public TypeConverterRegistry getRegistry() { + return registry; + } + + public long getAttemptCounter() { + return registry.getStatistics().getAttemptCounter(); + } + + public long getHitCounter() { + return registry.getStatistics().getHitCounter(); + } + + public long getMissCounter() { + return registry.getStatistics().getMissCounter(); + } + + public long getFailedCounter() { + return registry.getStatistics().getFailedCounter(); + } + + public void resetTypeConversionCounters() { + registry.getStatistics().reset(); + } +} Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/spi/TypeConverterRegistry.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/spi/TypeConverterRegistry.java?rev=1326514&r1=1326513&r2=1326514&view=diff ============================================================================== --- camel/trunk/camel-core/src/main/java/org/apache/camel/spi/TypeConverterRegistry.java (original) +++ camel/trunk/camel-core/src/main/java/org/apache/camel/spi/TypeConverterRegistry.java Mon Apr 16 07:10:04 2012 @@ -16,6 +16,7 @@ */ package org.apache.camel.spi; +import org.apache.camel.Service; import org.apache.camel.TypeConverter; /** @@ -23,7 +24,38 @@ import org.apache.camel.TypeConverter; * * @version */ -public interface TypeConverterRegistry { +public interface TypeConverterRegistry extends Service { + + /** + * Utilization statistics of the this registry. + */ + interface Statistics { + + /** + * Number of attempts + */ + long getAttemptCounter(); + + /** + * Number of successful conversions + */ + long getHitCounter(); + + /** + * Number of attempts which cannot be converted as no suitable type converter exists + */ + long getMissCounter(); + + /** + * Number of failed attempts during type conversion + */ + long getFailedCounter(); + + /** + * Reset the counters + */ + void reset(); + } /** * Registers a new type converter @@ -64,4 +96,12 @@ public interface TypeConverterRegistry { * @return the injector */ Injector getInjector(); + + /** + * Gets the utilization statistics of this type converter registry + * + * @return the utilization statistics + */ + Statistics getStatistics(); + } Copied: camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedTypeConverterRegistryTest.java (from r1326471, camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedLoadBalancerTest.java) URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedTypeConverterRegistryTest.java?p2=camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedTypeConverterRegistryTest.java&p1=camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedLoadBalancerTest.java&r1=1326471&r2=1326514&rev=1326514&view=diff ============================================================================== --- camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedLoadBalancerTest.java (original) +++ camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedTypeConverterRegistryTest.java Mon Apr 16 07:10:04 2012 @@ -16,6 +16,7 @@ */ package org.apache.camel.management; +import java.util.Set; import javax.management.MBeanServer; import javax.management.ObjectName; @@ -24,33 +25,64 @@ import org.apache.camel.builder.RouteBui /** * @version */ -public class ManagedLoadBalancerTest extends ManagementTestSupport { +public class ManagedTypeConverterRegistryTest extends ManagementTestSupport { - public void testLoadBalancer() throws Exception { - getMockEndpoint("mock:a").expectedBodiesReceived("Hello World", "Hi World"); - getMockEndpoint("mock:b").expectedBodiesReceived("Bye World"); - - template.sendBody("direct:start", "Hello World"); - template.sendBody("direct:start", "Bye World"); - template.sendBody("direct:start", "Hi World"); + public void testTypeConverterRegistry() throws Exception { + getMockEndpoint("mock:a").expectedMessageCount(2); + + template.sendBody("direct:start", "3"); + template.sendBody("direct:start", "7"); assertMockEndpointsSatisfied(); MBeanServer mbeanServer = getMBeanServer(); - ObjectName name = ObjectName.getInstance("org.apache.camel:context=localhost/camel-1,type=endpoints,name=\"mock://a\""); - Long queueSize = (Long) mbeanServer.invoke(name, "queueSize", null, null); - assertEquals(2, queueSize.intValue()); - - name = ObjectName.getInstance("org.apache.camel:context=localhost/camel-1,type=endpoints,name=\"mock://b\""); - queueSize = (Long) mbeanServer.invoke(name, "queueSize", null, null); - assertEquals(1, queueSize.intValue()); - - name = ObjectName.getInstance("org.apache.camel:context=localhost/camel-1,type=processors,name=\"myBalancer\""); - mbeanServer.isRegistered(name); - - Long total = (Long) mbeanServer.getAttribute(name, "ExchangesTotal"); - assertEquals(3, total.intValue()); + ObjectName on = ObjectName.getInstance("org.apache.camel:context=localhost/camel-1,type=services,*"); + + // number of services + Set<ObjectName> names = mbeanServer.queryNames(on, null); + ObjectName name = null; + for (ObjectName service : names) { + if (service.toString().contains("DefaultTypeConverter")) { + name = service; + break; + } + } + assertNotNull("Cannot find DefaultTypeConverter", name); + + Long failed = (Long) mbeanServer.getAttribute(name, "FailedCounter"); + assertEquals(0, failed.intValue()); + Long miss = (Long) mbeanServer.getAttribute(name, "MissCounter"); + assertEquals(0, miss.intValue()); + Long attempt = (Long) mbeanServer.getAttribute(name, "AttemptCounter"); + assertEquals(2, attempt.intValue()); + Long hit = (Long) mbeanServer.getAttribute(name, "HitCounter"); + assertEquals(2, hit.intValue()); + + try { + template.sendBody("direct:start", "foo"); + fail("Should have thrown exception"); + } catch (Exception e) { + // expected + } + + // should now have a failed + failed = (Long) mbeanServer.getAttribute(name, "FailedCounter"); + assertEquals(1, failed.intValue()); + miss = (Long) mbeanServer.getAttribute(name, "MissCounter"); + assertEquals(0, miss.intValue()); + + // reset + mbeanServer.invoke(name, "resetTypeConversionCounters", null, null); + + failed = (Long) mbeanServer.getAttribute(name, "FailedCounter"); + assertEquals(0, failed.intValue()); + miss = (Long) mbeanServer.getAttribute(name, "MissCounter"); + assertEquals(0, miss.intValue()); + attempt = (Long) mbeanServer.getAttribute(name, "AttemptCounter"); + assertEquals(0, attempt.intValue()); + hit = (Long) mbeanServer.getAttribute(name, "HitCounter"); + assertEquals(0, hit.intValue()); } @Override @@ -59,8 +91,8 @@ public class ManagedLoadBalancerTest ext @Override public void configure() throws Exception { from("direct:start").routeId("foo") - .loadBalance().id("myBalancer").roundRobin() - .to("mock:a").to("mock:b"); + .convertBodyTo(int.class) + .to("mock:a"); } }; }