You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by dh...@apache.org on 2015/03/24 22:26:39 UTC
camel git commit: CAMEL-8543: Added support for configuring
Salesforce HTTP client, HTTP proxy, added HTTP proxy integration tests
Repository: camel
Updated Branches:
refs/heads/master 22f59a3ea -> 9f0e167b8
CAMEL-8543: Added support for configuring Salesforce HTTP client, HTTP proxy, added HTTP proxy integration tests
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/9f0e167b
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/9f0e167b
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/9f0e167b
Branch: refs/heads/master
Commit: 9f0e167b8306e4d15e43a0ec66916085f88e08dd
Parents: 22f59a3
Author: Dhiraj Bokde <dh...@yahoo.com>
Authored: Tue Mar 24 14:26:09 2015 -0700
Committer: Dhiraj Bokde <dh...@yahoo.com>
Committed: Tue Mar 24 14:26:34 2015 -0700
----------------------------------------------------------------------
.../camel-salesforce-component/pom.xml | 6 +
.../salesforce/SalesforceComponent.java | 99 ++++++-
.../salesforce/SalesforceEndpoint.java | 36 +++
.../salesforce/SalesforceEndpointConfig.java | 2 +-
.../salesforce/AbstractSalesforceTestBase.java | 4 +-
.../salesforce/HttpProxyIntegrationTest.java | 154 ++++++++++
.../camel-salesforce-maven-plugin/pom.xml | 6 +
.../src/it/simple-it/pom.xml | 14 +
.../apache/camel/maven/CamelSalesforceMojo.java | 297 +++++++++++++------
.../CamelSalesforceMojoIntegrationTest.java | 23 +-
.../maven/HttpProxyMojoIntegrationTest.java | 110 +++++++
11 files changed, 631 insertions(+), 120 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/9f0e167b/components/camel-salesforce/camel-salesforce-component/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/pom.xml b/components/camel-salesforce/camel-salesforce-component/pom.xml
index 7ff091f..1be59f0 100644
--- a/components/camel-salesforce/camel-salesforce-component/pom.xml
+++ b/components/camel-salesforce/camel-salesforce-component/pom.xml
@@ -114,6 +114,12 @@
<artifactId>camel-test</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-server</artifactId>
+ <version>${jetty-version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
http://git-wip-us.apache.org/repos/asf/camel/blob/9f0e167b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java
index c12edc2..8d43b70 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java
@@ -38,12 +38,15 @@ import org.apache.camel.component.salesforce.internal.SalesforceSession;
import org.apache.camel.component.salesforce.internal.streaming.SubscriptionHelper;
import org.apache.camel.impl.UriEndpointComponent;
import org.apache.camel.spi.EndpointCompleter;
+import org.apache.camel.util.IntrospectionSupport;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.ReflectionHelper;
import org.apache.camel.util.ServiceHelper;
import org.apache.camel.util.jsse.SSLContextParameters;
+import org.eclipse.jetty.client.Address;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.RedirectListener;
+import org.eclipse.jetty.client.security.ProxyAuthorization;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,16 +58,29 @@ public class SalesforceComponent extends UriEndpointComponent implements Endpoin
private static final Logger LOG = LoggerFactory.getLogger(SalesforceComponent.class);
- private static final int MAX_CONNECTIONS_PER_ADDRESS = 20;
private static final int CONNECTION_TIMEOUT = 60000;
- private static final int RESPONSE_TIMEOUT = 60000;
+ private static final long RESPONSE_TIMEOUT = 60000;
private static final Pattern SOBJECT_NAME_PATTERN = Pattern.compile("^.*[\\?&]sObjectName=([^&,]+).*$");
private static final String APEX_CALL_PREFIX = OperationName.APEX_CALL.value() + "/";
private SalesforceLoginConfig loginConfig;
private SalesforceEndpointConfig config;
+ // HTTP client parameters, map of property-name to value
+ private Map<String, Object> httpClientProperties;
+
+ // SSL parameters
private SSLContextParameters sslContextParameters;
+
+ // Proxy host and port
+ private String httpProxyHost;
+ private Integer httpProxyPort;
+
+ // Proxy basic authentication
+ private String httpProxyUsername;
+ private String httpProxyPassword;
+
+ // DTO packages to scan
private String[] packages;
// component state
@@ -127,10 +143,12 @@ public class SalesforceComponent extends UriEndpointComponent implements Endpoin
// if operation is APEX call, map remaining parameters to query params
if (operationName == OperationName.APEX_CALL && !parameters.isEmpty()) {
- Map<String, Object> queryParams = new HashMap<String, Object>(parameters);
+ Map<String, Object> queryParams = new HashMap<String, Object>(copy.getApexQueryParams());
+
+ // override component params with endpoint params
+ queryParams.putAll(parameters);
parameters.clear();
- queryParams.putAll(copy.getApexQueryParams());
copy.setApexQueryParams(queryParams);
}
@@ -161,18 +179,34 @@ public class SalesforceComponent extends UriEndpointComponent implements Endpoin
if (config != null && config.getHttpClient() != null) {
httpClient = config.getHttpClient();
} else {
- final SslContextFactory sslContextFactory = new SslContextFactory();
- final SSLContextParameters contextParameters =
- sslContextParameters != null ? sslContextParameters : new SSLContextParameters();
- sslContextFactory.setSslContext(contextParameters.createSSLContext());
- httpClient = new HttpClient(sslContextFactory);
+ httpClient = new HttpClient();
+ // default settings
httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
- httpClient.setMaxConnectionsPerAddress(MAX_CONNECTIONS_PER_ADDRESS);
httpClient.setConnectTimeout(CONNECTION_TIMEOUT);
httpClient.setTimeout(RESPONSE_TIMEOUT);
}
}
+ // set ssl context parameters
+ final SSLContextParameters contextParameters = sslContextParameters != null
+ ? sslContextParameters : new SSLContextParameters();
+ final SslContextFactory sslContextFactory = httpClient.getSslContextFactory();
+ sslContextFactory.setSslContext(contextParameters.createSSLContext());
+
+ // set HTTP client parameters
+ if (httpClientProperties != null && !httpClientProperties.isEmpty()) {
+ IntrospectionSupport.setProperties(getCamelContext().getTypeConverter(),
+ httpClient, new HashMap<String, Object>(httpClientProperties));
+ }
+
+ // set HTTP proxy settings
+ if (this.httpProxyHost != null && httpProxyPort != null) {
+ httpClient.setProxy(new Address(this.httpProxyHost, this.httpProxyPort));
+ }
+ if (this.httpProxyUsername != null && httpProxyPassword != null) {
+ httpClient.setProxyAuthentication(new ProxyAuthorization(this.httpProxyUsername, this.httpProxyPassword));
+ }
+
// add redirect listener to handle Salesforce redirects
// this is ok to do since the RedirectListener is in the same classloader as Jetty client
String listenerClass = RedirectListener.class.getName();
@@ -235,7 +269,10 @@ public class SalesforceComponent extends UriEndpointComponent implements Endpoin
if (httpClient != null) {
// shutdown http client connections
httpClient.stop();
- httpClient.destroy();
+ // destroy http client if it was created by the component
+ if (config.getHttpClient() == null) {
+ httpClient.destroy();
+ }
httpClient = null;
}
}
@@ -332,6 +369,14 @@ public class SalesforceComponent extends UriEndpointComponent implements Endpoin
this.config = config;
}
+ public Map<String, Object> getHttpClientProperties() {
+ return httpClientProperties;
+ }
+
+ public void setHttpClientProperties(Map<String, Object> httpClientProperties) {
+ this.httpClientProperties = httpClientProperties;
+ }
+
public SSLContextParameters getSslContextParameters() {
return sslContextParameters;
}
@@ -340,6 +385,38 @@ public class SalesforceComponent extends UriEndpointComponent implements Endpoin
this.sslContextParameters = sslContextParameters;
}
+ public String getHttpProxyHost() {
+ return httpProxyHost;
+ }
+
+ public void setHttpProxyHost(String httpProxyHost) {
+ this.httpProxyHost = httpProxyHost;
+ }
+
+ public Integer getHttpProxyPort() {
+ return httpProxyPort;
+ }
+
+ public void setHttpProxyPort(Integer httpProxyPort) {
+ this.httpProxyPort = httpProxyPort;
+ }
+
+ public String getHttpProxyUsername() {
+ return httpProxyUsername;
+ }
+
+ public void setHttpProxyUsername(String httpProxyUsername) {
+ this.httpProxyUsername = httpProxyUsername;
+ }
+
+ public String getHttpProxyPassword() {
+ return httpProxyPassword;
+ }
+
+ public void setHttpProxyPassword(String httpProxyPassword) {
+ this.httpProxyPassword = httpProxyPassword;
+ }
+
public String[] getPackages() {
return packages;
}
http://git-wip-us.apache.org/repos/asf/camel/blob/9f0e167b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpoint.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpoint.java
index 27e28f2..85d11c7 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpoint.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpoint.java
@@ -25,6 +25,9 @@ import org.apache.camel.impl.SynchronousDelegateProducer;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
import org.apache.camel.spi.UriPath;
+import org.eclipse.jetty.client.HttpClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Represents a Salesforce endpoint.
@@ -32,6 +35,8 @@ import org.apache.camel.spi.UriPath;
@UriEndpoint(scheme = "salesforce", syntax = "salesforce:operationName:topicName", consumerClass = SalesforceConsumer.class)
public class SalesforceEndpoint extends DefaultEndpoint {
+ private static final Logger LOG = LoggerFactory.getLogger(SalesforceEndpoint.class);
+
@UriPath
private final OperationName operationName;
@UriPath
@@ -98,4 +103,35 @@ public class SalesforceEndpoint extends DefaultEndpoint {
return topicName;
}
+ @Override
+ protected void doStart() throws Exception {
+ try {
+ super.doStart();
+ } finally {
+ // check if this endpoint has its own http client that needs to be started
+ final HttpClient httpClient = getConfiguration().getHttpClient();
+ if (httpClient != null && getComponent().getConfig().getHttpClient() != httpClient) {
+ final String endpointUri = getEndpointUri();
+ LOG.debug("Starting http client for {} ...", endpointUri);
+ httpClient.start();
+ LOG.debug("Started http client for {}", endpointUri);
+ }
+ }
+ }
+
+ @Override
+ protected void doStop() throws Exception {
+ try {
+ super.doStop();
+ } finally {
+ // check if this endpoint has its own http client that needs to be stopped
+ final HttpClient httpClient = getConfiguration().getHttpClient();
+ if (httpClient != null && getComponent().getConfig().getHttpClient() != httpClient) {
+ final String endpointUri = getEndpointUri();
+ LOG.debug("Stopping http client for {} ...", endpointUri);
+ httpClient.stop();
+ LOG.debug("Stopped http client for {}", endpointUri);
+ }
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/9f0e167b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpointConfig.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpointConfig.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpointConfig.java
index 9af05b9..39b860a 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpointConfig.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpointConfig.java
@@ -129,7 +129,7 @@ public class SalesforceEndpointConfig implements Cloneable {
public SalesforceEndpointConfig copy() {
try {
final SalesforceEndpointConfig copy = (SalesforceEndpointConfig) super.clone();
- // nothing to deep copy
+ // nothing to deep copy, getApexQueryParams() is readonly, so no need to deep copy
return copy;
} catch (CloneNotSupportedException ex) {
throw new RuntimeCamelException(ex);
http://git-wip-us.apache.org/repos/asf/camel/blob/9f0e167b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/AbstractSalesforceTestBase.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/AbstractSalesforceTestBase.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/AbstractSalesforceTestBase.java
index 52d1d65..f05bbf9 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/AbstractSalesforceTestBase.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/AbstractSalesforceTestBase.java
@@ -16,8 +16,6 @@
*/
package org.apache.camel.component.salesforce;
-import java.io.IOException;
-
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.salesforce.dto.generated.Merchandise__c;
import org.apache.camel.test.junit4.CamelTestSupport;
@@ -40,7 +38,7 @@ public abstract class AbstractSalesforceTestBase extends CamelTestSupport {
protected abstract RouteBuilder doCreateRouteBuilder() throws Exception;
- protected void createComponent() throws IllegalAccessException, IOException {
+ protected void createComponent() throws Exception {
// create the component
SalesforceComponent component = new SalesforceComponent();
final SalesforceEndpointConfig config = new SalesforceEndpointConfig();
http://git-wip-us.apache.org/repos/asf/camel/blob/9f0e167b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/HttpProxyIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/HttpProxyIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/HttpProxyIntegrationTest.java
new file mode 100644
index 0000000..7b237cd
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/HttpProxyIntegrationTest.java
@@ -0,0 +1,154 @@
+/**
+ * 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.salesforce;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.salesforce.api.dto.Version;
+import org.apache.camel.component.salesforce.api.dto.Versions;
+import org.eclipse.jetty.http.HttpHeaders;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.ConnectHandler;
+import org.eclipse.jetty.server.nio.SelectChannelConnector;
+import org.eclipse.jetty.util.B64Code;
+import org.eclipse.jetty.util.StringUtil;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test HTTP proxy configuration for Salesforce component.
+ */
+public class HttpProxyIntegrationTest extends AbstractSalesforceTestBase {
+
+ private static final Logger LOG = LoggerFactory.getLogger(HttpProxyIntegrationTest.class);
+ private static final String HTTP_PROXY_HOST = "localhost";
+ private static final String HTTP_PROXY_USER_NAME = "camel-user";
+ private static final String HTTP_PROXY_PASSWORD = "camel-user-password";
+
+ private static Server server;
+ private static int httpProxyPort;
+
+ @Test
+ public void testGetVersions() throws Exception {
+ doTestGetVersions("");
+ doTestGetVersions("Xml");
+ }
+
+ @SuppressWarnings("unchecked")
+ private void doTestGetVersions(String suffix) throws Exception {
+ // test getVersions doesn't need a body
+ // assert expected result
+ Object o = template().requestBody("direct:getVersions" + suffix, (Object) null);
+ List<Version> versions = null;
+ if (o instanceof Versions) {
+ versions = ((Versions) o).getVersions();
+ } else {
+ versions = (List<Version>) o;
+ }
+ assertNotNull(versions);
+ LOG.debug("Versions: {}", versions);
+ }
+
+ @BeforeClass
+ public static void setupServer() throws Exception {
+ // start a local HTTP proxy using Jetty server
+ server = new Server();
+
+ Connector connector = new SelectChannelConnector();
+ connector.setHost(HTTP_PROXY_HOST);
+ server.setConnectors(new Connector[]{connector});
+
+ final String authenticationString = "Basic "
+ + B64Code.encode(HTTP_PROXY_USER_NAME + ":" + HTTP_PROXY_PASSWORD, StringUtil.__ISO_8859_1);
+
+ ConnectHandler handler = new ConnectHandler() {
+ @Override
+ protected boolean handleAuthentication(HttpServletRequest request, HttpServletResponse response, String address) throws ServletException, IOException {
+ // validate proxy-authentication header
+ final String header = request.getHeader(HttpHeaders.PROXY_AUTHORIZATION);
+ if (!authenticationString.equals(header)) {
+ throw new ServletException("Missing header " + HttpHeaders.PROXY_AUTHORIZATION);
+ }
+ LOG.info("CONNECT exchange contains required header " + HttpHeaders.PROXY_AUTHORIZATION);
+ return super.handleAuthentication(request, response, address);
+ }
+ };
+ server.setHandler(handler);
+
+ LOG.info("Starting proxy server...");
+ server.start();
+
+ httpProxyPort = connector.getLocalPort();
+ LOG.info("Started proxy server on port {}", httpProxyPort);
+ }
+
+ @Override
+ protected void createComponent() throws Exception {
+
+ super.createComponent();
+ final SalesforceComponent salesforce = (SalesforceComponent) context().getComponent("salesforce");
+
+ // set HTTP proxy settings
+ salesforce.setHttpProxyHost(HTTP_PROXY_HOST);
+ salesforce.setHttpProxyPort(httpProxyPort);
+ salesforce.setHttpProxyUsername(HTTP_PROXY_USER_NAME);
+ salesforce.setHttpProxyPassword(HTTP_PROXY_PASSWORD);
+
+ // set HTTP client properties
+ final HashMap<String, Object> properties = new HashMap<String, Object>();
+ properties.put("timeout", "60000");
+ properties.put("removeIdleDestinations", "true");
+ salesforce.setHttpClientProperties(properties);
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ AbstractSalesforceTestBase.tearDownAfterClass();
+ // stop the proxy server after component
+ LOG.info("Stopping proxy server...");
+ server.stop();
+ LOG.info("Stopped proxy server");
+ }
+
+ @Override
+ protected RouteBuilder doCreateRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+
+ // testGetVersion
+ from("direct:getVersions")
+ .to("salesforce:getVersions");
+
+ // allow overriding format per endpoint
+ from("direct:getVersionsXml")
+ .to("salesforce:getVersions?format=XML");
+
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/9f0e167b/components/camel-salesforce/camel-salesforce-maven-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/pom.xml b/components/camel-salesforce/camel-salesforce-maven-plugin/pom.xml
index 1f22d6a..cad281b 100644
--- a/components/camel-salesforce/camel-salesforce-maven-plugin/pom.xml
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/pom.xml
@@ -75,6 +75,12 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-server</artifactId>
+ <version>${jetty-version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j-api-version}</version>
http://git-wip-us.apache.org/repos/asf/camel/blob/9f0e167b/components/camel-salesforce/camel-salesforce-maven-plugin/src/it/simple-it/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/it/simple-it/pom.xml b/components/camel-salesforce/camel-salesforce-maven-plugin/src/it/simple-it/pom.xml
index 0f24037..b025aad 100644
--- a/components/camel-salesforce/camel-salesforce-maven-plugin/src/it/simple-it/pom.xml
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/it/simple-it/pom.xml
@@ -61,6 +61,20 @@
<goal>generate</goal>
</goals>
<configuration>
+ <httpClientProperties>
+ <timeout>60000</timeout>
+ <maxConnectionsPerAddress>10</maxConnectionsPerAddress>
+ <removeIdleDestinations>true</removeIdleDestinations>
+ </httpClientProperties>
+ <sslContextParameters>
+ <clientParameters>
+ <cipherSuitesFilter>
+ <exclude>
+ <exclude>SSL.*</exclude>
+ </exclude>
+ </cipherSuitesFilter>
+ </clientParameters>
+ </sslContextParameters>
<includePattern>(.*__c)</includePattern>
<!-- Salesforce login info -->
<clientId>${clientId}</clientId>
http://git-wip-us.apache.org/repos/asf/camel/blob/9f0e167b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
index d517f24..372b6e4 100644
--- a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
@@ -21,6 +21,7 @@ import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
+import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -49,6 +50,9 @@ import org.apache.camel.component.salesforce.internal.SalesforceSession;
import org.apache.camel.component.salesforce.internal.client.DefaultRestClient;
import org.apache.camel.component.salesforce.internal.client.RestClient;
import org.apache.camel.component.salesforce.internal.client.SyncResponseCallback;
+import org.apache.camel.util.IntrospectionSupport;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.jsse.SSLContextParameters;
import org.apache.log4j.Logger;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
@@ -62,105 +66,148 @@ import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.log.Log4JLogChute;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.codehaus.jackson.map.ObjectMapper;
+import org.eclipse.jetty.client.Address;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.RedirectListener;
+import org.eclipse.jetty.client.security.ProxyAuthorization;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
/**
- * Goal which generates POJOs for Salesforce SObjects
+ * Goal to generate DTOs for Salesforce SObjects
*/
@Mojo(name = "generate", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
public class CamelSalesforceMojo extends AbstractMojo {
+
+ // default connect and call timeout
+ protected static final int DEFAULT_TIMEOUT = 60000;
+
private static final String JAVA_EXT = ".java";
private static final String PACKAGE_NAME_PATTERN = "^[a-z]+(\\.[a-z][a-z0-9]*)*$";
+
private static final String SOBJECT_POJO_VM = "/sobject-pojo.vm";
private static final String SOBJECT_QUERY_RECORDS_VM = "/sobject-query-records.vm";
private static final String SOBJECT_PICKLIST_VM = "/sobject-picklist.vm";
// used for velocity logging, to avoid creating velocity.log
private static final Logger LOG = Logger.getLogger(CamelSalesforceMojo.class.getName());
- private static final int TIMEOUT = 60000;
/**
- * Salesforce client id
+ * HTTP client properties.
+ */
+ @Parameter
+ protected Map<String, Object> httpClientProperties;
+
+ /**
+ * SSL Context parameters.
+ */
+ @Parameter(property = "camelSalesforce.sslContextParameters")
+ protected SSLContextParameters sslContextParameters;
+
+ /**
+ * HTTP Proxy host.
+ */
+ @Parameter(property = "camelSalesforce.httpProxyHost")
+ protected String httpProxyHost;
+
+ /**
+ * HTTP Proxy port.
+ */
+ @Parameter(property = "camelSalesforce.httpProxyPort")
+ protected Integer httpProxyPort;
+
+ /**
+ * Proxy authentication username.
+ */
+ @Parameter(property = "camelSalesforce.httpProxyUsername")
+ protected String httpProxyUsername;
+
+ /**
+ * Proxy authentication password.
+ */
+ @Parameter(property = "camelSalesforce.httpProxyPassword")
+ protected String httpProxyPassword;
+
+ /**
+ * Salesforce client id.
*/
@Parameter(property = "camelSalesforce.clientId", required = true)
protected String clientId;
/**
- * Salesforce client secret
+ * Salesforce client secret.
*/
@Parameter(property = "camelSalesforce.clientSecret", required = true)
protected String clientSecret;
/**
- * Salesforce user name
+ * Salesforce username.
*/
@Parameter(property = "camelSalesforce.userName", required = true)
protected String userName;
/**
- * Salesforce password
+ * Salesforce password.
*/
@Parameter(property = "camelSalesforce.password", required = true)
protected String password;
/**
- * Salesforce version
+ * Salesforce API version.
*/
@Parameter(property = "camelSalesforce.version", defaultValue = SalesforceEndpointConfig.DEFAULT_VERSION)
protected String version;
/**
- * Location of the file.
+ * Location of generated DTO files, defaults to target/generated-sources/camel-salesforce.
*/
@Parameter(property = "camelSalesforce.outputDirectory",
defaultValue = "${project.build.directory}/generated-sources/camel-salesforce")
protected File outputDirectory;
/**
- * Salesforce URL.
+ * Salesforce login URL, defaults to https://login.salesforce.com.
*/
@Parameter(property = "camelSalesforce.loginUrl", defaultValue = SalesforceLoginConfig.DEFAULT_LOGIN_URL)
protected String loginUrl;
/**
- * Names of Salesforce SObject for which POJOs must be generated
+ * Names of Salesforce SObject for which DTOs must be generated.
*/
@Parameter
protected String[] includes;
/**
- * Do NOT generate POJOs for these Salesforce SObjects
+ * Do NOT generate DTOs for these Salesforce SObjects.
*/
@Parameter
protected String[] excludes;
/**
- * Include Salesforce SObjects that match pattern
+ * Include Salesforce SObjects that match pattern.
*/
@Parameter(property = "camelSalesforce.includePattern")
protected String includePattern;
/**
- * Exclude Salesforce SObjects that match pattern
+ * Exclude Salesforce SObjects that match pattern.
*/
@Parameter(property = "camelSalesforce.excludePattern")
protected String excludePattern;
/**
- * Java package name for generated POJOs
+ * Java package name for generated DTOs.
*/
@Parameter(property = "camelSalesforce.packageName", defaultValue = "org.apache.camel.salesforce.dto")
protected String packageName;
private VelocityEngine engine;
+ private long responseTimeout;
/**
- * Execute the mojo to generate SObject POJOs
+ * Execute the mojo to generate SObject DTOs
*
* @throws MojoExecutionException
*/
- // CHECKSTYLE:OFF
public void execute() throws MojoExecutionException {
// initialize velocity to load resources from class loader and use Log4J
Properties velocityProperties = new Properties();
@@ -177,15 +224,7 @@ public class CamelSalesforceMojo extends AbstractMojo {
}
// connect to Salesforce
- final HttpClient httpClient = new HttpClient();
- httpClient.registerListener(RedirectListener.class.getName());
- httpClient.setConnectTimeout(TIMEOUT);
- httpClient.setTimeout(TIMEOUT);
- try {
- httpClient.start();
- } catch (Exception e) {
- throw new MojoExecutionException("Error creating HTTP client: " + e.getMessage(), e);
- }
+ final HttpClient httpClient = createHttpClient();
final SalesforceSession session = new SalesforceSession(httpClient,
new SalesforceLoginConfig(loginUrl, clientId, clientSecret, userName, password, false));
@@ -221,7 +260,7 @@ public class CamelSalesforceMojo extends AbstractMojo {
try {
getLog().info("Getting Salesforce Objects...");
restClient.getGlobalObjects(callback);
- if (!callback.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
+ if (!callback.await(responseTimeout, TimeUnit.MILLISECONDS)) {
throw new MojoExecutionException("Timeout waiting for getGlobalObjects!");
}
final SalesforceException ex = callback.getException();
@@ -243,67 +282,11 @@ public class CamelSalesforceMojo extends AbstractMojo {
// check if we are generating POJOs for all objects or not
if ((includes != null && includes.length > 0)
|| (excludes != null && excludes.length > 0)
- || (includePattern != null && !includePattern.trim().isEmpty())
- || (excludePattern != null && !excludePattern.trim().isEmpty())) {
-
- getLog().info("Looking for matching Object names...");
- // create a list of accepted names
- final Set<String> includedNames = new HashSet<String>();
- if (includes != null && includes.length > 0) {
- for (String name : includes) {
- name = name.trim();
- if (name.isEmpty()) {
- throw new MojoExecutionException("Invalid empty name in includes");
- }
- includedNames.add(name);
- }
- }
-
- final Set<String> excludedNames = new HashSet<String>();
- if (excludes != null && excludes.length > 0) {
- for (String name : excludes) {
- name = name.trim();
- if (name.isEmpty()) {
- throw new MojoExecutionException("Invalid empty name in excludes");
- }
- excludedNames.add(name);
- }
- }
+ || ObjectHelper.isNotEmpty(includePattern)
+ || ObjectHelper.isNotEmpty(excludePattern)) {
- // check whether a pattern is in effect
- Pattern incPattern;
- if (includePattern != null && !includePattern.trim().isEmpty()) {
- incPattern = Pattern.compile(includePattern.trim());
- } else if (includedNames.isEmpty()) {
- // include everything by default if no include names are set
- incPattern = Pattern.compile(".*");
- } else {
- // include nothing by default if include names are set
- incPattern = Pattern.compile("^$");
- }
-
- // check whether a pattern is in effect
- Pattern excPattern;
- if (excludePattern != null && !excludePattern.trim().isEmpty()) {
- excPattern = Pattern.compile(excludePattern.trim());
- } else {
- // exclude nothing by default
- excPattern = Pattern.compile("^$");
- }
+ filterObjectNames(objectNames);
- final Set<String> acceptedNames = new HashSet<String>();
- for (String name : objectNames) {
- // name is included, or matches include pattern
- // and is not excluded and does not match exclude pattern
- if ((includedNames.contains(name) || incPattern.matcher(name).matches())
- && !excludedNames.contains(name) && !excPattern.matcher(name).matches()) {
- acceptedNames.add(name);
- }
- }
- objectNames.clear();
- objectNames.addAll(acceptedNames);
-
- getLog().info(String.format("Found %s matching Objects", objectNames.size()));
} else {
getLog().warn(String.format("Generating Java classes for all %s Objects, this may take a while...", objectNames.size()));
}
@@ -314,16 +297,16 @@ public class CamelSalesforceMojo extends AbstractMojo {
getLog().info("Retrieving Object descriptions...");
for (String name : objectNames) {
try {
- callback.reset();
- restClient.getDescription(name, callback);
- if (!callback.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
- throw new MojoExecutionException("Timeout waiting for getDescription for sObject " + name);
- }
- final SalesforceException ex = callback.getException();
- if (ex != null) {
- throw ex;
- }
- descriptions.add(mapper.readValue(callback.getResponse(), SObjectDescription.class));
+ callback.reset();
+ restClient.getDescription(name, callback);
+ if (!callback.await(responseTimeout, TimeUnit.MILLISECONDS)) {
+ throw new MojoExecutionException("Timeout waiting for getDescription for sObject " + name);
+ }
+ final SalesforceException ex = callback.getException();
+ if (ex != null) {
+ throw ex;
+ }
+ descriptions.add(mapper.readValue(callback.getResponse(), SObjectDescription.class));
} catch (Exception e) {
String msg = "Error getting SObject description for '" + name + "': " + e.getMessage();
throw new MojoExecutionException(msg, e);
@@ -372,7 +355,129 @@ public class CamelSalesforceMojo extends AbstractMojo {
}
}
}
- // CHECKSTYLE:ON
+
+ protected void filterObjectNames(Set<String> objectNames) throws MojoExecutionException {
+ getLog().info("Looking for matching Object names...");
+ // create a list of accepted names
+ final Set<String> includedNames = new HashSet<String>();
+ if (includes != null && includes.length > 0) {
+ for (String name : includes) {
+ name = name.trim();
+ if (name.isEmpty()) {
+ throw new MojoExecutionException("Invalid empty name in includes");
+ }
+ includedNames.add(name);
+ }
+ }
+
+ final Set<String> excludedNames = new HashSet<String>();
+ if (excludes != null && excludes.length > 0) {
+ for (String name : excludes) {
+ name = name.trim();
+ if (name.isEmpty()) {
+ throw new MojoExecutionException("Invalid empty name in excludes");
+ }
+ excludedNames.add(name);
+ }
+ }
+
+ // check whether a pattern is in effect
+ Pattern incPattern;
+ if (includePattern != null && !includePattern.trim().isEmpty()) {
+ incPattern = Pattern.compile(includePattern.trim());
+ } else if (includedNames.isEmpty()) {
+ // include everything by default if no include names are set
+ incPattern = Pattern.compile(".*");
+ } else {
+ // include nothing by default if include names are set
+ incPattern = Pattern.compile("^$");
+ }
+
+ // check whether a pattern is in effect
+ Pattern excPattern;
+ if (excludePattern != null && !excludePattern.trim().isEmpty()) {
+ excPattern = Pattern.compile(excludePattern.trim());
+ } else {
+ // exclude nothing by default
+ excPattern = Pattern.compile("^$");
+ }
+
+ final Set<String> acceptedNames = new HashSet<String>();
+ for (String name : objectNames) {
+ // name is included, or matches include pattern
+ // and is not excluded and does not match exclude pattern
+ if ((includedNames.contains(name) || incPattern.matcher(name).matches())
+ && !excludedNames.contains(name) && !excPattern.matcher(name).matches()) {
+ acceptedNames.add(name);
+ }
+ }
+ objectNames.clear();
+ objectNames.addAll(acceptedNames);
+
+ getLog().info(String.format("Found %s matching Objects", objectNames.size()));
+ }
+
+ protected HttpClient createHttpClient() throws MojoExecutionException {
+
+ final HttpClient httpClient = new HttpClient();
+
+ // default settings
+ httpClient.registerListener(RedirectListener.class.getName());
+ httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
+ httpClient.setConnectTimeout(DEFAULT_TIMEOUT);
+ httpClient.setTimeout(DEFAULT_TIMEOUT);
+
+ // set ssl context parameters
+ try {
+ final SSLContextParameters contextParameters = sslContextParameters != null
+ ? sslContextParameters : new SSLContextParameters();
+ final SslContextFactory sslContextFactory = httpClient.getSslContextFactory();
+ sslContextFactory.setSslContext(contextParameters.createSSLContext());
+ } catch (GeneralSecurityException e) {
+ throw new MojoExecutionException("Error creating default SSL context: " + e.getMessage(), e);
+ } catch (IOException e) {
+ throw new MojoExecutionException("Error creating default SSL context: " + e.getMessage(), e);
+ }
+
+ // set HTTP client parameters
+ if (httpClientProperties != null && !httpClientProperties.isEmpty()) {
+ try {
+ IntrospectionSupport.setProperties(httpClient, new HashMap<String, Object>(httpClientProperties));
+ } catch (Exception e) {
+ throw new MojoExecutionException("Error setting HTTP client properties: " + e.getMessage(), e);
+ }
+ }
+
+ // wait for 1 second longer than the HTTP client response timeout
+ responseTimeout = httpClient.getTimeout() + 1000L;
+
+ // set http proxy settings
+ if (this.httpProxyHost != null && httpProxyPort != null) {
+ httpClient.setProxy(new Address(this.httpProxyHost, this.httpProxyPort));
+ }
+ if (this.httpProxyUsername != null && httpProxyPassword != null) {
+ try {
+ httpClient.setProxyAuthentication(new ProxyAuthorization(this.httpProxyUsername, this.httpProxyPassword));
+ } catch (IOException e) {
+ throw new MojoExecutionException("Error configuring proxy authorization: " + e.getMessage(), e);
+ }
+ }
+
+ // add redirect listener to handle Salesforce redirects
+ // this is ok to do since the RedirectListener is in the same classloader as Jetty client
+ String listenerClass = RedirectListener.class.getName();
+ if (httpClient.getRegisteredListeners() == null
+ || !httpClient.getRegisteredListeners().contains(listenerClass)) {
+ httpClient.registerListener(listenerClass);
+ }
+
+ try {
+ httpClient.start();
+ } catch (Exception e) {
+ throw new MojoExecutionException("Error creating HTTP client: " + e.getMessage(), e);
+ }
+ return httpClient;
+ }
private void processDescription(File pkgDir, SObjectDescription description, GeneratorUtility utility, String generatedDate) throws MojoExecutionException {
// generate a source file for SObject
http://git-wip-us.apache.org/repos/asf/camel/blob/9f0e167b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoIntegrationTest.java b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoIntegrationTest.java
index cf9bcb9..a40b9b9 100644
--- a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoIntegrationTest.java
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoIntegrationTest.java
@@ -35,6 +35,19 @@ public class CamelSalesforceMojoIntegrationTest {
@Test
public void testExecute() throws Exception {
+ CamelSalesforceMojo mojo = createMojo();
+
+ // generate code
+ mojo.execute();
+
+ // validate generated code
+ // check that it was generated
+ Assert.assertTrue("Output directory was not created", mojo.outputDirectory.exists());
+
+ // TODO check that the generated code compiles
+ }
+
+ protected CamelSalesforceMojo createMojo() throws IOException {
CamelSalesforceMojo mojo = new CamelSalesforceMojo();
mojo.setLog(new SystemStreamLog());
@@ -59,15 +72,7 @@ public class CamelSalesforceMojoIntegrationTest {
}
mojo.outputDirectory.delete();
}
-
- // generate code
- mojo.execute();
-
- // validate generated code
- // check that it was generated
- Assert.assertTrue("Output directory was not created", mojo.outputDirectory.exists());
-
- // TODO check that the generated code compiles
+ return mojo;
}
private void setLoginProperties(CamelSalesforceMojo mojo) throws IOException {
http://git-wip-us.apache.org/repos/asf/camel/blob/9f0e167b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/HttpProxyMojoIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/HttpProxyMojoIntegrationTest.java b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/HttpProxyMojoIntegrationTest.java
new file mode 100644
index 0000000..47d15fb
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/HttpProxyMojoIntegrationTest.java
@@ -0,0 +1,110 @@
+/**
+ * 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.maven;
+
+import java.io.IOException;
+import java.util.HashMap;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.camel.util.jsse.SSLContextParameters;
+import org.eclipse.jetty.http.HttpHeaders;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.ConnectHandler;
+import org.eclipse.jetty.server.nio.SelectChannelConnector;
+import org.eclipse.jetty.util.B64Code;
+import org.eclipse.jetty.util.StringUtil;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HttpProxyMojoIntegrationTest extends CamelSalesforceMojoIntegrationTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(HttpProxyMojoIntegrationTest.class);
+
+ private static final String HTTP_PROXY_HOST = "localhost";
+ private static final String HTTP_PROXY_USER_NAME = "camel-user";
+ private static final String HTTP_PROXY_PASSWORD = "camel-user-password";
+
+ private static Server server;
+ private static int httpProxyPort;
+
+ @BeforeClass
+ public static void setupServer() throws Exception {
+ // start a local HTTP proxy using Jetty server
+ server = new Server();
+
+ Connector connector = new SelectChannelConnector();
+ connector.setHost(HTTP_PROXY_HOST);
+ server.setConnectors(new Connector[]{connector});
+
+ final String authenticationString = "Basic "
+ + B64Code.encode(HTTP_PROXY_USER_NAME + ":" + HTTP_PROXY_PASSWORD, StringUtil.__ISO_8859_1);
+
+ ConnectHandler handler = new ConnectHandler() {
+ @Override
+ protected boolean handleAuthentication(HttpServletRequest request, HttpServletResponse response, String address) throws ServletException, IOException {
+ // validate proxy-authentication header
+ final String header = request.getHeader(HttpHeaders.PROXY_AUTHORIZATION);
+ if (!authenticationString.equals(header)) {
+ throw new ServletException("Missing header " + HttpHeaders.PROXY_AUTHORIZATION);
+ }
+ LOG.info("CONNECT exchange contains required header " + HttpHeaders.PROXY_AUTHORIZATION);
+ return super.handleAuthentication(request, response, address);
+ }
+ };
+ server.setHandler(handler);
+
+ LOG.info("Starting proxy server...");
+ server.start();
+
+ httpProxyPort = connector.getLocalPort();
+ LOG.info("Started proxy server on port {}", httpProxyPort);
+ }
+
+ @Override
+ protected CamelSalesforceMojo createMojo() throws IOException {
+ final CamelSalesforceMojo mojo = super.createMojo();
+
+ // SSL context parameters
+ mojo.sslContextParameters = new SSLContextParameters();
+
+ // HTTP proxy properties
+ mojo.httpProxyHost = HTTP_PROXY_HOST;
+ mojo.httpProxyPort = httpProxyPort;
+ mojo.httpProxyUsername = HTTP_PROXY_USER_NAME;
+ mojo.httpProxyPassword = HTTP_PROXY_PASSWORD;
+
+ // HTTP client properties
+ mojo.httpClientProperties = new HashMap<String, Object>();
+ mojo.httpClientProperties.put("timeout", "60000");
+ mojo.httpClientProperties.put("removeIdleDestinations", "true");
+
+ return mojo;
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ // stop the proxy server after component
+ LOG.info("Stopping proxy server...");
+ server.stop();
+ LOG.info("Stopped proxy server");
+ }
+}