You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ni...@apache.org on 2010/04/17 04:20:12 UTC

svn commit: r935108 - in /camel/trunk: components/camel-jetty/ components/camel-jetty/src/main/java/org/apache/camel/component/jetty/ components/camel-jetty/src/test/java/org/apache/camel/component/jetty/ platforms/karaf/features/src/main/resources/ te...

Author: ningjiang
Date: Sat Apr 17 02:20:12 2010
New Revision: 935108

URL: http://svn.apache.org/viewvc?rev=935108&view=rev
Log:
CAMEL-2652 Allow camel-jetty to enable Jetty JMX extensions, Applied the patch with thanks to David

Added:
    camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyEnableJmxTest.java   (with props)
Modified:
    camel/trunk/components/camel-jetty/pom.xml
    camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
    camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpEndpoint.java
    camel/trunk/platforms/karaf/features/src/main/resources/features.xml
    camel/trunk/tests/camel-itest-karaf/pom.xml
    camel/trunk/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/AbstractFeatureTest.java

Modified: camel/trunk/components/camel-jetty/pom.xml
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jetty/pom.xml?rev=935108&r1=935107&r2=935108&view=diff
==============================================================================
--- camel/trunk/components/camel-jetty/pom.xml (original)
+++ camel/trunk/components/camel-jetty/pom.xml Sat Apr 17 02:20:12 2010
@@ -66,7 +66,11 @@
             <groupId>org.eclipse.jetty</groupId>
             <artifactId>jetty-client</artifactId>
         </dependency>
-
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-jmx</artifactId>
+            <version>${jetty-version}</version>
+        </dependency>
         <!-- testing -->
         <dependency>
             <groupId>org.apache.camel</groupId>

Modified: camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java?rev=935108&r1=935107&r2=935108&view=diff
==============================================================================
--- camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java (original)
+++ camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java Sat Apr 17 02:20:12 2010
@@ -21,6 +21,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import javax.management.MBeanServer;
+
 import org.apache.camel.CamelContext;
 import org.apache.camel.Endpoint;
 import org.apache.camel.RuntimeCamelException;
@@ -29,14 +31,16 @@ import org.apache.camel.component.http.H
 import org.apache.camel.component.http.HttpComponent;
 import org.apache.camel.component.http.HttpConsumer;
 import org.apache.camel.component.http.HttpEndpoint;
+import org.apache.camel.spi.ManagementAgent;
+import org.apache.camel.spi.ManagementStrategy;
 import org.apache.camel.util.CastUtils;
 import org.apache.camel.util.IntrospectionSupport;
 import org.apache.camel.util.URISupport;
-import org.apache.camel.util.UnsafeUriCharactersEncoder;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.eclipse.jetty.client.Address;
 import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.jmx.MBeanContainer;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.Server;
@@ -76,6 +80,7 @@ public class JettyHttpComponent extends 
     protected ThreadPool httpClientThreadPool;
     protected Integer httpClientMinThreads;
     protected Integer httpClientMaxThreads;
+    protected MBeanContainer mbContainer;
 
     class ConnectorRef {
         Server server;
@@ -110,6 +115,7 @@ public class JettyHttpComponent extends 
         Boolean throwExceptionOnFailure = getAndRemoveParameter(parameters, "throwExceptionOnFailure", Boolean.class);
         Boolean bridgeEndpoint = getAndRemoveParameter(parameters, "bridgeEndpoint", Boolean.class);
         Boolean matchOnUriPrefix = getAndRemoveParameter(parameters, "matchOnUriPrefix", Boolean.class);
+        Boolean enableJmx = getAndRemoveParameter(parameters, "enableJmx", Boolean.class);
 
         // configure http client if we have url configuration for it
         // http client is only used for jetty http producer (hence not very commonly used)
@@ -155,6 +161,10 @@ public class JettyHttpComponent extends 
         if (matchOnUriPrefix != null) {
             endpoint.setMatchOnUriPrefix(matchOnUriPrefix);
         }
+        
+        if (enableJmx != null) {
+            endpoint.setEnableJmx(enableJmx);
+        }
 
         setProperties(endpoint, parameters);
         return endpoint;
@@ -184,6 +194,9 @@ public class JettyHttpComponent extends 
                     LOG.warn("You use localhost interface! It means that no external connections will be available. Don't you want to use 0.0.0.0 instead (all network interfaces)?");
                 }
                 Server server = createServer();
+                if (endpoint.isEnableJmx()) {
+                    enableJmx(server);
+                }
                 server.addConnector(connector);
 
                 connectorRef = new ConnectorRef(server, connector, createServletForConnector(server, connector, endpoint.getHandlers()));
@@ -202,6 +215,16 @@ public class JettyHttpComponent extends 
             connectorRef.servlet.connect(consumer);
         }
     }
+    
+    private void enableJmx(Server server) {
+        MBeanContainer containerToRegister = getMbContainer();
+        if (containerToRegister != null) {
+            server.getContainer().addEventListener(containerToRegister);
+            // Since we may have many Servers running, don't tie the MBeanContainer
+            // to a Server lifecycle or we end up closing it while it is still in use.
+            //server.addBean(mbContainer);
+        }
+    }
 
     private void enableSessionSupport(Server server) throws Exception {
         ServletContextHandler context = (ServletContextHandler)server.getChildHandlerByClass(ServletContextHandler.class);
@@ -236,6 +259,13 @@ public class JettyHttpComponent extends 
                     connectorRef.connector.stop();
                     connectorRef.server.stop();
                     CONNECTORS.remove(connectorKey);
+                    // Camel controls the lifecycle of these entities so remove the
+                    // registered MBeans when Camel is done with the managed objects.
+                    MBeanContainer containerToClean = getMbContainer(); 
+                    if (containerToClean != null) {
+                        containerToClean.removeBean(connectorRef.server);
+                        containerToClean.removeBean(connectorRef.connector);
+                    }
                 }
             }
         }
@@ -379,6 +409,33 @@ public class JettyHttpComponent extends 
         this.httpClientMaxThreads = httpClientMaxThreads;
     }
 
+    public synchronized MBeanContainer getMbContainer() {
+        // If null, provide the default implementation.
+        if (mbContainer == null) {
+            MBeanServer mbs = null;
+            
+            final ManagementStrategy mStrategy = 
+                this.getCamelContext().getManagementStrategy();
+            final ManagementAgent mAgent = mStrategy.getManagementAgent();
+            if (mAgent != null) {
+                mbs = mAgent.getMBeanServer();
+            }
+            
+            if (mbs != null) {
+                mbContainer = new MBeanContainer(mbs);
+                startMbContainer();
+            } else {
+                LOG.warn("JMX disabled in Camel Context.  The Camel Context takes precedent and JMX will not be enabled in Jetty.");
+            }
+        }
+        
+        return this.mbContainer;
+    }
+
+    public void setMbContainer(MBeanContainer mbContainer) {
+        this.mbContainer = mbContainer;
+    }
+
     // Implementation methods
     // -------------------------------------------------------------------------
     protected CamelServlet createServletForConnector(Server server, Connector connector, List<Handler> handlers) throws Exception {
@@ -422,6 +479,25 @@ public class JettyHttpComponent extends 
         server.setHandler(collection);
         return server;
     }
+    
+    /**
+     * Starts {@link #mbContainer} and registers the
+     * container with itself as a managed bean logging an error
+     * if there is a problem starting the container.  Does nothing
+     * if {@link #mbContainer} is {@code null}.
+     */
+    protected void startMbContainer() {
+        if (mbContainer != null && !mbContainer.isStarted()) {
+            try {
+                mbContainer.start();
+                // Publish the container itself for consistency with
+                // traditional embedded Jetty configurations.
+                mbContainer.addBean(mbContainer);
+            } catch (Exception e) {
+                LOG.fatal("Could not start Jetty MBeanContainer.  Jetty JMX extensions will remain disabled.", e);
+            }
+        }
+    }
 
     @Override
     protected void doStart() throws Exception {
@@ -433,6 +509,8 @@ public class JettyHttpComponent extends 
         if (httpClient != null && !httpClient.isStarted()) {
             httpClient.start();
         }
+        
+        startMbContainer();
     }
 
     @Override
@@ -442,7 +520,14 @@ public class JettyHttpComponent extends 
             for (ConnectorRef connectorRef : CONNECTORS.values()) {
                 connectorRef.server.removeConnector(connectorRef.connector);
                 connectorRef.connector.stop();
-                connectorRef.server.stop();                
+                connectorRef.server.stop();
+                // Camel controls the lifecycle of these entities so remove the
+                // registered MBeans when Camel is done with the managed objects.
+                MBeanContainer containerToClean = getMbContainer(); 
+                if (containerToClean != null) {
+                    containerToClean.removeBean(connectorRef.server);
+                    containerToClean.removeBean(connectorRef.connector);
+                }
             }
             CONNECTORS.clear();
         }
@@ -453,5 +538,8 @@ public class JettyHttpComponent extends 
             LifeCycle lc = (LifeCycle) httpClientThreadPool;
             lc.stop();
         }
+        if (mbContainer != null) {
+            mbContainer.stop();
+        }
     }
 }
\ No newline at end of file

Modified: camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpEndpoint.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpEndpoint.java?rev=935108&r1=935107&r2=935108&view=diff
==============================================================================
--- camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpEndpoint.java (original)
+++ camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpEndpoint.java Sat Apr 17 02:20:12 2010
@@ -37,6 +37,7 @@ public class JettyHttpEndpoint extends H
     private List<Handler> handlers;
     private HttpClient client;
     private JettyHttpBinding jettyBinding;
+    private boolean enableJmx;
 
     public JettyHttpEndpoint(JettyHttpComponent component, String uri, URI httpURL) throws URISyntaxException {
         super(uri, component, httpURL);
@@ -98,4 +99,12 @@ public class JettyHttpEndpoint extends H
     public void setJettyBinding(JettyHttpBinding jettyBinding) {
         this.jettyBinding = jettyBinding;
     }
+
+    public boolean isEnableJmx() {
+        return this.enableJmx;
+    }
+
+    public void setEnableJmx(boolean enableJmx) {
+        this.enableJmx = enableJmx;
+    }
 }

Added: camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyEnableJmxTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyEnableJmxTest.java?rev=935108&view=auto
==============================================================================
--- camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyEnableJmxTest.java (added)
+++ camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyEnableJmxTest.java Sat Apr 17 02:20:12 2010
@@ -0,0 +1,159 @@
+/**
+ * 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.component.jetty;
+
+import java.lang.management.ManagementFactory;
+import java.util.List;
+import java.util.Set;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+
+
+public class JettyEnableJmxTest  extends CamelTestSupport {
+    
+    private String serverUri0 = 
+        "http://localhost:9080/myservice?enableJmx=true";
+    private String serverUri1 = 
+        "http://localhost:9081/myservice?enableJmx=true";
+    private String serverUri2 = 
+        "http://localhost:9082/myservice?enableJmx=false";
+    private String serverUri3 = 
+        "http://localhost:9083/myservice?enableJmx=false";
+    private MBeanServerConnection mbsc;
+
+    @Override
+    public void tearDown() throws Exception {
+        releaseMBeanServers();
+        mbsc = null;
+        super.tearDown();
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        releaseMBeanServers();
+        super.setUp();
+        mbsc = getMBeanConnection();
+    }
+    
+    @Test
+    public void testEnableJmxProperty() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        String expectedBody = "<html><body>foo</body></html>";
+        mock.expectedBodiesReceived(
+                expectedBody, expectedBody, expectedBody, expectedBody);
+        mock.expectedHeaderReceived("x", "foo");
+
+        template.requestBody(serverUri0 + "&x=foo", null, Object.class);
+        template.requestBody(serverUri1 + "&x=foo", null, Object.class);
+        template.requestBody(serverUri2 + "&x=foo", null, Object.class);
+        template.requestBody(serverUri3 + "&x=foo", null, Object.class);
+
+        assertMockEndpointsSatisfied();
+        
+        Set<ObjectName> s = mbsc.queryNames(new ObjectName("org.eclipse.jetty.server:type=server,*"), null);
+        assertEquals("Could not find 2 Jetty Server: " + s, 2, s.size());
+    }
+    
+    @Test
+    public void testShutdown() throws Exception {
+        Set<ObjectName> s = mbsc.queryNames(new ObjectName("org.eclipse.jetty.server:type=server,*"), null);
+        assertEquals("Could not find 2 Jetty Server: " + s, 2, s.size());
+        
+        context.stop();
+        
+        s = mbsc.queryNames(new ObjectName("org.eclipse.jetty.server:type=server,*"), null);
+        assertEquals("Could not find 0 Jetty Server: " + s, 0, s.size());
+    }
+    
+    @Test
+    public void testEndpointDisconnect() throws Exception {
+        Set<ObjectName> s = mbsc.queryNames(new ObjectName("org.eclipse.jetty.server:type=server,*"), null);
+        assertEquals("Could not find 2 Jetty Server: " + s, 2, s.size());
+        
+        context.stopRoute("route0");
+        
+        s = mbsc.queryNames(new ObjectName("org.eclipse.jetty.server:type=server,*"), null);
+        assertEquals("Could not find 1 Jetty Server: " + s, 1, s.size());
+        
+        context.stopRoute("route2");
+        context.stopRoute("route3");
+        
+        s = mbsc.queryNames(new ObjectName("org.eclipse.jetty.server:type=server,*"), null);
+        assertEquals("Could not find 1 Jetty Server: " + s, 1, s.size());
+        
+        context.stopRoute("route1");
+        
+        s = mbsc.queryNames(new ObjectName("org.eclipse.jetty.server:type=server,*"), null);
+        assertEquals("Could not find 0 Jetty Server: " + s, 0, s.size());
+    }
+
+    @Override
+    protected boolean useJmx() {
+        return true;
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() throws Exception {
+                from("jetty:" + serverUri0)
+                    .routeId("route0")
+                    .setBody().simple("<html><body>${in.header.x}</body></html>")
+                    .to("mock:result");
+                
+                from("jetty:" + serverUri1)
+                    .routeId("route1")
+                    .setBody().simple("<html><body>${in.header.x}</body></html>")
+                    .to("mock:result");
+                
+                from("jetty:" + serverUri2)
+                    .routeId("route2")
+                    .setBody().simple("<html><body>${in.header.x}</body></html>")
+                    .to("mock:result");
+                
+                from("jetty:" + serverUri3)
+                    .routeId("route3")
+                    .setBody().simple("<html><body>${in.header.x}</body></html>")
+                    .to("mock:result");
+            }
+        };
+    }
+    
+    protected void releaseMBeanServers() {
+        List<MBeanServer> servers =
+            (List<MBeanServer>)MBeanServerFactory.findMBeanServer(null);
+
+        for (MBeanServer server : servers) {
+            MBeanServerFactory.releaseMBeanServer(server);
+        }
+    }
+    
+    protected MBeanServerConnection getMBeanConnection() throws Exception {
+        if (mbsc == null) {
+            mbsc = ManagementFactory.getPlatformMBeanServer();
+        }
+        return mbsc;
+    }
+}

Propchange: camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyEnableJmxTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyEnableJmxTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: camel/trunk/platforms/karaf/features/src/main/resources/features.xml
URL: http://svn.apache.org/viewvc/camel/trunk/platforms/karaf/features/src/main/resources/features.xml?rev=935108&r1=935107&r2=935108&view=diff
==============================================================================
--- camel/trunk/platforms/karaf/features/src/main/resources/features.xml (original)
+++ camel/trunk/platforms/karaf/features/src/main/resources/features.xml Sat Apr 17 02:20:12 2010
@@ -119,10 +119,13 @@
     <bundle>mvn:org.eclipse.jetty/jetty-http/${jetty-bundle-version}</bundle>
     <bundle>mvn:org.eclipse.jetty/jetty-client/${jetty-bundle-version}</bundle>
     <bundle>mvn:org.eclipse.jetty/jetty-continuation/${jetty-bundle-version}</bundle>
+    <bundle>mvn:org.eclipse.jetty/jetty-jmx/${jetty-bundle-version}</bundle>
     <bundle>mvn:org.eclipse.jetty/jetty-server/${jetty-bundle-version}</bundle>
     <bundle>mvn:org.eclipse.jetty/jetty-security/${jetty-bundle-version}</bundle>
     <bundle>mvn:org.eclipse.jetty/jetty-servlet/${jetty-bundle-version}</bundle>
     <bundle>mvn:org.eclipse.jetty/jetty-servlets/${jetty-bundle-version}</bundle>
+    <bundle>mvn:org.eclipse.jetty/jetty-xml/${jetty-bundle-version}</bundle>
+    <bundle>mvn:org.eclipse.jetty/jetty-webapp/${jetty-bundle-version}</bundle>
     <feature version='${pom.version}'>camel-core</feature>
     <feature version='${pom.version}'>camel-http</feature>
     <bundle>mvn:org.apache.camel/camel-jetty/${pom.version}</bundle>

Modified: camel/trunk/tests/camel-itest-karaf/pom.xml
URL: http://svn.apache.org/viewvc/camel/trunk/tests/camel-itest-karaf/pom.xml?rev=935108&r1=935107&r2=935108&view=diff
==============================================================================
--- camel/trunk/tests/camel-itest-karaf/pom.xml (original)
+++ camel/trunk/tests/camel-itest-karaf/pom.xml Sat Apr 17 02:20:12 2010
@@ -104,6 +104,7 @@
       <plugin>
         <groupId>org.apache.servicemix.tooling</groupId>
         <artifactId>depends-maven-plugin</artifactId>
+        <version>1.2</version>
         <executions>
           <execution>
             <id>generate-depends-file</id>

Modified: camel/trunk/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/AbstractFeatureTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/AbstractFeatureTest.java?rev=935108&r1=935107&r2=935108&view=diff
==============================================================================
--- camel/trunk/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/AbstractFeatureTest.java (original)
+++ camel/trunk/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/AbstractFeatureTest.java Sat Apr 17 02:20:12 2010
@@ -159,7 +159,7 @@ public abstract class AbstractFeatureTes
 
             scanFeatures(mavenBundle().groupId("org.apache.camel.karaf").
                          artifactId("apache-camel").versionAsInProject().type("xml/features"),
-                          "camel-osgi", "camel-" + feature),
+                          "camel-spring-osgi", "camel-" + feature),
                           //cleanCaches(),
 
             felix());