Author: davsclaus Date: Tue Dec 6 07:42:33 2011 New Revision: 1210808 URL: http://svn.apache.org/viewvc?rev=1210808&view=rev Log: CAMEL-4669: Added JMX opertions to clear content cache on ResourceEndpoint. Thanks to Rich Newcomb for the patch.
Added: camel/trunk/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedResourceEndpointMBean.java Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/component/ResourceEndpoint.java camel/trunk/components/camel-freemarker/src/main/java/org/apache/camel/component/freemarker/FreemarkerEndpoint.java camel/trunk/components/camel-freemarker/src/test/java/org/apache/camel/component/freemarker/FreemarkerContentCacheTest.java camel/trunk/components/camel-stringtemplate/src/test/java/org/apache/camel/component/stringtemplate/StringTemplateContentCacheTest.java camel/trunk/components/camel-velocity/src/test/java/org/apache/camel/component/velocity/VelocityContentCacheTest.java Added: camel/trunk/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedResourceEndpointMBean.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedResourceEndpointMBean.java?rev=1210808&view=auto ============================================================================== --- camel/trunk/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedResourceEndpointMBean.java (added) +++ camel/trunk/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedResourceEndpointMBean.java Tue Dec 6 07:42:33 2011 @@ -0,0 +1,33 @@ +/** + * 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 ManagedResourceEndpointMBean { + + @ManagedAttribute(description = "Whether the content is cached") + boolean isContentCache(); + + @ManagedAttribute(description = "Whether the content is cached") + void setContentCache(boolean contentCache); + + @ManagedOperation(description = "Clears the content cache") + void clearContentCache(); + +} Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/component/ResourceEndpoint.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/ResourceEndpoint.java?rev=1210808&r1=1210807&r2=1210808&view=diff ============================================================================== --- camel/trunk/camel-core/src/main/java/org/apache/camel/component/ResourceEndpoint.java (original) +++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/ResourceEndpoint.java Tue Dec 6 07:42:33 2011 @@ -21,6 +21,8 @@ import java.io.IOException; import java.io.InputStream; import org.apache.camel.Component; +import org.apache.camel.api.management.ManagedResource; +import org.apache.camel.api.management.mbean.ManagedResourceEndpointMBean; import org.apache.camel.converter.IOConverter; import org.apache.camel.impl.ProcessorEndpoint; import org.apache.camel.util.IOHelper; @@ -32,11 +34,12 @@ import org.slf4j.LoggerFactory; * A useful base class for endpoints which depend on a resource * such as things like Velocity or XQuery based components. */ -public abstract class ResourceEndpoint extends ProcessorEndpoint { +@ManagedResource(description = "Managed ResourceEndpoint") +public abstract class ResourceEndpoint extends ProcessorEndpoint implements ManagedResourceEndpointMBean { protected final transient Logger log = LoggerFactory.getLogger(getClass()); private String resourceUri; private boolean contentCache; - private byte[] buffer; + private volatile byte[] buffer; public ResourceEndpoint() { } @@ -58,7 +61,7 @@ public abstract class ResourceEndpoint e public InputStream getResourceAsInputStream() throws IOException { // try to get the resource input stream InputStream is; - if (contentCache) { + if (isContentCache()) { synchronized (this) { if (buffer == null) { log.debug("Reading resource: {} into the content cache", resourceUri); @@ -92,6 +95,11 @@ public abstract class ResourceEndpoint e public boolean isContentCache() { return contentCache; } + + public synchronized void clearContentCache() { + log.debug("Clearing resource: {} from the content cache", resourceUri); + buffer = null; + } /** * Sets whether to use resource content cache or not - default is <tt>false</tt>. Modified: camel/trunk/components/camel-freemarker/src/main/java/org/apache/camel/component/freemarker/FreemarkerEndpoint.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-freemarker/src/main/java/org/apache/camel/component/freemarker/FreemarkerEndpoint.java?rev=1210808&r1=1210807&r2=1210808&view=diff ============================================================================== --- camel/trunk/components/camel-freemarker/src/main/java/org/apache/camel/component/freemarker/FreemarkerEndpoint.java (original) +++ camel/trunk/components/camel-freemarker/src/main/java/org/apache/camel/component/freemarker/FreemarkerEndpoint.java Tue Dec 6 07:42:33 2011 @@ -89,6 +89,11 @@ public class FreemarkerEndpoint extends log.debug("Getting endpoint with URI: {}", newUri); return (FreemarkerEndpoint) getCamelContext().getEndpoint(newUri); } + + @Override + public void clearContentCache() { + configuration.clearTemplateCache(); + } @Override @SuppressWarnings("unchecked") Modified: camel/trunk/components/camel-freemarker/src/test/java/org/apache/camel/component/freemarker/FreemarkerContentCacheTest.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-freemarker/src/test/java/org/apache/camel/component/freemarker/FreemarkerContentCacheTest.java?rev=1210808&r1=1210807&r2=1210808&view=diff ============================================================================== --- camel/trunk/components/camel-freemarker/src/test/java/org/apache/camel/component/freemarker/FreemarkerContentCacheTest.java (original) +++ camel/trunk/components/camel-freemarker/src/test/java/org/apache/camel/component/freemarker/FreemarkerContentCacheTest.java Tue Dec 6 07:42:33 2011 @@ -16,6 +16,12 @@ */ package org.apache.camel.component.freemarker; +import java.util.ArrayList; +import java.util.Set; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + import org.apache.camel.Exchange; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.mock.MockEndpoint; @@ -27,6 +33,11 @@ import org.junit.Test; * Unit test the cache when reloading .ftl files in the classpath */ public class FreemarkerContentCacheTest extends CamelTestSupport { + + @Override + public boolean useJmx() { + return true; + } @Before public void setUp() throws Exception { @@ -102,6 +113,46 @@ public class FreemarkerContentCacheTest mock.assertIsSatisfied(); } + @Test + public void testClearCacheViaJmx() throws Exception { + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedBodiesReceived("Hello London"); + + template.sendBodyAndHeader("direct:b", "Body", "name", "London"); + mock.assertIsSatisfied(); + + // now change content in the file in the classpath and try again + template.sendBodyAndHeader("file://target/test-classes/org/apache/camel/component/freemarker?fileExist=Override", "Bye ${headers.name}", Exchange.FILE_NAME, "hello.ftl"); + + mock.reset(); + // we must expected the original filecontent as the cache is enabled, so its Hello and not Bye + mock.expectedBodiesReceived("Hello Paris"); + + template.sendBodyAndHeader("direct:b", "Body", "name", "Paris"); + mock.assertIsSatisfied(); + + // clear the cache via the mbean server + MBeanServer mbeanServer = context.getManagementStrategy().getManagementAgent().getMBeanServer(); + Set<ObjectName> objNameSet = mbeanServer.queryNames(new ObjectName("org.apache.camel:type=endpoints,name=\"freemarker:*contentCache=true*\",*"), null); + ObjectName managedObjName = new ArrayList<ObjectName>(objNameSet).get(0); + mbeanServer.invoke(managedObjName, "clearContentCache", null, null); + + // change content in the file in the classpath and try again + template.sendBodyAndHeader("file://target/test-classes/org/apache/camel/component/freemarker?fileExist=Override", "Bye ${headers.name}", Exchange.FILE_NAME, "hello.ftl"); + mock.reset(); + // we expect the updated file content because the cache was cleared + mock.expectedBodiesReceived("Bye Paris"); + template.sendBodyAndHeader("direct:b", "Body", "name", "Paris"); + mock.assertIsSatisfied(); + + // change content in the file in the classpath and try again to verify that the caching is still in effect after clearing the cache + template.sendBodyAndHeader("file://target/test-classes/org/apache/camel/component/freemarker?fileExist=Override", "Hello ${headers.name}", Exchange.FILE_NAME, "hello.ftl"); + mock.reset(); + // we expect the cached content from the prior update + mock.expectedBodiesReceived("Bye Paris"); + template.sendBodyAndHeader("direct:b", "Body", "name", "Paris"); + mock.assertIsSatisfied(); + } protected RouteBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { Modified: camel/trunk/components/camel-stringtemplate/src/test/java/org/apache/camel/component/stringtemplate/StringTemplateContentCacheTest.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-stringtemplate/src/test/java/org/apache/camel/component/stringtemplate/StringTemplateContentCacheTest.java?rev=1210808&r1=1210807&r2=1210808&view=diff ============================================================================== --- camel/trunk/components/camel-stringtemplate/src/test/java/org/apache/camel/component/stringtemplate/StringTemplateContentCacheTest.java (original) +++ camel/trunk/components/camel-stringtemplate/src/test/java/org/apache/camel/component/stringtemplate/StringTemplateContentCacheTest.java Tue Dec 6 07:42:33 2011 @@ -16,6 +16,12 @@ */ package org.apache.camel.component.stringtemplate; +import java.util.ArrayList; +import java.util.Set; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + import org.apache.camel.Exchange; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.mock.MockEndpoint; @@ -35,6 +41,11 @@ public class StringTemplateContentCacheT // create a tm file in the classpath as this is the tricky reloading stuff template.sendBodyAndHeader("file://target/test-classes/org/apache/camel/component/stringtemplate?fileExist=Override", "Hello $headers.name$", Exchange.FILE_NAME, "hello.tm"); } + + @Override + public boolean useJmx() { + return true; + } @Test public void testNotCached() throws Exception { @@ -72,6 +83,45 @@ public class StringTemplateContentCacheT template.sendBodyAndHeader("direct:b", "Body", "name", "Paris"); mock.assertIsSatisfied(); } + + @Test + public void testClearCacheViaJmx() throws Exception { + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedBodiesReceived("Hello London"); + + template.sendBodyAndHeader("direct:b", "Body", "name", "London"); + mock.assertIsSatisfied(); + + // now change content in the file in the classpath and try again + template.sendBodyAndHeader("file://target/test-classes/org/apache/camel/component/stringtemplate?fileExist=Override", "Bye $headers.name$", Exchange.FILE_NAME, "hello.tm"); + + mock.reset(); + // we must expected the original filecontent as the cache is enabled, so its Hello and not Bye + mock.expectedBodiesReceived("Hello Paris"); + + template.sendBodyAndHeader("direct:b", "Body", "name", "Paris"); + mock.assertIsSatisfied(); + + // clear the cache using jmx + MBeanServer mbeanServer = context.getManagementStrategy().getManagementAgent().getMBeanServer(); + Set<ObjectName> objNameSet = mbeanServer.queryNames(new ObjectName("org.apache.camel:type=endpoints,name=\"string-template:*contentCache=true*\",*"), null); + ObjectName managedObjName = new ArrayList<ObjectName>(objNameSet).get(0); + mbeanServer.invoke(managedObjName, "clearContentCache", null, null); + + mock.reset(); + // we expect that the new resource will be set as the cached value, since the cache has been cleared + mock.expectedBodiesReceived("Bye Paris"); + template.sendBodyAndHeader("file://target/test-classes/org/apache/camel/component/stringtemplate?fileExist=Override", "Bye $headers.name$", Exchange.FILE_NAME, "hello.tm"); + template.sendBodyAndHeader("direct:b", "Body", "name", "Paris"); + mock.assertIsSatisfied(); + + mock.reset(); + // we expect that the cached value will not be replaced by a different resource since the cache is now re-established + mock.expectedBodiesReceived("Bye Paris"); + template.sendBodyAndHeader("file://target/test-classes/org/apache/camel/component/stringtemplate?fileExist=Override", "Hello $headers.name$", Exchange.FILE_NAME, "hello.tm"); + template.sendBodyAndHeader("direct:b", "Body", "name", "Paris"); + mock.assertIsSatisfied(); + } protected RouteBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { Modified: camel/trunk/components/camel-velocity/src/test/java/org/apache/camel/component/velocity/VelocityContentCacheTest.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-velocity/src/test/java/org/apache/camel/component/velocity/VelocityContentCacheTest.java?rev=1210808&r1=1210807&r2=1210808&view=diff ============================================================================== --- camel/trunk/components/camel-velocity/src/test/java/org/apache/camel/component/velocity/VelocityContentCacheTest.java (original) +++ camel/trunk/components/camel-velocity/src/test/java/org/apache/camel/component/velocity/VelocityContentCacheTest.java Tue Dec 6 07:42:33 2011 @@ -16,6 +16,12 @@ */ package org.apache.camel.component.velocity; +import java.util.ArrayList; +import java.util.Set; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + import org.apache.camel.Exchange; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.mock.MockEndpoint; @@ -35,6 +41,11 @@ public class VelocityContentCacheTest ex // create a vm file in the classpath as this is the tricky reloading stuff template.sendBodyAndHeader("file://target/test-classes/org/apache/camel/component/velocity?fileExist=Override", "Hello $headers.name", Exchange.FILE_NAME, "hello.vm"); } + + @Override + public boolean useJmx() { + return true; + } @Test public void testNotCached() throws Exception { @@ -91,6 +102,49 @@ public class VelocityContentCacheTest ex template.sendBodyAndHeader("direct:c", "Body", "name", "Paris"); mock.assertIsSatisfied(); } + + @Test + public void testClearCacheViaJmx() throws Exception { + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedBodiesReceived("Hello London"); + + template.sendBodyAndHeader("direct:b", "Body", "name", "London"); + mock.assertIsSatisfied(); + + // now change content in the file in the classpath and try again + template.sendBodyAndHeader("file://target/test-classes/org/apache/camel/component/velocity?fileExist=Override", "Bye $headers.name", Exchange.FILE_NAME, "hello.vm"); + + mock.reset(); + // we must expected the original filecontent as the cache is enabled, so its Hello and not Bye + mock.expectedBodiesReceived("Hello Paris"); + + template.sendBodyAndHeader("direct:b", "Body", "name", "Paris"); + mock.assertIsSatisfied(); + + // clear the cache via the mbean server + MBeanServer mbeanServer = context.getManagementStrategy().getManagementAgent().getMBeanServer(); + Set<ObjectName> objNameSet = mbeanServer.queryNames(new ObjectName("org.apache.camel:type=endpoints,name=\"velocity:*contentCache=true*\",*"), null); + ObjectName managedObjName = new ArrayList<ObjectName>(objNameSet).get(0); + mbeanServer.invoke(managedObjName, "clearContentCache", null, null); + + // now change content in the file in the classpath + template.sendBodyAndHeader("file://target/test-classes/org/apache/camel/component/velocity?fileExist=Override", "Bye $headers.name", Exchange.FILE_NAME, "hello.vm"); + + mock.reset(); + // we expect the update to work now since the cache has been cleared + mock.expectedBodiesReceived("Bye Paris"); + template.sendBodyAndHeader("direct:b", "Body", "name", "Paris"); + mock.assertIsSatisfied(); + + // change the content in the file again + template.sendBodyAndHeader("file://target/test-classes/org/apache/camel/component/velocity?fileExist=Override", "Hello $headers.name", Exchange.FILE_NAME, "hello.vm"); + mock.reset(); + // we expect the new value to be ignored since the cache was re-established with the prior exchange + mock.expectedBodiesReceived("Bye Paris"); + template.sendBodyAndHeader("direct:b", "Body", "name", "Paris"); + mock.assertIsSatisfied(); + } + protected RouteBuilder createRouteBuilder() throws Exception { return new RouteBuilder() {