camel-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dhira...@apache.org
Subject [5/5] git commit: Intial version of Camel support for Box.com, it's also a POC for the awesome Camel API component framework
Date Fri, 27 Jun 2014 23:22:23 GMT
Intial version of Camel support for Box.com, it's also a POC for the awesome Camel API component framework


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/a4c8f76c
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/a4c8f76c
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/a4c8f76c

Branch: refs/heads/master
Commit: a4c8f76ca7f0299d7f50a05a11d5c2f7a88b6b83
Parents: 6fccf69
Author: Dhiraj Bokde <dhirajsb@yahoo.com>
Authored: Fri Jun 27 16:21:39 2014 -0700
Committer: Dhiraj Bokde <dhirajsb@yahoo.com>
Committed: Fri Jun 27 16:22:04 2014 -0700

----------------------------------------------------------------------
 components/camel-box/pom.xml                    | 414 +++++++++++++++++
 .../camel/component/box/BoxComponent.java       |  87 ++++
 .../camel/component/box/BoxConfiguration.java   | 199 ++++++++
 .../apache/camel/component/box/BoxConsumer.java |  32 ++
 .../apache/camel/component/box/BoxEndpoint.java | 230 ++++++++++
 .../apache/camel/component/box/BoxProducer.java |  36 ++
 .../component/box/internal/BoxClientHelper.java | 220 +++++++++
 .../component/box/internal/BoxConstants.java    |  29 ++
 .../box/internal/BoxPropertiesHelper.java       |  39 ++
 .../component/box/internal/CachedBoxClient.java |  72 +++
 .../box/internal/CachingSecureStorage.java      |  50 +++
 .../box/internal/LoginAuthFlowListener.java     |  67 +++
 .../component/box/internal/LoginAuthFlowUI.java | 190 ++++++++
 .../box/internal/OAuthHelperListener.java       |  53 +++
 .../services/org/apache/camel/component/box     |  18 +
 .../component/box/AbstractBoxTestSupport.java   | 165 +++++++
 ...BoxCollaborationsManagerIntegrationTest.java | 154 +++++++
 .../box/IBoxCommentsManagerIntegrationTest.java | 143 ++++++
 .../box/IBoxEventsManagerIntegrationTest.java   |  77 ++++
 .../box/IBoxFilesManagerIntegrationTest.java    | 449 +++++++++++++++++++
 .../box/IBoxFoldersManagerIntegrationTest.java  | 236 ++++++++++
 .../box/IBoxGroupsManagerIntegrationTest.java   | 326 ++++++++++++++
 .../box/IBoxSearchManagerIntegrationTest.java   |  66 +++
 .../IBoxSharedItemsManagerIntegrationTest.java  |  55 +++
 .../box/IBoxUsersManagerIntegrationTest.java    | 280 ++++++++++++
 .../src/test/resources/log4j.properties         |  36 ++
 .../src/test/resources/test-options.properties  |  45 ++
 components/pom.xml                              |   1 +
 28 files changed, 3769 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/a4c8f76c/components/camel-box/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-box/pom.xml b/components/camel-box/pom.xml
new file mode 100644
index 0000000..e073959
--- /dev/null
+++ b/components/camel-box/pom.xml
@@ -0,0 +1,414 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>components</artifactId>
+    <version>2.14-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>camel-box</artifactId>
+  <packaging>bundle</packaging>
+  <name>Camel Box.com Component</name>
+  <description>Camel Component for Box.com</description>
+
+  <properties>
+    <schemeName>box</schemeName>
+    <componentName>Box</componentName>
+    <componentPackage>org.apache.camel.component.box</componentPackage>
+    <outPackage>org.apache.camel.component.box.internal</outPackage>
+    <boxjavalibv2.version>3.0.9</boxjavalibv2.version>
+    <htmlunit.version>2.15</htmlunit.version>
+
+    <camel.osgi.export.pkg>${componentPackage}</camel.osgi.export.pkg>
+    <camel.osgi.export.service>org.apache.camel.spi.ComponentResolver;component=box</camel.osgi.export.service>
+    <httpclient.version>4.3.3</httpclient.version>
+    <httpunit.version>1.7</httpunit.version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>net.box</groupId>
+      <artifactId>boxjavalibv2</artifactId>
+      <version>${boxjavalibv2.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>org.apache.httpcomponents</groupId>
+          <artifactId>httpclient</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.apache.httpcomponents</groupId>
+          <artifactId>httpclient-cache</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>net.sourceforge.htmlunit</groupId>
+      <artifactId>htmlunit</artifactId>
+      <version>${htmlunit.version}</version>
+    </dependency>
+<!--
+    <dependency>
+      <groupId>httpunit</groupId>
+      <artifactId>httpunit</artifactId>
+      <version>${httpunit.version}</version>
+    </dependency>
+-->
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient-cache</artifactId>
+      <version>${httpclient.version}</version>
+    </dependency>
+
+    <!-- Camel annotations in provided scope to avoid compile errors in IDEs -->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>spi-annotations</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <!-- Component API javadoc in provided scope to read API signatures -->
+    <dependency>
+      <groupId>net.box</groupId>
+      <artifactId>boxjavalibv2</artifactId>
+      <version>${boxjavalibv2.version}</version>
+      <classifier>javadoc</classifier>
+      <scope>provided</scope>
+    </dependency>
+
+    <!-- logging -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <!-- testing -->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+
+      <!-- generate Component source and test source -->
+      <plugin>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-api-component-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>generate-test-component-classes</id>
+            <goals>
+              <goal>fromApis</goal>
+            </goals>
+            <configuration>
+              <apis>
+                <api>
+                  <apiName>collaborations</apiName>
+                  <proxyClass>com.box.boxjavalibv2.resourcemanagers.IBoxCollaborationsManager</proxyClass>
+                  <fromJavadoc/>
+                </api>
+                <api>
+                  <apiName>comments</apiName>
+                  <proxyClass>com.box.boxjavalibv2.resourcemanagers.IBoxCommentsManager</proxyClass>
+                  <fromJavadoc/>
+                </api>
+                <api>
+                  <apiName>events</apiName>
+                  <proxyClass>com.box.boxjavalibv2.resourcemanagers.IBoxEventsManager</proxyClass>
+                  <fromJavadoc/>
+                </api>
+                <api>
+                  <apiName>files</apiName>
+                  <proxyClass>com.box.boxjavalibv2.resourcemanagers.IBoxFilesManager</proxyClass>
+                  <substitutions>
+                    <substitution>
+                      <method>^.+$</method>
+                      <argName>^.+$</argName>
+                      <argType>^\S+\.Box(.+)RequestObject</argType>
+                      <replacement>$1Request</replacement>
+                      <replaceWithType>true</replaceWithType>
+                    </substitution>
+                    <substitution>
+                      <method>^.+$</method>
+                      <argName>type</argName>
+                      <argType>com.box.boxjavalibv2.dao.BoxResourceType</argType>
+                      <replacement>resourceType</replacement>
+                    </substitution>
+                    <substitution>
+                      <method>^.+$</method>
+                      <argName>^id$</argName>
+                      <replacement>fileId</replacement>
+                    </substitution>
+                  </substitutions>
+                  <fromJavadoc/>
+                  <aliases>
+                    <alias>
+                      <methodPattern>[gs]et(.+)</methodPattern>
+                      <methodAlias>$1</methodAlias>
+                    </alias>
+                    <alias>
+                      <methodPattern>(create|update|upload|download)\\w+</methodPattern>
+                      <methodAlias>$1</methodAlias>
+                    </alias>
+                  </aliases>
+                </api>
+                <api>
+                  <apiName>folders</apiName>
+                  <proxyClass>com.box.boxjavalibv2.resourcemanagers.IBoxFoldersManager</proxyClass>
+                  <substitutions>
+                    <substitution>
+                      <method>^.+$</method>
+                      <argName>^.+$</argName>
+                      <argType>^\S+\.Box(.+)RequestObject</argType>
+                      <replacement>$1Request</replacement>
+                      <replaceWithType>true</replaceWithType>
+                    </substitution>
+                    <substitution>
+                      <method>^.+$</method>
+                      <argName>type</argName>
+                      <argType>com.box.boxjavalibv2.dao.BoxResourceType</argType>
+                      <replacement>resourceType</replacement>
+                    </substitution>
+                    <substitution>
+                      <method>^.+$</method>
+                      <argName>^id$</argName>
+                      <replacement>folderId</replacement>
+                    </substitution>
+                  </substitutions>
+                  <fromJavadoc/>
+                </api>
+                <api>
+                  <apiName>groups</apiName>
+                  <proxyClass>com.box.boxjavalibv2.resourcemanagers.IBoxGroupsManager</proxyClass>
+                  <substitutions>
+                    <substitution>
+                      <method>^.+$</method>
+                      <argName>^.+$</argName>
+                      <argType>^\S+\.Box(.+)RequestObject</argType>
+                      <replacement>$1Request</replacement>
+                      <replaceWithType>true</replaceWithType>
+                    </substitution>
+                    <substitution>
+                      <method>^.+$</method>
+                      <argName>type</argName>
+                      <argType>com.box.boxjavalibv2.dao.BoxResourceType</argType>
+                      <replacement>resourceType</replacement>
+                    </substitution>
+                    <substitution>
+                      <method>^.+$</method>
+                      <argName>^id$</argName>
+                      <replacement>groupId</replacement>
+                    </substitution>
+                  </substitutions>
+                  <fromJavadoc/>
+                  <aliases>
+                    <alias>
+                      <methodPattern>[gs]et(.+)</methodPattern>
+                      <methodAlias>$1</methodAlias>
+                    </alias>
+                    <alias>
+                      <methodPattern>(delete|update)\\w+</methodPattern>
+                      <methodAlias>$1</methodAlias>
+                    </alias>
+                  </aliases>
+                </api>
+                <api>
+                  <apiName>search</apiName>
+                  <proxyClass>com.box.boxjavalibv2.resourcemanagers.IBoxSearchManager</proxyClass>
+                  <fromJavadoc/>
+                </api>
+                <api>
+                  <apiName>shared-comments</apiName>
+                  <proxyClass>com.box.boxjavalibv2.resourcemanagers.IBoxCommentsManager</proxyClass>
+                </api>
+                <api>
+                  <apiName>shared-files</apiName>
+                  <proxyClass>com.box.boxjavalibv2.resourcemanagers.IBoxFilesManager</proxyClass>
+                  <aliases>
+                    <alias>
+                      <methodPattern>[gs]et(.+)</methodPattern>
+                      <methodAlias>$1</methodAlias>
+                    </alias>
+                    <alias>
+                      <methodPattern>(create|update|upload|download)\\w+</methodPattern>
+                      <methodAlias>$1</methodAlias>
+                    </alias>
+                  </aliases>
+                </api>
+                <api>
+                  <apiName>shared-folders</apiName>
+                  <proxyClass>com.box.boxjavalibv2.resourcemanagers.IBoxFoldersManager</proxyClass>
+                </api>
+                <api>
+                  <apiName>shared-items</apiName>
+                  <proxyClass>com.box.boxjavalibv2.resourcemanagers.IBoxSharedItemsManager</proxyClass>
+                  <fromJavadoc/>
+                </api>
+                <api>
+                  <apiName>users</apiName>
+                  <proxyClass>com.box.boxjavalibv2.resourcemanagers.IBoxUsersManager</proxyClass>
+                  <aliases>
+                    <alias>
+                      <methodPattern>[gs]et(.+)</methodPattern>
+                      <methodAlias>$1</methodAlias>
+                    </alias>
+                    <alias>
+                      <methodPattern>(create|update|upload|download)\\w+</methodPattern>
+                      <methodAlias>$1</methodAlias>
+                    </alias>
+                  </aliases>
+                  <fromJavadoc/>
+                </api>
+              </apis>
+              <!-- common substitutions -->
+              <substitutions>
+                <substitution>
+                  <method>^.+$</method>
+                  <argName>^.+$</argName>
+                  <argType>^\S+\.Box(.+)RequestObject</argType>
+                  <replacement>$1Request</replacement>
+                  <replaceWithType>true</replaceWithType>
+                </substitution>
+                <substitution>
+                  <method>^.+$</method>
+                  <argName>type</argName>
+                  <argType>com.box.boxjavalibv2.dao.BoxResourceType</argType>
+                  <replacement>resourceType</replacement>
+                </substitution>
+<!--
+                <substitution>
+                  <method>^.+$</method>
+                  <argName>.*(i|I)d</argName>
+                  <replacement>id</replacement>
+                </substitution>
+-->
+              </substitutions>
+              <fromJavadoc>
+                <excludeClasses>BoxResourceManager|BoxItemsManager</excludeClasses>
+              </fromJavadoc>
+              <aliases>
+                <alias>
+                  <methodPattern>[gs]et(.+)</methodPattern>
+                  <methodAlias>$1</methodAlias>
+                </alias>
+                <alias>
+                  <methodPattern>(create|delete|update)\\w+</methodPattern>
+                  <methodAlias>$1</methodAlias>
+                </alias>
+              </aliases>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!-- add generated source and test source to build -->
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <version>1.8</version>
+        <executions>
+          <execution>
+            <id>add-generated-sources</id>
+            <goals>
+              <goal>add-source</goal>
+            </goals>
+            <configuration>
+              <sources>
+                <source>${project.build.directory}/generated-sources/camel-component</source>
+              </sources>
+            </configuration>
+          </execution>
+          <execution>
+            <id>add-generated-test-sources</id>
+            <goals>
+              <goal>add-test-source</goal>
+            </goals>
+            <configuration>
+              <sources>
+                <source>${project.build.directory}/generated-test-sources/camel-component</source>
+              </sources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+    </plugins>
+
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.camel</groupId>
+          <artifactId>camel-api-component-maven-plugin</artifactId>
+          <version>${project.version}</version>
+          <configuration>
+            <scheme>${schemeName}</scheme>
+            <componentName>${componentName}</componentName>
+            <componentPackage>${componentPackage}</componentPackage>
+            <outPackage>${outPackage}</outPackage>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+
+  </build>
+
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-api-component-maven-plugin</artifactId>
+        <version>${project.version}</version>
+        <configuration>
+          <scheme>${schemeName}</scheme>
+          <componentName>${componentName}</componentName>
+          <componentPackage>${componentPackage}</componentPackage>
+          <outPackage>${outPackage}</outPackage>
+        </configuration>
+      </plugin>
+    </plugins>
+  </reporting>
+
+  <profiles>
+    <profile>
+      <id>box-test</id>
+      <build>
+        <plugins>
+          <plugin>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <configuration>
+              <childDelegation>false</childDelegation>
+              <useFile>true</useFile>
+              <forkMode>once</forkMode>
+              <forkedProcessTimeoutInSeconds>300</forkedProcessTimeoutInSeconds>
+              <includes>
+                <include>**/*Test.java</include>
+              </includes>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/a4c8f76c/components/camel-box/src/main/java/org/apache/camel/component/box/BoxComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/main/java/org/apache/camel/component/box/BoxComponent.java b/components/camel-box/src/main/java/org/apache/camel/component/box/BoxComponent.java
new file mode 100644
index 0000000..aa48337
--- /dev/null
+++ b/components/camel-box/src/main/java/org/apache/camel/component/box/BoxComponent.java
@@ -0,0 +1,87 @@
+/**
+ * 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.box;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.component.box.internal.BoxApiCollection;
+import org.apache.camel.component.box.internal.BoxApiName;
+import org.apache.camel.component.box.internal.BoxClientHelper;
+import org.apache.camel.component.box.internal.CachedBoxClient;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.util.component.AbstractApiComponent;
+
+/**
+ * Represents the component that manages {@link BoxEndpoint}.
+ */
+@UriEndpoint(scheme = "box", consumerClass = BoxConsumer.class, consumerPrefix = "consumer")
+public class BoxComponent extends AbstractApiComponent<BoxApiName, BoxConfiguration, BoxApiCollection> {
+
+    private CachedBoxClient cachedBoxClient;
+
+    public BoxComponent() {
+        super(BoxEndpoint.class, BoxApiName.class, BoxApiCollection.getCollection());
+    }
+
+    public BoxComponent(CamelContext context) {
+        super(context, BoxEndpoint.class, BoxApiName.class, BoxApiCollection.getCollection());
+    }
+
+    @Override
+    protected BoxApiName getApiName(String apiNameStr) throws IllegalArgumentException {
+        return BoxApiName.fromValue(apiNameStr);
+    }
+
+    @Override
+    protected Endpoint createEndpoint(String uri, String methodName, BoxApiName apiName,
+                                      BoxConfiguration endpointConfiguration) {
+        return new BoxEndpoint(uri, this, apiName, methodName, endpointConfiguration);
+    }
+
+    // get the component's singleton BoxClient
+    protected synchronized CachedBoxClient getBoxClient() {
+        if (cachedBoxClient == null) {
+            if (configuration != null) {
+                cachedBoxClient = BoxClientHelper.createBoxClient(configuration);
+            } else {
+                throw new IllegalArgumentException("Unable to connect, Box component configuration is missing");
+            }
+        }
+        return cachedBoxClient;
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        if (cachedBoxClient != null) {
+            // close shared client connections
+            BoxClientHelper.closeIdleConnections(cachedBoxClient);
+        }
+    }
+
+    @Override
+    public void doShutdown() throws Exception {
+        try {
+            if (cachedBoxClient != null) {
+                // shutdown singleton client
+                BoxClientHelper.shutdownBoxClient(configuration, cachedBoxClient);
+            }
+        } finally {
+            cachedBoxClient = null;
+            super.doShutdown();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a4c8f76c/components/camel-box/src/main/java/org/apache/camel/component/box/BoxConfiguration.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/main/java/org/apache/camel/component/box/BoxConfiguration.java b/components/camel-box/src/main/java/org/apache/camel/component/box/BoxConfiguration.java
new file mode 100644
index 0000000..0fdac6d
--- /dev/null
+++ b/components/camel-box/src/main/java/org/apache/camel/component/box/BoxConfiguration.java
@@ -0,0 +1,199 @@
+/**
+ * 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.box;
+
+import java.util.Map;
+
+import com.box.boxjavalibv2.BoxConnectionManagerBuilder;
+import com.box.boxjavalibv2.IBoxConfig;
+import com.box.boxjavalibv2.authorization.IAuthSecureStorage;
+import com.box.boxjavalibv2.authorization.OAuthRefreshListener;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+
+/**
+ * Component configuration for Box component.
+ */
+@UriParams
+public class BoxConfiguration {
+
+    @UriParam
+    private String clientId;
+
+    @UriParam
+    private String clientSecret;
+
+    @UriParam
+    private IAuthSecureStorage authSecureStorage;
+
+    @UriParam
+    private String userName;
+
+    @UriParam
+    private String userPassword;
+
+    @UriParam
+    private OAuthRefreshListener refreshListener;
+
+    @UriParam
+    private boolean revokeOnShutdown;
+
+    @UriParam
+    private String sharedLink;
+
+    @UriParam
+    private String sharedPassword;
+
+    @UriParam
+    private IBoxConfig boxConfig;
+
+    @UriParam
+    private BoxConnectionManagerBuilder connectionManagerBuilder;
+
+    @UriParam
+    private Map<String, Object> httpParams;
+
+    /**
+     * Box.com login timeout in seconds, defaults to 30.
+     */
+    @UriParam
+    private int loginTimeout = 30;
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getClientSecret() {
+        return clientSecret;
+    }
+
+    public void setClientSecret(String clientSecret) {
+        this.clientSecret = clientSecret;
+    }
+
+    public IAuthSecureStorage getAuthSecureStorage() {
+        return authSecureStorage;
+    }
+
+    public void setAuthSecureStorage(IAuthSecureStorage authSecureStorage) {
+        this.authSecureStorage = authSecureStorage;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getUserPassword() {
+        return userPassword;
+    }
+
+    public void setUserPassword(String userPassword) {
+        this.userPassword = userPassword;
+    }
+
+    public OAuthRefreshListener getRefreshListener() {
+        return refreshListener;
+    }
+
+    public void setRefreshListener(OAuthRefreshListener refreshListener) {
+        this.refreshListener = refreshListener;
+    }
+
+    public boolean isRevokeOnShutdown() {
+        return revokeOnShutdown;
+    }
+
+    public void setRevokeOnShutdown(boolean revokeOnShutdown) {
+        this.revokeOnShutdown = revokeOnShutdown;
+    }
+
+    public String getSharedLink() {
+        return sharedLink;
+    }
+
+    public void setSharedLink(String sharedLink) {
+        this.sharedLink = sharedLink;
+    }
+
+    public String getSharedPassword() {
+        return sharedPassword;
+    }
+
+    public void setSharedPassword(String sharedPassword) {
+        this.sharedPassword = sharedPassword;
+    }
+
+    public IBoxConfig getBoxConfig() {
+        return boxConfig;
+    }
+
+    public void setBoxConfig(IBoxConfig boxConfig) {
+        this.boxConfig = boxConfig;
+    }
+
+    public BoxConnectionManagerBuilder getConnectionManagerBuilder() {
+        return connectionManagerBuilder;
+    }
+
+    public void setConnectionManagerBuilder(BoxConnectionManagerBuilder connectionManagerBuilder) {
+        this.connectionManagerBuilder = connectionManagerBuilder;
+    }
+
+    public Map<String, Object> getHttpParams() {
+        return httpParams;
+    }
+
+    public void setHttpParams(Map<String, Object> httpParams) {
+        this.httpParams = httpParams;
+    }
+
+    public int getLoginTimeout() {
+        return loginTimeout;
+    }
+
+    public void setLoginTimeout(int loginTimeout) {
+        this.loginTimeout = loginTimeout;
+    }
+
+    @Override
+    public int hashCode() {
+        return super.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof BoxConfiguration) {
+            final BoxConfiguration other = (BoxConfiguration) obj;
+            // configurations are equal if BoxClient creation parameters are equal
+            return boxConfig == other.boxConfig
+                && connectionManagerBuilder == other.connectionManagerBuilder
+                && httpParams == other.httpParams
+                && clientId == other.clientId
+                && clientSecret == other.clientSecret
+                && authSecureStorage == other.authSecureStorage;
+        }
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a4c8f76c/components/camel-box/src/main/java/org/apache/camel/component/box/BoxConsumer.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/main/java/org/apache/camel/component/box/BoxConsumer.java b/components/camel-box/src/main/java/org/apache/camel/component/box/BoxConsumer.java
new file mode 100644
index 0000000..3c2679f
--- /dev/null
+++ b/components/camel-box/src/main/java/org/apache/camel/component/box/BoxConsumer.java
@@ -0,0 +1,32 @@
+/**
+ * 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.box;
+
+import org.apache.camel.Processor;
+import org.apache.camel.component.box.internal.BoxApiName;
+import org.apache.camel.util.component.AbstractApiConsumer;
+
+/**
+ * The Box consumer.
+ */
+public class BoxConsumer extends AbstractApiConsumer<BoxApiName, BoxConfiguration> {
+
+    public BoxConsumer(BoxEndpoint endpoint, Processor processor) {
+        super(endpoint, processor);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a4c8f76c/components/camel-box/src/main/java/org/apache/camel/component/box/BoxEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/main/java/org/apache/camel/component/box/BoxEndpoint.java b/components/camel-box/src/main/java/org/apache/camel/component/box/BoxEndpoint.java
new file mode 100644
index 0000000..d6f5ade
--- /dev/null
+++ b/components/camel-box/src/main/java/org/apache/camel/component/box/BoxEndpoint.java
@@ -0,0 +1,230 @@
+/**
+ * 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.box;
+
+import java.util.Map;
+
+import com.box.boxjavalibv2.BoxClient;
+import com.box.boxjavalibv2.resourcemanagers.IBoxResourceManager;
+import org.apache.camel.Consumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.component.box.internal.BoxApiCollection;
+import org.apache.camel.component.box.internal.BoxApiName;
+import org.apache.camel.component.box.internal.BoxClientHelper;
+import org.apache.camel.component.box.internal.BoxPropertiesHelper;
+import org.apache.camel.component.box.internal.CachedBoxClient;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.component.AbstractApiEndpoint;
+import org.apache.camel.util.component.ApiMethod;
+import org.apache.camel.util.component.ApiMethodPropertiesHelper;
+
+/**
+ * Represents a Box endpoint.
+ */
+@UriEndpoint(scheme = "box", consumerClass = BoxConsumer.class, consumerPrefix = "consumer")
+public class BoxEndpoint extends AbstractApiEndpoint<BoxApiName, BoxConfiguration> {
+
+    private static final String SHARED_LINK_PROPERTY = "sharedLink";
+    private static final String SHARED_PASSWORD_PROPERTY = "sharedPassword";
+
+    // cached client
+    private CachedBoxClient cachedBoxClient;
+
+    // proxy manager
+    private IBoxResourceManager apiProxy;
+
+    // configuration values for shared links
+    private String sharedLink;
+    private String sharedPassword;
+
+    private boolean boxClientShared;
+
+    public BoxEndpoint(String uri, BoxComponent component,
+                         BoxApiName apiName, String methodName, BoxConfiguration endpointConfiguration) {
+        super(uri, component, apiName, methodName, BoxApiCollection.getCollection().getHelper(apiName), endpointConfiguration);
+    }
+
+    public Producer createProducer() throws Exception {
+        return new BoxProducer(this);
+    }
+
+    public Consumer createConsumer(Processor processor) throws Exception {
+        // make sure inBody is not set for consumers
+        if (inBody != null) {
+            throw new IllegalArgumentException("Option inBody is not supported for consumer endpoint");
+        }
+        final BoxConsumer consumer = new BoxConsumer(this, processor);
+        // also set consumer.* properties
+        configureConsumer(consumer);
+        return consumer;
+    }
+
+    @Override
+    protected ApiMethodPropertiesHelper<BoxConfiguration> getPropertiesHelper() {
+        return BoxPropertiesHelper.getHelper();
+    }
+
+    @Override
+    protected void afterConfigureProperties() {
+        // create client eagerly, a good way to validate configuration
+        createBoxClient();
+
+        this.sharedLink = configuration.getSharedLink();
+        this.sharedPassword = configuration.getSharedPassword();
+
+        // validate shared endpoints
+        switch (getApiName()) {
+        case SHARED_COMMENTS:
+        case SHARED_FILES:
+        case SHARED_FOLDERS:
+        case SHARED_ITEMS:
+            if (ObjectHelper.isEmpty(sharedLink)) {
+                log.warn("Header properties sharedLink and sharedPassword MUST be provided for endpoint {}",
+                    getEndpointUri());
+            }
+            break;
+        default:
+        }
+    }
+
+    private void createBoxClient() {
+        final BoxComponent component = getComponent();
+        this.boxClientShared = configuration.equals(getComponent().getConfiguration());
+        if (boxClientShared) {
+            // get shared singleton client from Component
+            cachedBoxClient = component.getBoxClient();
+        } else {
+            cachedBoxClient = BoxClientHelper.createBoxClient(configuration);
+        }
+    }
+
+    @Override
+    public BoxComponent getComponent() {
+        return (BoxComponent) super.getComponent();
+    }
+
+    @Override
+    protected void interceptProperties(Map<String, Object> properties) {
+        // set shared link and password from configuration if not set as header properties
+        if (!properties.containsKey(SHARED_LINK_PROPERTY) && !ObjectHelper.isEmpty(sharedLink)) {
+            properties.put(SHARED_LINK_PROPERTY, sharedLink);
+        }
+        if (!properties.containsKey(SHARED_PASSWORD_PROPERTY) && !ObjectHelper.isEmpty(sharedPassword)) {
+            properties.put(SHARED_PASSWORD_PROPERTY, sharedPassword);
+        }
+    }
+
+    @Override
+    public Object getApiProxy(ApiMethod method, Map<String, Object> args) {
+        if (apiProxy == null) {
+            // create API proxy lazily
+            createApiProxy(args);
+        }
+        return apiProxy;
+    }
+
+    private void createApiProxy(Map<String, Object> args) {
+
+        // get shared link and password from args
+        final String sharedLink = (String) args.get("sharedLink");
+        final String sharedPassword = (String) args.get("sharedPassword");
+
+        switch (apiName) {
+        case SHARED_COMMENTS:
+        case SHARED_FILES:
+        case SHARED_FOLDERS:
+        case SHARED_ITEMS:
+            if (ObjectHelper.isEmpty(sharedLink)) {
+                throw new IllegalArgumentException("Missing required property sharedLink");
+            }
+        default:
+        }
+
+        final BoxClient boxClient = cachedBoxClient.getBoxClient();
+        switch (apiName) {
+        case COLLABORATIONS:
+            apiProxy = boxClient.getCollaborationsManager();
+            break;
+        case COMMENTS:
+            apiProxy = boxClient.getCommentsManager();
+            break;
+        case EVENTS:
+            apiProxy = boxClient.getEventsManager();
+            break;
+        case FILES:
+            apiProxy = boxClient.getFilesManager();
+            break;
+        case FOLDERS:
+            apiProxy = boxClient.getFoldersManager();
+            break;
+        case GROUPS:
+            apiProxy = boxClient.getGroupsManager();
+            break;
+        case SEARCH:
+            apiProxy = boxClient.getSearchManager();
+            break;
+        case SHARED_FILES:
+            apiProxy = boxClient.getSharedFilesManager(sharedLink, sharedPassword);
+            break;
+        case SHARED_FOLDERS:
+            apiProxy = boxClient.getSharedFoldersManager(sharedLink, sharedPassword);
+            break;
+        case SHARED_COMMENTS:
+            apiProxy = boxClient.getSharedCommentsManager(sharedLink, sharedPassword);
+            break;
+        case SHARED_ITEMS:
+            apiProxy = boxClient.getSharedItemsManager(sharedLink, sharedPassword);
+            break;
+        case USERS:
+            apiProxy = boxClient.getUsersManager();
+            break;
+        default:
+        }
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        BoxClientHelper.getOAuthToken(configuration, cachedBoxClient);
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        try {
+            if (!boxClientShared) {
+                // while there is no way to suspend BoxClient, we can close idle connections to be nice
+                BoxClientHelper.closeIdleConnections(cachedBoxClient);
+            }
+        } finally {
+            super.doStop();
+        }
+    }
+
+    @Override
+    public void doShutdown() throws Exception {
+        try {
+            // cleanup if BoxClient is not shared
+            if (!boxClientShared) {
+                BoxClientHelper.shutdownBoxClient(configuration, cachedBoxClient);
+            }
+        } finally {
+            cachedBoxClient = null;
+            super.doShutdown();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a4c8f76c/components/camel-box/src/main/java/org/apache/camel/component/box/BoxProducer.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/main/java/org/apache/camel/component/box/BoxProducer.java b/components/camel-box/src/main/java/org/apache/camel/component/box/BoxProducer.java
new file mode 100644
index 0000000..a1d2cf3
--- /dev/null
+++ b/components/camel-box/src/main/java/org/apache/camel/component/box/BoxProducer.java
@@ -0,0 +1,36 @@
+/**
+ * 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.box;
+
+import org.apache.camel.component.box.internal.BoxApiName;
+import org.apache.camel.component.box.internal.BoxConstants;
+import org.apache.camel.component.box.internal.BoxPropertiesHelper;
+import org.apache.camel.util.component.AbstractApiProducer;
+
+/**
+ * The Box producer.
+ */
+public class BoxProducer extends AbstractApiProducer<BoxApiName, BoxConfiguration> {
+
+    public BoxProducer(BoxEndpoint endpoint) {
+        super(endpoint, BoxPropertiesHelper.getHelper());
+    }
+
+    protected String getThreadProfileName() {
+        return BoxConstants.THREAD_PROFILE_NAME;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a4c8f76c/components/camel-box/src/main/java/org/apache/camel/component/box/internal/BoxClientHelper.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/main/java/org/apache/camel/component/box/internal/BoxClientHelper.java b/components/camel-box/src/main/java/org/apache/camel/component/box/internal/BoxClientHelper.java
new file mode 100644
index 0000000..621132f
--- /dev/null
+++ b/components/camel-box/src/main/java/org/apache/camel/component/box/internal/BoxClientHelper.java
@@ -0,0 +1,220 @@
+/**
+ * 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.box.internal;
+
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import com.box.boxjavalibv2.BoxClient;
+import com.box.boxjavalibv2.BoxConnectionManagerBuilder;
+import com.box.boxjavalibv2.BoxRESTClient;
+import com.box.boxjavalibv2.authorization.IAuthFlowUI;
+import com.box.boxjavalibv2.authorization.IAuthSecureStorage;
+import com.box.boxjavalibv2.exceptions.AuthFatalFailureException;
+import com.box.boxjavalibv2.exceptions.BoxServerException;
+import com.box.restclientv2.IBoxRESTClient;
+import com.box.restclientv2.exceptions.BoxRestException;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.box.BoxConfiguration;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.http.client.HttpClient;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.params.HttpParams;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Helper class to work with {@link BoxClient}.
+ */
+public final class BoxClientHelper {
+
+    private static final Logger LOG = LoggerFactory.getLogger(BoxClientHelper.class);
+
+    private BoxClientHelper() {
+    }
+
+    // create BoxClient using provided configuration
+    @SuppressWarnings("deprecation")
+    public static CachedBoxClient createBoxClient(final BoxConfiguration configuration) {
+
+        final String clientId = configuration.getClientId();
+        final String clientSecret = configuration.getClientSecret();
+
+        final IAuthSecureStorage authSecureStorage = configuration.getAuthSecureStorage();
+        final String userName = configuration.getUserName();
+        final String userPassword = configuration.getUserPassword();
+
+        if ((authSecureStorage == null && ObjectHelper.isEmpty(userPassword))
+            || ObjectHelper.isEmpty(userName) || ObjectHelper.isEmpty(clientId) || ObjectHelper.isEmpty(clientSecret)) {
+            throw new IllegalArgumentException(
+                "Missing one or more required properties "
+                + "clientId, clientSecret, userName and either authSecureStorage or userPassword");
+        }
+        LOG.debug("Creating BoxClient for login:{}, client_id:{} ...", userName, clientId);
+
+        // if set, use configured connection manager builder
+        final BoxConnectionManagerBuilder configBuilder = configuration.getConnectionManagerBuilder();
+        final BoxConnectionManagerBuilder connectionManager = configBuilder != null
+            ? configBuilder : new BoxConnectionManagerBuilder();
+
+        // create REST client for BoxClient
+        final ClientConnectionManager[] clientConnectionManager = new ClientConnectionManager[1];
+        final IBoxRESTClient restClient = new BoxRESTClient(connectionManager.build()) {
+            @Override
+            public HttpClient getRawHttpClient() {
+                final HttpClient httpClient = super.getRawHttpClient();
+                clientConnectionManager[0] = httpClient.getConnectionManager();
+
+                // set custom HTTP params
+                final Map<String, Object> configParams = configuration.getHttpParams();
+                if (configParams != null && !configParams.isEmpty()) {
+                    LOG.debug("Setting {} HTTP Params", configParams.size());
+
+                    final HttpParams httpParams = httpClient.getParams();
+                    for (Map.Entry<String, Object> param : configParams.entrySet()) {
+                        httpParams.setParameter(param.getKey(), param.getValue());
+                    }
+                }
+
+                return httpClient;
+            }
+        };
+        final BoxClient boxClient = new BoxClient(clientId, clientSecret, null, null,
+            restClient, configuration.getBoxConfig());
+
+        // enable OAuth auto-refresh
+        boxClient.setAutoRefreshOAuth(true);
+
+        // wrap the configured storage in a caching storage
+        final CachingSecureStorage storage = new CachingSecureStorage(authSecureStorage);
+
+        // set up a listener to notify secure storage and user provided listener, store it in configuration!
+        final OAuthHelperListener listener = new OAuthHelperListener(storage, configuration.getRefreshListener());
+        boxClient.addOAuthRefreshListener(listener);
+
+        final CachedBoxClient cachedBoxClient = new CachedBoxClient(boxClient, userName, clientId, storage, listener, clientConnectionManager);
+        LOG.debug("BoxClient created {}", cachedBoxClient);
+        return cachedBoxClient;
+    }
+
+    public static void getOAuthToken(BoxConfiguration configuration, CachedBoxClient cachedBoxClient)
+        throws AuthFatalFailureException, BoxRestException, BoxServerException, InterruptedException {
+
+        final BoxClient boxClient = cachedBoxClient.getBoxClient();
+        synchronized (boxClient) {
+            if (boxClient.isAuthenticated()) {
+                return;
+            }
+
+            LOG.debug("Getting OAuth token for {}...", cachedBoxClient);
+
+            final IAuthSecureStorage authSecureStorage = cachedBoxClient.getSecureStorage();
+            if (authSecureStorage != null && authSecureStorage.getAuth() != null) {
+
+                LOG.debug("Using secure storage for {}", cachedBoxClient);
+                // authenticate using stored refresh token
+                boxClient.authenticateFromSecureStorage(authSecureStorage);
+            } else {
+
+                LOG.debug("Using OAuth {}", cachedBoxClient);
+                // authorize App for user, and create OAuth token with refresh token
+                final IAuthFlowUI authFlowUI = new LoginAuthFlowUI(configuration, boxClient);
+                final CountDownLatch latch = new CountDownLatch(1);
+                final LoginAuthFlowListener listener = new LoginAuthFlowListener(latch);
+                boxClient.authenticate(authFlowUI, true, listener);
+
+                // wait for login to finish or timeout
+                if (!latch.await(configuration.getLoginTimeout(), TimeUnit.SECONDS)) {
+                    if (!boxClient.isAuthenticated()) {
+                        throw new RuntimeCamelException(String.format("Login timeout for %s", cachedBoxClient));
+                    }
+                }
+                final Exception ex = listener.getException();
+                if (ex != null) {
+                    throw new RuntimeCamelException(String.format("Login error for %s: %s",
+                        cachedBoxClient, ex.getMessage()), ex);
+                }
+            }
+
+            LOG.debug("OAuth token created for {}", cachedBoxClient);
+            // notify the cached client listener for the first time, since BoxClient doesn't!!!
+            cachedBoxClient.getListener().onRefresh(boxClient.getAuthData());
+        }
+    }
+
+    public static void closeIdleConnections(CachedBoxClient cachedBoxClient) {
+        @SuppressWarnings("deprecation")
+        final ClientConnectionManager connectionManager = cachedBoxClient.getClientConnectionManager();
+        if (connectionManager != null) {
+            // close all idle connections
+            connectionManager.closeIdleConnections(1, TimeUnit.MILLISECONDS);
+        }
+    }
+
+    public static void shutdownBoxClient(BoxConfiguration configuration, CachedBoxClient cachedBoxClient)
+        throws BoxServerException, BoxRestException, AuthFatalFailureException {
+
+        final BoxClient boxClient = cachedBoxClient.getBoxClient();
+        synchronized (boxClient) {
+
+            LOG.debug("Shutting down {} ...", cachedBoxClient);
+            try {
+                // revoke token if requested
+                if (configuration.isRevokeOnShutdown()) {
+                    revokeOAuthToken(configuration, cachedBoxClient);
+                }
+            } finally {
+
+                boxClient.setConnectionOpen(false);
+                // close connections in the underlying HttpClient
+                @SuppressWarnings("deprecation")
+                final ClientConnectionManager connectionManager = cachedBoxClient.getClientConnectionManager();
+                if (connectionManager != null) {
+                    LOG.debug("Closing connections for {}", cachedBoxClient);
+
+                    connectionManager.shutdown();
+                } else {
+                    LOG.debug("ConnectionManager not created for {}", cachedBoxClient);
+                }
+            }
+            LOG.debug("Shutdown successful for {}", cachedBoxClient);
+        }
+    }
+
+    private static void revokeOAuthToken(BoxConfiguration configuration, CachedBoxClient cachedBoxClient)
+        throws BoxServerException, BoxRestException, AuthFatalFailureException {
+
+        final BoxClient boxClient = cachedBoxClient.getBoxClient();
+        synchronized (boxClient) {
+
+            if (boxClient.isAuthenticated()) {
+
+                LOG.debug("Revoking OAuth refresh token for {}", cachedBoxClient);
+
+                // notify the OAuthListener of revoked token
+                cachedBoxClient.getListener().onRefresh(null);
+                // mark auth data revoked
+                boxClient.getOAuthDataController().setOAuthData(null);
+
+                // revoke OAuth token
+                boxClient.getOAuthManager().revokeOAuth(boxClient.getAuthData().getAccessToken(),
+                    configuration.getClientId(), configuration.getClientSecret());
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a4c8f76c/components/camel-box/src/main/java/org/apache/camel/component/box/internal/BoxConstants.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/main/java/org/apache/camel/component/box/internal/BoxConstants.java b/components/camel-box/src/main/java/org/apache/camel/component/box/internal/BoxConstants.java
new file mode 100644
index 0000000..11f584b
--- /dev/null
+++ b/components/camel-box/src/main/java/org/apache/camel/component/box/internal/BoxConstants.java
@@ -0,0 +1,29 @@
+/**
+ * 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.box.internal;
+
+/**
+ * Constants for Box component.
+ */
+public interface BoxConstants {
+
+    // suffix for parameters when passed as exchange header properties
+    String PROPERTY_PREFIX = "CamelBox.";
+
+    // thread profile name for this component
+    String THREAD_PROFILE_NAME = "CamelBox";
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a4c8f76c/components/camel-box/src/main/java/org/apache/camel/component/box/internal/BoxPropertiesHelper.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/main/java/org/apache/camel/component/box/internal/BoxPropertiesHelper.java b/components/camel-box/src/main/java/org/apache/camel/component/box/internal/BoxPropertiesHelper.java
new file mode 100644
index 0000000..ae9b4f6
--- /dev/null
+++ b/components/camel-box/src/main/java/org/apache/camel/component/box/internal/BoxPropertiesHelper.java
@@ -0,0 +1,39 @@
+/**
+ * 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.box.internal;
+
+import org.apache.camel.component.box.BoxConfiguration;
+import org.apache.camel.util.component.ApiMethodPropertiesHelper;
+
+/**
+ * Singleton {@link ApiMethodPropertiesHelper} for Box component.
+ */
+public final class BoxPropertiesHelper extends ApiMethodPropertiesHelper<BoxConfiguration> {
+
+    private static BoxPropertiesHelper helper;
+
+    private BoxPropertiesHelper() {
+        super(BoxConfiguration.class, BoxConstants.PROPERTY_PREFIX);
+    }
+
+    public static synchronized BoxPropertiesHelper getHelper() {
+        if (helper == null) {
+            helper = new BoxPropertiesHelper();
+        }
+        return helper;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a4c8f76c/components/camel-box/src/main/java/org/apache/camel/component/box/internal/CachedBoxClient.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/main/java/org/apache/camel/component/box/internal/CachedBoxClient.java b/components/camel-box/src/main/java/org/apache/camel/component/box/internal/CachedBoxClient.java
new file mode 100644
index 0000000..2a806ba
--- /dev/null
+++ b/components/camel-box/src/main/java/org/apache/camel/component/box/internal/CachedBoxClient.java
@@ -0,0 +1,72 @@
+/**
+ * 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.box.internal;
+
+import com.box.boxjavalibv2.BoxClient;
+import org.apache.http.conn.ClientConnectionManager;
+
+public class CachedBoxClient {
+
+    private final BoxClient boxClient;
+
+    private final String login;
+
+    private final String clientId;
+
+    private final CachingSecureStorage secureStorage;
+
+    private final OAuthHelperListener listener;
+
+    @SuppressWarnings("deprecation")
+    private final ClientConnectionManager[] clientConnectionManager;
+
+    @SuppressWarnings("deprecation")
+    public CachedBoxClient(BoxClient boxClient, String login, String clientId, CachingSecureStorage secureStorage,
+                           OAuthHelperListener listener, ClientConnectionManager[] clientConnectionManager) {
+        this.boxClient = boxClient;
+        this.login = login;
+        this.clientId = clientId;
+        this.secureStorage = secureStorage;
+        this.listener = listener;
+        if (clientConnectionManager == null || clientConnectionManager.length != 1) {
+            throw new IllegalArgumentException("clientConnectionManager must be an array of length 1");
+        }
+        this.clientConnectionManager = clientConnectionManager;
+    }
+
+    public BoxClient getBoxClient() {
+        return boxClient;
+    }
+
+    public CachingSecureStorage getSecureStorage() {
+        return secureStorage;
+    }
+
+    public OAuthHelperListener getListener() {
+        return listener;
+    }
+
+    @SuppressWarnings("deprecation")
+    public ClientConnectionManager getClientConnectionManager() {
+        return clientConnectionManager[0];
+    }
+
+    @Override
+    public String toString() {
+        return String.format("{login:%s, client_id:%s}", login, clientId);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a4c8f76c/components/camel-box/src/main/java/org/apache/camel/component/box/internal/CachingSecureStorage.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/main/java/org/apache/camel/component/box/internal/CachingSecureStorage.java b/components/camel-box/src/main/java/org/apache/camel/component/box/internal/CachingSecureStorage.java
new file mode 100644
index 0000000..adb606c
--- /dev/null
+++ b/components/camel-box/src/main/java/org/apache/camel/component/box/internal/CachingSecureStorage.java
@@ -0,0 +1,50 @@
+/**
+ * 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.box.internal;
+
+import com.box.boxjavalibv2.authorization.IAuthSecureStorage;
+import com.box.boxjavalibv2.dao.IAuthData;
+
+/**
+ * A caching {@link IAuthSecureStorage} that also delegates to another {@link IAuthSecureStorage}.
+ */
+public class CachingSecureStorage implements IAuthSecureStorage {
+
+    private final IAuthSecureStorage secureStorage;
+
+    private IAuthData auth;
+
+    public CachingSecureStorage(IAuthSecureStorage secureStorage) {
+        this.secureStorage = secureStorage;
+    }
+
+    @Override
+    public void saveAuth(IAuthData newAuth) {
+        this.auth = newAuth;
+        if (secureStorage != null) {
+            secureStorage.saveAuth(newAuth);
+        }
+    }
+
+    @Override
+    public IAuthData getAuth() {
+        if (auth == null && secureStorage != null) {
+            auth = secureStorage.getAuth();
+        }
+        return auth;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a4c8f76c/components/camel-box/src/main/java/org/apache/camel/component/box/internal/LoginAuthFlowListener.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/main/java/org/apache/camel/component/box/internal/LoginAuthFlowListener.java b/components/camel-box/src/main/java/org/apache/camel/component/box/internal/LoginAuthFlowListener.java
new file mode 100644
index 0000000..3b0a25d
--- /dev/null
+++ b/components/camel-box/src/main/java/org/apache/camel/component/box/internal/LoginAuthFlowListener.java
@@ -0,0 +1,67 @@
+/**
+ * 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.box.internal;
+
+import java.util.concurrent.CountDownLatch;
+
+import com.box.boxjavalibv2.authorization.IAuthEvent;
+import com.box.boxjavalibv2.authorization.IAuthFlowListener;
+import com.box.boxjavalibv2.authorization.IAuthFlowMessage;
+import com.box.boxjavalibv2.events.OAuthEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+* Implementation of {@link IAuthFlowListener} to get success or failure status of OAuth flow.
+*/
+public final class LoginAuthFlowListener implements IAuthFlowListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(LoginAuthFlowListener.class);
+
+    private final Exception[] exception = new Exception[1];
+    private final CountDownLatch latch;
+
+    public LoginAuthFlowListener(CountDownLatch latch) {
+        this.latch = latch;
+    }
+
+    @Override
+    public void onAuthFlowMessage(IAuthFlowMessage message) {
+        // do nothing
+    }
+
+    @Override
+    public void onAuthFlowException(Exception e) {
+        // record exception
+        exception[0] = e;
+        LOG.warn(String.format("OAuth exception: %s", e.getMessage()), e);
+        latch.countDown();
+    }
+
+    @Override
+    public void onAuthFlowEvent(IAuthEvent state, IAuthFlowMessage message) {
+        // check success
+        if (state == OAuthEvent.OAUTH_CREATED) {
+            LOG.debug("OAuth succeeded");
+            latch.countDown();
+        }
+    }
+
+    public Exception getException() {
+        return exception[0];
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a4c8f76c/components/camel-box/src/main/java/org/apache/camel/component/box/internal/LoginAuthFlowUI.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/main/java/org/apache/camel/component/box/internal/LoginAuthFlowUI.java b/components/camel-box/src/main/java/org/apache/camel/component/box/internal/LoginAuthFlowUI.java
new file mode 100644
index 0000000..568d27c
--- /dev/null
+++ b/components/camel-box/src/main/java/org/apache/camel/component/box/internal/LoginAuthFlowUI.java
@@ -0,0 +1,190 @@
+/**
+ * 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.box.internal;
+
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.box.boxjavalibv2.BoxClient;
+import com.box.boxjavalibv2.authorization.IAuthFlowListener;
+import com.box.boxjavalibv2.authorization.IAuthFlowUI;
+import com.box.boxjavalibv2.authorization.OAuthDataMessage;
+import com.box.boxjavalibv2.authorization.OAuthWebViewData;
+import com.box.boxjavalibv2.dao.BoxOAuthToken;
+import com.box.boxjavalibv2.events.OAuthEvent;
+import com.box.boxjavalibv2.resourcemanagers.IBoxOAuthManager;
+import com.gargoylesoftware.htmlunit.BrowserVersion;
+import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
+import com.gargoylesoftware.htmlunit.Page;
+import com.gargoylesoftware.htmlunit.ProxyConfig;
+import com.gargoylesoftware.htmlunit.WebClient;
+import com.gargoylesoftware.htmlunit.WebClientOptions;
+import com.gargoylesoftware.htmlunit.html.HtmlButton;
+import com.gargoylesoftware.htmlunit.html.HtmlForm;
+import com.gargoylesoftware.htmlunit.html.HtmlPage;
+import com.gargoylesoftware.htmlunit.html.HtmlPasswordInput;
+import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
+import com.gargoylesoftware.htmlunit.html.HtmlTextInput;
+import org.apache.camel.component.box.BoxConfiguration;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpStatus;
+import org.apache.http.conn.params.ConnRoutePNames;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+* HtmlUnit based OAuth2 implementation of {@link IAuthFlowUI}
+*/
+public final class LoginAuthFlowUI implements IAuthFlowUI {
+
+    private static final Logger LOG = LoggerFactory.getLogger(LoginAuthFlowUI.class);
+    private static final Pattern QUERY_PARAM_PATTERN = Pattern.compile("&?([^=]+)=([^&]+)");
+
+    private final BoxConfiguration configuration;
+    private final BoxClient boxClient;
+
+    private IAuthFlowListener listener;
+
+    public LoginAuthFlowUI(BoxConfiguration configuration, BoxClient boxClient) {
+        this.configuration = configuration;
+        this.boxClient = boxClient;
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public void authenticate(IAuthFlowListener listener) {
+
+        // TODO run this on an Executor to make it async
+
+        // create HtmlUnit client
+        final WebClient webClient = new WebClient(BrowserVersion.FIREFOX_24);
+        final WebClientOptions options = webClient.getOptions();
+        options.setRedirectEnabled(true);
+        options.setJavaScriptEnabled(false);
+        options.setThrowExceptionOnFailingStatusCode(true);
+        options.setThrowExceptionOnScriptError(true);
+        options.setPrintContentOnFailingStatusCode(LOG.isDebugEnabled());
+
+        // add HTTP proxy if set
+        final Map<String, Object> httpParams = configuration.getHttpParams();
+        if (httpParams != null && httpParams.get(ConnRoutePNames.DEFAULT_PROXY) != null) {
+            final HttpHost proxyHost = (HttpHost) httpParams.get(ConnRoutePNames.DEFAULT_PROXY);
+            final Boolean socksProxy = (Boolean) httpParams.get("http.route.socks-proxy");
+            final ProxyConfig proxyConfig = new ProxyConfig(proxyHost.getHostName(), proxyHost.getPort(),
+                socksProxy != null ? socksProxy : false);
+            options.setProxyConfig(proxyConfig);
+        }
+
+        // authorize application on user's behalf
+        try {
+            final String csrfId = String.valueOf(new SecureRandom().nextLong());
+
+            OAuthWebViewData viewData = new OAuthWebViewData(boxClient.getOAuthDataController());
+            viewData.setOptionalState(String.valueOf(csrfId));
+            final HtmlPage authPage = webClient.getPage(viewData.buildUrl().toString());
+
+            // submit login credentials
+            final HtmlForm loginForm = authPage.getFormByName("login_form");
+            final HtmlTextInput login = loginForm.getInputByName("login");
+            login.setText(configuration.getUserName());
+            final HtmlPasswordInput password = loginForm.getInputByName("password");
+            password.setText(configuration.getUserPassword());
+            final HtmlSubmitInput submitInput = loginForm.getInputByName("login_submit");
+
+            // submit consent
+            final HtmlPage consentPage = submitInput.click();
+            final HtmlForm consentForm = consentPage.getFormByName("consent_form");
+            final HtmlButton consentAccept = consentForm.getButtonByName("consent_accept");
+
+            // disable redirect to avoid loading redirect URL
+            webClient.getOptions().setRedirectEnabled(false);
+
+            // validate CSRF and get authorization code
+            String redirectQuery;
+            try {
+                final Page redirectPage = consentAccept.click();
+                redirectQuery = redirectPage.getUrl().getQuery();
+            } catch (FailingHttpStatusCodeException e) {
+                // escalate non redirect errors
+                if (e.getStatusCode() != HttpStatus.SC_MOVED_TEMPORARILY) {
+                    throw e;
+                }
+                final String location = e.getResponse().getResponseHeaderValue("Location");
+                redirectQuery = location.substring(location.indexOf('?') + 1);
+            }
+            final Map<String, String> params = new HashMap<String, String>();
+            final Matcher matcher = QUERY_PARAM_PATTERN.matcher(redirectQuery);
+            while (matcher.find()) {
+                params.put(matcher.group(1), matcher.group(2));
+            }
+            final String state = params.get("state");
+            if (!csrfId.equals(state)) {
+                final SecurityException e = new SecurityException("Invalid CSRF code!");
+                listener.onAuthFlowException(e);
+                this.listener.onAuthFlowException(e);
+            } else {
+
+                // get authorization code
+                final String authorizationCode = params.get("code");
+
+                // get OAuth token
+                final IBoxOAuthManager oAuthManager = boxClient.getOAuthManager();
+                final BoxOAuthToken oAuthToken = oAuthManager.createOAuth(authorizationCode,
+                    configuration.getClientId(), configuration.getClientSecret(), null);
+
+                // send initial token to BoxClient and this.listener
+                final OAuthDataMessage authDataMessage = new OAuthDataMessage(oAuthToken,
+                    boxClient.getJSONParser(), boxClient.getResourceHub());
+                listener.onAuthFlowEvent(OAuthEvent.OAUTH_CREATED, authDataMessage);
+                this.listener.onAuthFlowEvent(OAuthEvent.OAUTH_CREATED, authDataMessage);
+            }
+
+        } catch (Exception e) {
+            // forward login exceptions to listener
+            listener.onAuthFlowException(e);
+            this.listener.onAuthFlowException(e);
+        }
+    }
+
+    @Override
+    public void addAuthFlowListener(IAuthFlowListener listener) {
+        this.listener = listener;
+    }
+
+    @Override
+    public void initializeAuthFlow(Object applicationContext, String clientId, String clientSecret) {
+        // unknown usage
+        throw new UnsupportedOperationException("initializeAuthFlow");
+    }
+
+    @Override
+    public void initializeAuthFlow(Object applicationContext, String clientId, String clientSecret,
+                                   String redirectUrl) {
+        // unknown usage
+        throw new UnsupportedOperationException("initializeAuthFlow");
+    }
+
+    @Override
+    public void initializeAuthFlow(Object applicationContext, String clientId, String clientSecret,
+                                   String redirectUrl, BoxClient boxClient) {
+        // unknown usage
+        throw new UnsupportedOperationException("initializeAuthFlow");
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a4c8f76c/components/camel-box/src/main/java/org/apache/camel/component/box/internal/OAuthHelperListener.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/main/java/org/apache/camel/component/box/internal/OAuthHelperListener.java b/components/camel-box/src/main/java/org/apache/camel/component/box/internal/OAuthHelperListener.java
new file mode 100644
index 0000000..684d1ba
--- /dev/null
+++ b/components/camel-box/src/main/java/org/apache/camel/component/box/internal/OAuthHelperListener.java
@@ -0,0 +1,53 @@
+/**
+ * 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.box.internal;
+
+import com.box.boxjavalibv2.authorization.IAuthSecureStorage;
+import com.box.boxjavalibv2.authorization.OAuthRefreshListener;
+import com.box.boxjavalibv2.dao.IAuthData;
+
+/**
+* Wrapper implementation of {@link OAuthRefreshListener} that
+ * delegates to an {@link IAuthSecureStorage} and another {@link OAuthRefreshListener}.
+*/
+class OAuthHelperListener implements OAuthRefreshListener {
+    private final IAuthSecureStorage authSecureStorage;
+    private final OAuthRefreshListener configListener;
+
+    private String refreshToken;
+
+    public OAuthHelperListener(IAuthSecureStorage authSecureStorage, OAuthRefreshListener configListener) {
+        this.authSecureStorage = authSecureStorage;
+        this.configListener = configListener;
+
+        if (authSecureStorage != null && authSecureStorage.getAuth() != null) {
+            this.refreshToken = authSecureStorage.getAuth().getRefreshToken();
+        }
+    }
+
+    @Override
+    public void onRefresh(IAuthData newAuthData) {
+        // look for refresh token update or revocation
+        if (authSecureStorage != null
+            && (newAuthData == null || !newAuthData.getRefreshToken().equals(refreshToken))) {
+            authSecureStorage.saveAuth(newAuthData);
+        }
+        if (configListener != null) {
+            configListener.onRefresh(newAuthData);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a4c8f76c/components/camel-box/src/main/resources/META-INF/services/org/apache/camel/component/box
----------------------------------------------------------------------
diff --git a/components/camel-box/src/main/resources/META-INF/services/org/apache/camel/component/box b/components/camel-box/src/main/resources/META-INF/services/org/apache/camel/component/box
new file mode 100644
index 0000000..43c4063
--- /dev/null
+++ b/components/camel-box/src/main/resources/META-INF/services/org/apache/camel/component/box
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.component.box.BoxComponent

http://git-wip-us.apache.org/repos/asf/camel/blob/a4c8f76c/components/camel-box/src/test/java/org/apache/camel/component/box/AbstractBoxTestSupport.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/test/java/org/apache/camel/component/box/AbstractBoxTestSupport.java b/components/camel-box/src/test/java/org/apache/camel/component/box/AbstractBoxTestSupport.java
new file mode 100644
index 0000000..7d2c33c
--- /dev/null
+++ b/components/camel-box/src/test/java/org/apache/camel/component/box/AbstractBoxTestSupport.java
@@ -0,0 +1,165 @@
+/**
+ * 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.box;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import com.box.boxjavalibv2.authorization.IAuthSecureStorage;
+import com.box.boxjavalibv2.authorization.OAuthRefreshListener;
+import com.box.boxjavalibv2.dao.BoxOAuthToken;
+import com.box.boxjavalibv2.dao.IAuthData;
+import com.box.boxjavalibv2.requests.requestobjects.BoxPagingRequestObject;
+import com.box.restclientv2.requestsbase.BoxDefaultRequestObject;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.apache.camel.util.IntrospectionSupport;
+import org.apache.camel.util.ObjectHelper;
+import org.junit.AfterClass;
+
+public abstract class AbstractBoxTestSupport extends CamelTestSupport {
+
+    protected static final String CAMEL_TEST_TAG = "camel_was_here";
+    private static final String LINE_SEPARATOR = System.getProperty("line.separator");
+    private static final String TEST_OPTIONS_PROPERTIES = "/test-options.properties";
+    private static final String REFRESH_TOKEN_PROPERTY = "refreshToken";
+    protected static final BoxDefaultRequestObject BOX_DEFAULT_REQUEST_OBJECT = new BoxDefaultRequestObject();
+    protected static final BoxPagingRequestObject BOX_PAGING_REQUEST_OBJECT = BoxPagingRequestObject.pagingRequestObject(100, 0);
+    protected static String testUserId;
+
+    private static String refreshToken;
+    private static String propertyText;
+
+    protected static String testFolderId;
+    protected static String testFileId;
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+
+        final InputStream in = getClass().getResourceAsStream(TEST_OPTIONS_PROPERTIES);
+        if (in == null) {
+            throw new IOException(TEST_OPTIONS_PROPERTIES + " could not be found");
+        }
+
+        final StringBuilder builder = new StringBuilder();
+        final BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
+        String line;
+        while((line = reader.readLine()) != null) {
+            builder.append(line).append(LINE_SEPARATOR);
+        }
+        propertyText = builder.toString();
+
+        final Properties properties = new Properties();
+        try {
+            properties.load(new StringReader(propertyText));
+        } catch (IOException e) {
+            throw new IOException(String.format("%s could not be loaded: %s", TEST_OPTIONS_PROPERTIES, e.getMessage()),
+                e);
+        }
+
+        // cache test properties
+        refreshToken = properties.getProperty(REFRESH_TOKEN_PROPERTY);
+        testFolderId = properties.getProperty("testFolderId");
+        testFileId = properties.getProperty("testFileId");
+        testUserId = properties.getProperty("testUserId");
+
+        Map<String, Object> options = new HashMap<String, Object>();
+        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
+            options.put(entry.getKey().toString(), entry.getValue());
+        }
+
+        final BoxConfiguration configuration = new BoxConfiguration();
+        IntrospectionSupport.setProperties(configuration, options);
+        configuration.setAuthSecureStorage(new IAuthSecureStorage() {
+
+            @Override
+            public void saveAuth(IAuthData auth) {
+                if (auth == null) {
+                    // revoked
+                    refreshToken = "";
+                } else {
+                    // remember the refresh token to write back to test-options.properties
+                    refreshToken = auth.getRefreshToken();
+                }
+            }
+
+            @Override
+            public IAuthData getAuth() {
+                if (ObjectHelper.isEmpty(refreshToken)) {
+                    return null;
+                } else {
+                    Map<String, Object> values = new HashMap<String, Object>();
+                    values.put(BoxOAuthToken.FIELD_REFRESH_TOKEN, refreshToken);
+                    return new BoxOAuthToken(values);
+                }
+            }
+        });
+        configuration.setRefreshListener(new OAuthRefreshListener() {
+            @Override
+            public void onRefresh(IAuthData newAuthData) {
+                log.debug("Refreshed OAuth data: " + ((newAuthData != null) ? newAuthData.getAccessToken() : null));
+            }
+        });
+
+        // add BoxComponent to Camel context
+        final CamelContext context = super.createCamelContext();
+        final BoxComponent component = new BoxComponent(context);
+
+        component.setConfiguration(configuration);
+        context.addComponent("box", component);
+
+        return context;
+    }
+
+    @AfterClass
+    public static void tearDownAfterClass() throws Exception {
+        CamelTestSupport.tearDownAfterClass();
+
+        // write the refresh token back to target/test-classes/test-options.properties
+        final URL resource = AbstractBoxTestSupport.class.getResource(TEST_OPTIONS_PROPERTIES);
+        final FileOutputStream out = new FileOutputStream(new File(resource.getPath()));
+        propertyText = propertyText.replaceAll(REFRESH_TOKEN_PROPERTY + "=\\S*",
+            REFRESH_TOKEN_PROPERTY + "=" + refreshToken);
+        out.write(propertyText.getBytes("UTF-8"));
+        out.close();
+    }
+
+    @Override
+    public boolean isCreateCamelContextPerClass() {
+        // only create the context once for this class
+        return true;
+    }
+
+    protected <T> T requestBodyAndHeaders(String endpointUri, Object body, Map<String, Object> headers)
+        throws CamelExecutionException {
+        return (T) template().requestBodyAndHeaders(endpointUri, body, headers);
+    }
+
+    protected <T> T requestBody(String endpoint, Object body) throws CamelExecutionException {
+        return (T) template().requestBody(endpoint, body);
+    }
+}


Mime
View raw message