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/04/06 22:37:53 UTC

[01/23] camel git commit: Added Salesforce component

Repository: camel
Updated Branches:
  refs/heads/camel-2.12.x 588abb5d9 -> 49c609843
  refs/heads/camel-2.13.x ede4a72b7 -> ebec06b57
  refs/heads/camel-2.14.x 595d1c534 -> 6e862cc94
  refs/heads/camel-2.15.x 5399860a2 -> 6f3daa8ec
  refs/heads/linkedin-component [created] 32dcec960
  refs/heads/master 3ef0af5a5 -> b858dbb91
  refs/heads/trunk [created] ec0e3a736


http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/QueryRecordsLine_Item__c.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/QueryRecordsLine_Item__c.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/QueryRecordsLine_Item__c.java
new file mode 100644
index 0000000..a2d00cb
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/QueryRecordsLine_Item__c.java
@@ -0,0 +1,35 @@
+/**
+ * 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.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+import org.apache.camel.component.salesforce.api.dto.AbstractQueryRecordsBase;
+
+import java.util.List;
+
+public class QueryRecordsLine_Item__c extends AbstractQueryRecordsBase {
+    @XStreamImplicit
+    private List<Line_Item__c> records;
+
+    public List<Line_Item__c> getRecords() {
+        return records;
+    }
+
+    public void setRecords(List<Line_Item__c> records) {
+        this.records = records;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SessionIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SessionIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SessionIntegrationTest.java
new file mode 100644
index 0000000..f36775d
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SessionIntegrationTest.java
@@ -0,0 +1,63 @@
+package org.apache.camel.component.salesforce.internal;
+
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.RedirectListener;
+import org.apache.camel.component.salesforce.LoginConfigHelper;
+import org.junit.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author dbokde
+ */
+public class SessionIntegrationTest extends Assert implements SalesforceSession.SalesforceSessionListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SessionIntegrationTest.class);
+    private static final int TIMEOUT = 60000;
+    private boolean onLoginTriggered;
+    private boolean onLogoutTriggered;
+
+    @Test
+    public void testLogin() throws Exception {
+
+        final HttpClient httpClient = new HttpClient();
+        httpClient.setConnectTimeout(TIMEOUT);
+        httpClient.setTimeout(TIMEOUT);
+        httpClient.registerListener(RedirectListener.class.getName());
+        httpClient.start();
+
+        final SalesforceSession session = new SalesforceSession(
+            httpClient, LoginConfigHelper.getLoginConfig());
+        session.addListener(this);
+
+        try {
+            String loginToken = session.login(session.getAccessToken());
+            LOG.info("First token " + loginToken);
+
+            assertTrue("SalesforceSessionListener onLogin NOT called", onLoginTriggered);
+            onLoginTriggered = false;
+
+            // refresh token, also causes logout
+            loginToken = session.login(loginToken);
+            LOG.info("Refreshed token " + loginToken);
+
+            assertTrue("SalesforceSessionListener onLogout NOT called", onLogoutTriggered);
+            assertTrue("SalesforceSessionListener onLogin NOT called", onLoginTriggered);
+
+        } finally {
+            // logout finally
+            session.logout();
+        }
+    }
+
+    @Override
+    public void onLogin(String accessToken, String instanceUrl) {
+        onLoginTriggered = true;
+    }
+
+    @Override
+    public void onLogout() {
+        onLogoutTriggered = true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/resources/log4j.properties b/components/camel-salesforce/camel-salesforce-component/src/test/resources/log4j.properties
new file mode 100644
index 0000000..9bbf19e
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/resources/log4j.properties
@@ -0,0 +1,18 @@
+#
+# The logging properties used
+#
+log4j.rootLogger=INFO, out
+
+# uncomment the following line to turn on Camel debugging
+#log4j.logger.org.apache.camel=DEBUG
+
+# CONSOLE appender not used by default
+log4j.appender.out=org.apache.log4j.ConsoleAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=[%30.30t] %-30.30c{1} %-5p %m%n
+#log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer
+
+#log4j.logger.org.apache.http=DEBUG
+#log4j.logger.org.apache.camel.component.salesforce=TRACE

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/test/resources/test-request.csv
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/resources/test-request.csv b/components/camel-salesforce/camel-salesforce-component/src/test/resources/test-request.csv
new file mode 100644
index 0000000..880c4c4
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/resources/test-request.csv
@@ -0,0 +1,3 @@
+"Description__c","Name","Price__c","Total_Inventory__c"
+"Created from Bulk API","[Bulk API] Merchandise 0 (batch 0)","15.0","30.0"
+"Created from Bulk API","[Bulk API] Merchandise 1 (batch 0)","30.0","60.0"
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/test/resources/test-request.xml
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/resources/test-request.xml b/components/camel-salesforce/camel-salesforce-component/src/test/resources/test-request.xml
new file mode 100644
index 0000000..bdfa10e
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/resources/test-request.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<sObjects xmlns="http://www.force.com/2009/06/asyncapi/dataload">
+  <sObject>
+    <Description__c>Created from Bulk API</Description__c>
+    <Price__c>15.0</Price__c>
+    <Total_Inventory__c>30.0</Total_Inventory__c>
+    <Name>[Bulk API] Merchandise 0 (batch 0)</Name>
+  </sObject>
+  <sObject>
+    <Description__c>Created from Bulk API</Description__c>
+    <Price__c>30.0</Price__c>
+    <Total_Inventory__c>60.0</Total_Inventory__c>
+    <Name>[Bulk API] Merchandise 1 (batch 0)</Name>
+  </sObject>
+</sObjects>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-maven-plugin/.gitignore
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/.gitignore b/components/camel-salesforce/camel-salesforce-maven-plugin/.gitignore
new file mode 100644
index 0000000..7bbe0e0
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/.gitignore
@@ -0,0 +1,5 @@
+target
+*.iml
+*.iws
+*.ipr
+*test-login.properties*

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-maven-plugin/README.md
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/README.md b/components/camel-salesforce/camel-salesforce-maven-plugin/README.md
new file mode 100644
index 0000000..5bfd808
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/README.md
@@ -0,0 +1,26 @@
+# Maven plugin for camel-salesforce component #
+
+This plugin generates DTOs for the [Camel Salesforce Component](https://github.com/dhirajsb/camel-salesforce). 
+
+## Usage ##
+
+The plugin configuration has the following properties.
+
+* clientId - Salesforce client Id for Remote API access
+* clientSecret - Salesforce client secret for Remote API access
+* userName - Salesforce account user name
+* password - Salesforce account password (including secret token)
+* version - Salesforce Rest API version, defaults to 25.0
+* outputDirectory - Directory where to place generated DTOs, defaults to ${project.build.directory}/generated-sources/camel-salesforce
+* includes - List of SObject types to include
+* excludes - List of SObject types to exclude
+* includePattern - Java RegEx for SObject types to include
+* excludePattern - Java RegEx for SObject types to exclude
+* packageName - Java package name for generated DTOs, defaults to org.apache.camel.salesforce.dto.
+
+Fro obvious security reasons it is recommended that the clientId, clientSecret, userName and password fields be not set in the pom.xml. 
+The plugin should be configured for the rest of the properties, and can be executed using the following command:
+
+	mvn camel-salesforce:generate -DclientId=<clientid> -DclientSecret=<clientsecret> -DuserName=<username> -Dpassword=<password>
+
+The generated DTOs use Jackson and XStream annotations. All Salesforce field types are supported. Date and time fields are mapped to Joda DateTime, and picklist fields are mapped to generated Java Enumerations. 

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/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
new file mode 100644
index 0000000..2b571eb
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/pom.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<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>camel-salesforce</artifactId>
+    <version>2.12-SNAPSHOT</version>
+  </parent>
+
+  <groupId>org.apache.camel.maven</groupId>
+  <artifactId>camel-salesforce-maven-plugin</artifactId>
+  <packaging>maven-plugin</packaging>
+  <name>Camel :: Salesforce Maven mojo</name>
+  <description>Camel Salesforce Maven mojo</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-plugin-api</artifactId>
+      <version>2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-salesforce-component</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.velocity</groupId>
+      <artifactId>velocity</artifactId>
+      <version>${velocity-version}</version>
+    </dependency>
+
+    <!-- logging -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <version>${slf4j-api-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <version>${log4j-version}</version>
+    </dependency>
+
+    <!-- testing -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <version>${slf4j-api-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>${junit-version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/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
new file mode 100644
index 0000000..b0a4791
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
@@ -0,0 +1,569 @@
+/*
+ * Copyright 2001-2005 The Apache Software Foundation.
+ *
+ * Licensed 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 org.apache.log4j.Logger;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+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.HttpClient;
+import org.eclipse.jetty.client.RedirectListener;
+import org.apache.camel.component.salesforce.SalesforceLoginConfig;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.*;
+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 java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+/**
+ * Goal which generates POJOs for Salesforce SObjects
+ *
+ * @goal generate
+ * 
+ * @phase generate-sources
+ *
+ */
+public class CamelSalesforceMojo extends AbstractMojo
+{
+    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
+     * @parameter property="${clientId}"
+     * @required
+     */
+    protected String clientId;
+
+    /**
+     * Salesforce client secret
+     * @parameter property="${clientSecret}"
+     * @required
+     */
+    protected String clientSecret;
+
+    /**
+     * Salesforce user name
+     * @parameter property="${userName}"
+     * @required
+     */
+    protected String userName;
+
+    /**
+     * Salesforce password
+     * @parameter property="${password}"
+     * @required
+     */
+    protected String password;
+
+    /**
+     * Salesforce version
+     * @parameter property="${version}" default-value="25.0"
+     */
+    protected String version;
+
+    /**
+     * Location of the file.
+     * @parameter property="${outputDirectory}" default-value="${project.build.directory}/generated-sources/camel-salesforce"
+     * @required
+     */
+    protected File outputDirectory;
+
+    /**
+     * Names of Salesforce SObject for which POJOs must be generated
+     * @parameter
+     */
+    protected String[] includes;
+
+    /**
+     * Do NOT generate POJOs for these Salesforce SObjects
+     * @parameter
+     */
+    protected String[] excludes;
+
+    /**
+     * Include Salesforce SObjects that match pattern
+     * @parameter property="${includePattern}"
+     */
+    protected String includePattern;
+
+    /**
+     * Exclude Salesforce SObjects that match pattern
+     * @parameter property="${excludePattern}"
+     */
+    protected String excludePattern;
+
+    /**
+     * Java package name for generated POJOs
+     * @parameter property="${packageName}" default-value="org.apache.camel.salesforce.dto"
+     */
+    protected String packageName;
+
+    private VelocityEngine engine;
+
+    /**
+     * Execute the mojo to generate SObject POJOs
+     * @throws MojoExecutionException
+     */
+    public void execute()
+        throws MojoExecutionException
+    {
+        // initialize velocity to load resources from class loader and use Log4J
+        Properties velocityProperties = new Properties();
+        velocityProperties.setProperty(RuntimeConstants.RESOURCE_LOADER, "cloader");
+        velocityProperties.setProperty("cloader.resource.loader.class", ClasspathResourceLoader.class.getName());
+        velocityProperties.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, Log4JLogChute.class.getName());
+        velocityProperties.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM + ".log4j.logger", LOG.getName());
+        engine = new VelocityEngine(velocityProperties);
+        engine.init();
+
+        // make sure we can load both templates
+        if (!engine.resourceExists(SOBJECT_POJO_VM) ||
+            !engine.resourceExists(SOBJECT_QUERY_RECORDS_VM)) {
+            throw new MojoExecutionException("Velocity templates not found");
+        }
+
+        // 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 SalesforceSession session = new SalesforceSession(httpClient,
+            new SalesforceLoginConfig(SalesforceLoginConfig.DEFAULT_LOGIN_URL,
+            clientId, clientSecret, userName, password, false));
+
+        getLog().info("Salesforce login...");
+        try {
+            session.login(null);
+        } catch (SalesforceException e) {
+            String msg = "Salesforce login error " + e.getMessage();
+            throw new MojoExecutionException(msg, e);
+        }
+        getLog().info("Salesforce login successful");
+
+        // create rest client
+        RestClient restClient = null;
+        try {
+            restClient = new DefaultRestClient(httpClient,
+                version, "json", session);
+            // remember to start the active client object
+            ((DefaultRestClient)restClient).start();
+        } catch (Exception e) {
+            final String msg = "Unexpected exception creating Rest client: " + e.getMessage();
+            throw new MojoExecutionException(msg, e);
+        }
+
+        try {
+            // use Jackson json
+            final ObjectMapper mapper = new ObjectMapper();
+
+            // call getGlobalObjects to get all SObjects
+            final Set<String> objectNames = new HashSet<String>();
+            final SyncResponseCallback callback = new SyncResponseCallback();
+            try {
+                getLog().info("Getting Salesforce Objects...");
+                restClient.getGlobalObjects(callback);
+                if (!callback.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
+                    throw new MojoExecutionException("Timeout waiting for getGlobalObjects!");
+                }
+                final SalesforceException ex = callback.getException();
+                if (ex != null) {
+                    throw ex;
+                }
+                final GlobalObjects globalObjects = mapper.readValue(callback.getResponse(),
+                    GlobalObjects.class);
+
+                // create a list of object names
+                for (SObject sObject : globalObjects.getSobjects()) {
+                    objectNames.add(sObject.getName());
+                }
+            } catch (Exception e) {
+                String msg = "Error getting global Objects " + e.getMessage();
+                throw new MojoExecutionException(msg, e);
+            }
+
+            // 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);
+                    }
+                }
+
+                // 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()));
+
+            } else {
+                getLog().warn(String.format("Generating Java classes for all %s Objects, this may take a while...",
+                    objectNames.size()));
+            }
+
+            // for every accepted name, get SObject description
+            final Set<SObjectDescription> descriptions =
+                new HashSet<SObjectDescription>();
+
+            try {
+                getLog().info("Retrieving Object descriptions...");
+                for (String name : objectNames) {
+                    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));
+                }
+            } catch (Exception e) {
+                String msg = "Error getting SObject description " + e.getMessage();
+                throw new MojoExecutionException(msg, e);
+            }
+
+            // create package directory
+            // validate package name
+            if (!packageName.matches(PACKAGE_NAME_PATTERN)) {
+                throw new MojoExecutionException("Invalid package name " + packageName);
+            }
+            final File pkgDir = new File(outputDirectory, packageName.trim().replace('.', File.separatorChar));
+            if (!pkgDir.exists()) {
+                if (!pkgDir.mkdirs()) {
+                    throw new MojoExecutionException("Unable to create " + pkgDir);
+                }
+            }
+
+            getLog().info("Generating Java Classes...");
+            // generate POJOs for every object description
+            final GeneratorUtility utility = new GeneratorUtility();
+            // should we provide a flag to control timestamp generation?
+            final String generatedDate = new Date().toString();
+            for (SObjectDescription description : descriptions) {
+                processDescription(pkgDir, description, utility, generatedDate);
+            }
+
+            getLog().info(String.format("Successfully generated %s Java Classes", (descriptions.size() * 2)));
+
+        } finally {
+            // remember to stop the client
+            try {
+                ((DefaultRestClient)restClient).stop();
+            } catch (Exception ignore) {}
+
+            // Salesforce session stop
+            try {
+                session.stop();
+            } catch (Exception ignore) {}
+
+            // release HttpConnections
+            try {
+                httpClient.stop();
+            } catch (Exception ignore) {}
+        }
+    }
+
+    private void processDescription(File pkgDir, SObjectDescription description, GeneratorUtility utility, String generatedDate) throws MojoExecutionException {
+        // generate a source file for SObject
+        String fileName = description.getName() + JAVA_EXT;
+        BufferedWriter writer = null;
+        try {
+            final File pojoFile = new File(pkgDir, fileName);
+            writer = new BufferedWriter(new FileWriter(pojoFile));
+
+            VelocityContext context = new VelocityContext();
+            context.put("packageName", packageName);
+            context.put("utility", utility);
+            context.put("desc", description);
+            context.put("generatedDate", generatedDate);
+
+            Template pojoTemplate = engine.getTemplate(SOBJECT_POJO_VM);
+            pojoTemplate.merge(context, writer);
+            // close pojoFile
+            writer.close();
+
+            // write required Enumerations for any picklists
+            for (SObjectField field : description.getFields()) {
+                if (utility.isPicklist(field)) {
+                    fileName = utility.enumTypeName(field.getName()) + JAVA_EXT;
+                    File enumFile = new File(pkgDir, fileName);
+                    writer = new BufferedWriter(new FileWriter(enumFile));
+
+                    context = new VelocityContext();
+                    context.put("packageName", packageName);
+                    context.put("utility", utility);
+                    context.put("field", field);
+                    context.put("generatedDate", generatedDate);
+
+                    Template queryTemplate = engine.getTemplate(SOBJECT_PICKLIST_VM);
+                    queryTemplate.merge(context, writer);
+
+                    // close Enum file
+                    writer.close();
+                }
+            }
+
+            // write the QueryRecords class
+            fileName = "QueryRecords" + description.getName() + JAVA_EXT;
+            File queryFile = new File(pkgDir, fileName);
+            writer = new BufferedWriter(new FileWriter(queryFile));
+
+            context = new VelocityContext();
+            context.put("packageName", packageName);
+            context.put("desc", description);
+            context.put("generatedDate", generatedDate);
+
+            Template queryTemplate = engine.getTemplate(SOBJECT_QUERY_RECORDS_VM);
+            queryTemplate.merge(context, writer);
+
+            // close QueryRecords file
+            writer.close();
+
+        } catch (Exception e) {
+            String msg = "Error creating " + fileName + ": " + e.getMessage();
+            throw new MojoExecutionException(msg, e);
+        } finally {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (IOException ignore) {}
+            }
+        }
+    }
+
+    public static class GeneratorUtility {
+
+        private static final Set<String> baseFields;
+        private static final Map<String, String> lookupMap;
+
+        static {
+            baseFields = new HashSet<String>();
+            for (Field field : AbstractSObjectBase.class.getDeclaredFields()) {
+                baseFields.add(field.getName());
+            }
+
+            // create a type map
+            // using JAXB mapping, for the most part
+            // uses Joda time instead of XmlGregorianCalendar
+            // TODO do we need support for commented types???
+            final String[][] typeMap = new String[][] {
+                {"ID", "String"}, // mapping for tns:ID SOAP type
+                {"string", "String"},
+                {"integer", "java.math.BigInteger"},
+                {"int", "Integer"},
+                {"long", "Long"},
+                {"short", "Short"},
+                {"decimal", "java.math.BigDecimal"},
+                {"float", "Float"},
+                {"double", "Double"},
+                {"boolean", "Boolean"},
+                {"byte", "Byte"},
+//                {"QName", "javax.xml.namespace.QName"},
+
+//                {"dateTime", "javax.xml.datatype.XMLGregorianCalendar"},
+                {"dateTime", "org.joda.time.DateTime"},
+
+                // the blob base64Binary type is mapped to String URL for retrieving the blob
+                {"base64Binary", "String"},
+//                {"hexBinary", "byte[]"},
+
+                {"unsignedInt", "Long"},
+                {"unsignedShort", "Integer"},
+                {"unsignedByte", "Short"},
+
+//                {"time", "javax.xml.datatype.XMLGregorianCalendar"},
+                {"time", "org.joda.time.DateTime"},
+//                {"date", "javax.xml.datatype.XMLGregorianCalendar"},
+                {"date", "org.joda.time.DateTime"},
+//                {"g", "javax.xml.datatype.XMLGregorianCalendar"},
+                {"g", "org.joda.time.DateTime"},
+
+                // Salesforce maps any types like string, picklist, reference, etc. to string
+                {"anyType", "String"},
+/*
+                {"anySimpleType", "java.lang.Object"},
+                {"anySimpleType", "java.lang.String"},
+                {"duration", "javax.xml.datatype.Duration"},
+                {"NOTATION", "javax.xml.namespace.QName"}
+*/
+            };
+            lookupMap = new HashMap<String, String>();
+            for (String[] entry : typeMap) {
+                lookupMap.put(entry[0], entry[1]);
+            }
+        }
+
+        private static final String BASE64BINARY = "base64Binary";
+
+        public boolean isBlobField(SObjectField field) {
+            final String soapType = field.getSoapType();
+            return BASE64BINARY.equals(soapType.substring(soapType.indexOf(':')+1));
+        }
+
+        public boolean notBaseField(String name) {
+            return !baseFields.contains(name);
+        }
+
+        public String getFieldType(SObjectField field) throws MojoExecutionException {
+            // check if this is a picklist
+            if (isPicklist(field)) {
+                // use a pick list enum, which will be created after generating the SObject class
+                return enumTypeName(field.getName());
+            } else {
+                // map field to Java type
+                final String soapType = field.getSoapType();
+                final String type = lookupMap.get(soapType.substring(soapType.indexOf(':')+1));
+                if (type == null) {
+                    throw new MojoExecutionException(
+                        String.format("Unsupported type %s for field %s", soapType, field.getName()));
+                }
+                return type;
+            }
+        }
+
+        public boolean hasPicklists(SObjectDescription desc) {
+            for (SObjectField field : desc.getFields()) {
+                if (isPicklist(field)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public PickListValue getLastEntry(SObjectField field) {
+            final List<PickListValue> values = field.getPicklistValues();
+            return values.get(values.size() - 1);
+        }
+
+        public boolean isPicklist(SObjectField field) {
+            return field.getPicklistValues() != null && !field.getPicklistValues().isEmpty();
+        }
+
+        public String enumTypeName(String name) {
+            name = name.endsWith("__c") ? name.substring(0, name.length() - 3) : name;
+            return name + "Enum";
+        }
+
+        public String getEnumConstant(String value) {
+
+            // TODO add support for supplementary characters
+            final StringBuilder result = new StringBuilder();
+            boolean changed = false;
+            if (!Character.isJavaIdentifierStart(value.charAt(0))) {
+                result.append("_");
+                changed = true;
+            }
+            for (char c : value.toCharArray()) {
+                if (Character.isJavaIdentifierPart(c)) {
+                    result.append(c);
+                } else {
+                    // replace non Java identifier character with '_'
+                    result.append('_');
+                    changed = true;
+                }
+            }
+
+            return changed ? result.toString().toUpperCase() : value.toUpperCase();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-picklist.vm
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-picklist.vm b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-picklist.vm
new file mode 100644
index 0000000..0aed2a7
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-picklist.vm
@@ -0,0 +1,52 @@
+## sobject-picklist.vm
+/*
+ * Salesforce DTO generated by camel-salesforce-maven-plugin
+ * Generated on: $generatedDate
+ */
+package $packageName;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonValue;
+
+#set ( $enumName = $utility.enumTypeName($field.Name) )
+/**
+ * Salesforce Enumeration DTO for picklist $field.Name
+ */
+public enum $enumName {
+## find the last entry
+#set ( $lastEntry = $utility.getLastEntry($field) )
+
+#foreach ( $entry in $field.PicklistValues)
+#set ( $value = $entry.Value )
+#if ( $entry == $lastEntry )
+#set ( $delim = ";" )
+#else
+#set ( $delim = ",")
+#end
+    // $value
+    $utility.getEnumConstant($value)("$value")$delim
+#end
+
+    final String value;
+
+    private $enumName(String value) {
+        this.value = value;
+    }
+
+    @JsonValue
+    public String value() {
+        return this.value;
+    }
+
+    @JsonCreator
+    public static $enumName fromValue(String value) {
+#set ( $allValues = ".values()" )
+        for ($enumName e : $enumName$allValues) {
+            if (e.value.equals(value)) {
+                return e;
+            }
+        }
+        throw new IllegalArgumentException(value);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-pojo.vm
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-pojo.vm b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-pojo.vm
new file mode 100644
index 0000000..b240d46
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-pojo.vm
@@ -0,0 +1,60 @@
+## sobject-pojo.vm
+/*
+ * Salesforce DTO generated by camel-salesforce-maven-plugin
+ * Generated on: $generatedDate
+ */
+package $packageName;
+
+## add imports for XStreamConverter and PicklistEnumConverter if needed
+#set ( $hasPicklists = $utility.hasPicklists($desc) )
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+#if ( $hasPicklists )
+import com.thoughtworks.xstream.annotations.XStreamConverter;
+#end
+import org.codehaus.jackson.annotate.JsonProperty;
+#if ( $hasPicklists )
+import org.apache.camel.component.salesforce.api.PicklistEnumConverter;
+#end
+import org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase;
+
+/**
+ * Salesforce DTO for SObject $desc.Name
+ */
+@XStreamAlias("$desc.Name")
+public class $desc.Name extends AbstractSObjectBase {
+
+#foreach ( $field in $desc.Fields )
+#if ( $utility.notBaseField($field.Name) )
+#set ( $fieldName = $field.Name )
+#set ( $fieldType = $utility.getFieldType($field) )
+    // $fieldName
+#if ( $utility.isBlobField($field) )
+#set ( $propertyName = $fieldName + "Url" )
+#else
+#set ( $propertyName = $fieldName )
+#end
+## add a converter annotation if needed
+#if ( $utility.isPicklist($field) )
+    @XStreamConverter(PicklistEnumConverter.class)
+#else
+## add an alias for blob field url if needed
+#if ( $propertyName != $fieldName )
+    // blob field url, use getBlobField to get the content
+    @XStreamAlias("$fieldName")
+#end
+#end
+    private $fieldType $propertyName;
+
+    @JsonProperty("$fieldName")
+    public $fieldType get$propertyName() {
+        return this.$propertyName;
+    }
+
+    @JsonProperty("$fieldName")
+    public void set$propertyName($fieldType $propertyName) {
+        this.$propertyName = $propertyName;
+    }
+
+#end
+#end
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-query-records.vm
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-query-records.vm b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-query-records.vm
new file mode 100644
index 0000000..40f1ac1
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-query-records.vm
@@ -0,0 +1,29 @@
+## sobject-query-records.vm
+/*
+ * Salesforce Query DTO generated by camel-salesforce-maven-plugin
+ * Generated on: $generatedDate
+ */
+package $packageName;
+
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+import org.apache.camel.component.salesforce.api.dto.AbstractQueryRecordsBase;
+
+import java.util.List;
+
+/**
+ * Salesforce QueryRecords DTO for type $desc.Name
+ */
+#set( $descName = $desc.Name )
+public class QueryRecords$descName extends AbstractQueryRecordsBase {
+
+    @XStreamImplicit
+    private List<$descName> records;
+
+    public List<$descName> getRecords() {
+        return records;
+    }
+
+    public void setRecords(List<$descName> records) {
+        this.records = records;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/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
new file mode 100644
index 0000000..fe7bf88
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoIntegrationTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2001-2005 The Apache Software Foundation.
+ *
+ * Licensed 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 org.apache.maven.plugin.logging.SystemStreamLog;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+public class CamelSalesforceMojoIntegrationTest {
+
+    private static final String TEST_LOGIN_PROPERTIES = "test-salesforce-login.properties";
+
+    @Test
+    public void testExecute() throws Exception {
+        CamelSalesforceMojo mojo = new CamelSalesforceMojo();
+
+        mojo.setLog(new SystemStreamLog());
+
+        // set login properties
+        setLoginProperties(mojo);
+
+        // set defaults
+        mojo.version = "27.0";
+        mojo.outputDirectory = new File("target/generated-sources/camel-salesforce");
+        mojo.packageName = "org.apache.camel.salesforce.dto";
+
+        // set code generation properties
+        mojo.includePattern = "(.*__c)|(PushTopic)";
+
+        // remove generated code directory
+        if (mojo.outputDirectory.exists()) {
+            // remove old files
+            for (File file : mojo.outputDirectory.listFiles()) {
+                file.delete();
+            }
+            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
+    }
+
+    private void setLoginProperties(CamelSalesforceMojo mojo) throws IllegalAccessException, IOException {
+        // load test-salesforce-login properties
+        Properties properties = new Properties();
+        InputStream stream = new FileInputStream(TEST_LOGIN_PROPERTIES);
+        if (null == stream) {
+            throw new IllegalAccessException("Create a properties file named " +
+                TEST_LOGIN_PROPERTIES + " with clientId, clientSecret, userName, password and a testId" +
+                " for a Salesforce account with the Merchandise object from Salesforce Guides.");
+        }
+        properties.load(stream);
+        mojo.clientId= properties.getProperty("clientId");
+        mojo.clientSecret= properties.getProperty("clientSecret");
+        mojo.userName= properties.getProperty("userName");
+        mojo.password= properties.getProperty("password");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/log4j.properties b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/log4j.properties
new file mode 100644
index 0000000..6c5150e
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/log4j.properties
@@ -0,0 +1,19 @@
+#
+# The logging properties used
+#
+log4j.rootLogger=INFO, out
+
+# uncomment the following line to turn on Camel debugging
+#log4j.logger.org.apache.camel=DEBUG
+
+# CONSOLE appender not used by default
+log4j.appender.out=org.apache.log4j.ConsoleAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=[%30.30t] %-30.30c{1} %-5p %m%n
+#log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer
+
+#log4j.logger.org.apache.camel.maven=DEBUG
+#log4j.logger.org.apache.http=DEBUG
+#log4j.logger.org.apache.camel.component.salesforce=TRACE

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/pom.xml b/components/camel-salesforce/pom.xml
new file mode 100644
index 0000000..d751aee
--- /dev/null
+++ b/components/camel-salesforce/pom.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<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.12-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-salesforce</artifactId>
+    <packaging>pom</packaging>
+    <name>Camel :: Salesforce</name>
+    <description>Camel Salesforce parent project</description>
+
+    <modules>
+        <module>camel-salesforce-component</module>
+        <module>camel-salesforce-maven-plugin</module>
+    </modules>
+
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/pom.xml
----------------------------------------------------------------------
diff --git a/components/pom.xml b/components/pom.xml
index 2a0cf69..6beb121 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -142,6 +142,7 @@
     <module>camel-ruby</module>
     <module>camel-rx</module>
     <module>camel-saxon</module>
+    <module>camel-salesforce</module>
     <module>camel-script</module>
     <module>camel-servlet</module>
     <module>camel-servletlistener</module>

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/parent/pom.xml
----------------------------------------------------------------------
diff --git a/parent/pom.xml b/parent/pom.xml
index 53d2c2c..da4d788 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -73,6 +73,7 @@
     <cglib-version>2.2</cglib-version>
     <cmis-version>0.8.0</cmis-version>
     <cometd-bayeux-version>6.1.11</cometd-bayeux-version>
+    <cometd-java-client-version>2.4.3</cometd-java-client-version>
     <cometd-java-server-bundle-version>2.3.1_2</cometd-java-server-bundle-version>
     <cometd-java-server>2.3.1</cometd-java-server>
     <commons-beanutils-bundle-version>1.8.3_1</commons-beanutils-bundle-version>
@@ -954,6 +955,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-salesforce-component</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-saxon</artifactId>
         <version>${project.version}</version>
       </dependency>

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/platforms/karaf/features/src/main/resources/features.xml
----------------------------------------------------------------------
diff --git a/platforms/karaf/features/src/main/resources/features.xml b/platforms/karaf/features/src/main/resources/features.xml
index a714580..530f73e 100644
--- a/platforms/karaf/features/src/main/resources/features.xml
+++ b/platforms/karaf/features/src/main/resources/features.xml
@@ -725,6 +725,22 @@
     <bundle>mvn:com.netflix.rxjava/rxjava-core/${rxjava-version}</bundle>
     <bundle>mvn:org.apache.camel/camel-rx/${project.version}</bundle>
   </feature>
+  <feature name='camel-salesforce' version='${project.version}' resolver='(obr)' start-level='50'>
+    <feature version='${project.version}'>camel-core</feature>
+    <bundle dependency='true'>mvn:org.codehaus.jackson/jackson-mapper-asl/${jackson-version}</bundle>
+    <bundle dependency='true'>mvn:org.codehaus.jackson/jackson-core-asl/${jackson-version}</bundle>
+    <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.xstream/${xstream-bundle-version}</bundle>
+    <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.xpp3/${xpp3-bundle-version}</bundle>
+    <bundle dependency='true'>mvn:org.cometd.java/cometd-java-client/${cometd-java-client-version}</bundle>
+    <bundle dependency='true'>mvn:org.cometd.java/bayeux-api/${cometd-java-client-version}</bundle>
+    <bundle dependency='true'>mvn:org.cometd.java/cometd-java-common/${cometd-java-client-version}</bundle>
+    <bundle dependency='true'>mvn:org.eclipse.jetty/jetty-util/${jetty-version}</bundle>
+    <bundle dependency='true'>mvn:org.eclipse.jetty/jetty-io/${jetty--version}</bundle>
+    <bundle dependency='true'>mvn:org.eclipse.jetty/jetty-http/${jetty-version}</bundle>
+    <bundle dependency='true'>mvn:org.eclipse.jetty/jetty-client/${jetty-version}</bundle>
+    <bundle dependency='true'>mvn:joda-time/joda-time/${jodatime2-bundle-version}</bundle>
+    <bundle>mvn:org.apache.camel/camel-salesforce-component/${project.version}</bundle>
+  </feature>
   <feature name='camel-saxon' version='${project.version}' resolver='(obr)' start-level='50'>
     <feature version='${project.version}'>camel-core</feature>
     <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.xmlresolver/${xmlresolver-bundle-version}</bundle>


[19/23] camel git commit: CAMEL-8575: Applied patch to fix Salesforce security login retries, with thanks to Dmitry Lysai

Posted by dh...@apache.org.
CAMEL-8575: Applied patch to fix Salesforce security login retries, with thanks to Dmitry Lysai


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

Branch: refs/heads/camel-2.14.x
Commit: 6e862cc9496ffa97d491fc355f13986a4ce394ad
Parents: 595d1c5
Author: Dhiraj Bokde <dh...@yahoo.com>
Authored: Mon Apr 6 13:28:01 2015 -0700
Committer: Dhiraj Bokde <dh...@yahoo.com>
Committed: Mon Apr 6 13:28:01 2015 -0700

----------------------------------------------------------------------
 .../internal/client/AbstractClientBase.java     | 26 ++++++++---------
 .../salesforce/RestApiIntegrationTest.java      | 30 ++++++++++++++++++++
 2 files changed, 43 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/6e862cc9/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
index a00d289..b0c7442 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
@@ -103,19 +103,6 @@ public abstract class AbstractClientBase implements SalesforceSession.Salesforce
 
     protected void doHttpRequest(final ContentExchange request, final ClientResponseCallback callback) {
 
-        // use SalesforceSecurityListener for security login retries
-        try {
-            final boolean isHttps = HttpSchemes.HTTPS.equals(String.valueOf(request.getScheme()));
-            request.setEventListener(new SalesforceSecurityListener(
-                    httpClient.getDestination(request.getAddress(), isHttps),
-                    request, session, accessToken));
-        } catch (IOException e) {
-            // propagate exception
-            callback.onResponse(null, new SalesforceException(
-                    String.format("Error registering security listener: %s", e.getMessage()),
-                    e));
-        }
-
         // use HttpEventListener for lifecycle events
         request.setEventListener(new HttpEventListenerWrapper(request.getEventListener(), true) {
 
@@ -169,6 +156,19 @@ public abstract class AbstractClientBase implements SalesforceSession.Salesforce
             }
         });
 
+        // use SalesforceSecurityListener for security login retries
+        try {
+            final boolean isHttps = HttpSchemes.HTTPS.equals(String.valueOf(request.getScheme()));
+            request.setEventListener(new SalesforceSecurityListener(
+                    httpClient.getDestination(request.getAddress(), isHttps),
+                    request, session, accessToken));
+        } catch (IOException e) {
+            // propagate exception
+            callback.onResponse(null, new SalesforceException(
+                    String.format("Error registering security listener: %s", e.getMessage()),
+                    e));
+        }
+
         // execute the request
         try {
             httpClient.send(request);

http://git-wip-us.apache.org/repos/asf/camel/blob/6e862cc9/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
index 9627cf3..e87a21f 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
@@ -44,7 +44,14 @@ import org.apache.camel.component.salesforce.dto.generated.Document;
 import org.apache.camel.component.salesforce.dto.generated.Line_Item__c;
 import org.apache.camel.component.salesforce.dto.generated.Merchandise__c;
 import org.apache.camel.component.salesforce.dto.generated.QueryRecordsLine_Item__c;
+import org.apache.camel.util.jsse.SSLContextParameters;
+import org.eclipse.jetty.client.ContentExchange;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.client.RedirectListener;
+import org.eclipse.jetty.http.HttpMethods;
 import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -59,6 +66,29 @@ public class RestApiIntegrationTest extends AbstractSalesforceTestBase {
     private static String testId;
 
     @Test
+    public void testRetry() throws Exception {
+        SalesforceComponent sf = context().getComponent("salesforce", SalesforceComponent.class);
+        String accessToken = sf.getSession().getAccessToken();
+
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        sslContextFactory.setSslContext(new SSLContextParameters().createSSLContext());
+        HttpClient httpClient = new HttpClient(sslContextFactory);
+        httpClient.setConnectTimeout(60000);
+        httpClient.setTimeout(60000);
+        httpClient.registerListener(RedirectListener.class.getName());
+        httpClient.start();
+
+        ContentExchange logoutGet = new ContentExchange(true);
+        logoutGet.setURL(sf.getLoginConfig().getLoginUrl() + "/services/oauth2/revoke?token=" + accessToken);
+        logoutGet.setMethod(HttpMethods.GET);
+        httpClient.send(logoutGet);
+        assertEquals(HttpExchange.STATUS_COMPLETED, logoutGet.waitForDone());
+        assertEquals(HttpStatus.OK_200, logoutGet.getResponseStatus());
+
+        doTestGetGlobalObjects("");
+    }
+
+    @Test
     public void testGetVersions() throws Exception {
         doTestGetVersions("");
         doTestGetVersions("Xml");


[15/23] camel git commit: CAMEL-6568: Initial version of LinkedIn component

Posted by dh...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/src/main/resources/linkedin-api-wadl.xml
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/src/main/resources/linkedin-api-wadl.xml b/components/camel-linkedin/camel-linkedin-api/src/main/resources/linkedin-api-wadl.xml
new file mode 100644
index 0000000..f784a45
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/src/main/resources/linkedin-api-wadl.xml
@@ -0,0 +1,1045 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<wadl:application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+                  xmlns:wadl="http://wadl.dev.java.net/2009/02"
+                  xmlns:tns="http://camel.apache.org/component/linkedin/api/model"
+                  xsi:schemaLocation="http://camel.apache.org/component/linkedin/api/model linkedin-api-schema.xsd
+                  http://wadl.dev.java.net/2009/02 http://www.w3.org/Submission/wadl/wadl.xsd">
+
+  <wadl:grammars>
+    <wadl:include href="linkedin-api-schema.xsd"/>
+  </wadl:grammars>
+
+  <wadl:resources base="http://api.linkedin.com/v1/">
+
+    <!-- People -->
+    <wadl:resource path="people" id="People">
+
+      <wadl:resource path="~{fields}">
+        <wadl:doc><![CDATA[https://developer.linkedin.com/documents/profile-api]]></wadl:doc>
+        <wadl:method name="GET" id="getPerson">
+          <wadl:request>
+            <wadl:param href="#fields-selector"/>
+            <wadl:param href="#secure-urls"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#person"/>
+          </wadl:response>
+        </wadl:method>
+
+      </wadl:resource>
+
+      <wadl:resource path="~/connections{fields}">
+        <wadl:doc><![CDATA[https://developer.linkedin.com/documents/connections-api]]></wadl:doc>
+        <wadl:method name="GET" id="getConnections">
+          <wadl:request>
+            <wadl:param href="#fields-selector"/>
+            <wadl:param href="#secure-urls"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#connections"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="~/shares">
+        <wadl:method name="POST" id="share">
+          <wadl:request>
+            <wadl:representation mediaType="application/xml" element="tns:share"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation mediaType="application/xml" element="tns:update"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="~/network">
+        <wadl:doc><![CDATA[https://developer.linkedin.com/documents/get-network-updates-and-statistics-api]]></wadl:doc>
+
+        <wadl:resource path="updates{fields}">
+          <wadl:param href="#scope"/>
+          <wadl:param href="#type"/>
+          <wadl:param href="#count"/>
+          <wadl:param href="#start"/>
+          <wadl:param href="#after"/>
+          <wadl:param href="#before"/>
+          <wadl:param href="#show-hidden-members"/>
+
+          <wadl:method name="GET" id="getNetworkUpdates">
+            <wadl:request>
+              <wadl:param href="#fields-selector"/>
+              <wadl:param href="#secure-urls"/>
+            </wadl:request>
+            <wadl:response>
+              <wadl:representation href="#updates"/>
+            </wadl:response>
+          </wadl:method>
+        </wadl:resource>
+
+        <wadl:resource path="updates/key={update-key}">
+          <wadl:resource path="update-comments{fields}">
+            <wadl:method name="GET" id="getUpdateComments">
+              <wadl:request>
+                <wadl:param href="#update-key"/>
+                <wadl:param href="#fields-selector"/>
+                <wadl:param href="#secure-urls"/>
+              </wadl:request>
+              <wadl:response>
+                <wadl:representation mediaType="application/xml" element="tns:comments"/>
+              </wadl:response>
+            </wadl:method>
+          </wadl:resource>
+
+          <wadl:resource path="update-comments">
+            <wadl:method name="POST" id="addUpdateComment">
+              <wadl:request>
+                <wadl:param href="#update-key"/>
+                <wadl:representation mediaType="application/xml" element="tns:updatecomment"/>
+              </wadl:request>
+            </wadl:method>
+          </wadl:resource>
+
+          <wadl:resource path="likes{fields}">
+            <wadl:method name="GET" id="getUpdateLikes">
+              <wadl:request>
+                <wadl:param href="#update-key"/>
+                <wadl:param href="#fields-selector"/>
+                <wadl:param href="#secure-urls"/>
+              </wadl:request>
+              <wadl:response>
+                <wadl:representation mediaType="application/xml" element="tns:likes"/>
+              </wadl:response>
+            </wadl:method>
+          </wadl:resource>
+
+          <wadl:resource path="is-liked">
+            <wadl:method name="PUT" id="likeUpdate">
+              <wadl:request>
+                <wadl:param href="#update-key"/>
+                <wadl:representation href="#is-liked"/>
+              </wadl:request>
+            </wadl:method>
+          </wadl:resource>
+
+        </wadl:resource>
+
+        <wadl:resource path="network-stats">
+          <wadl:method name="GET" id="getNetworkStats">
+            <wadl:response>
+              <wadl:representation mediaType="application/xml" element="tns:networkstats"/>
+            </wadl:response>
+          </wadl:method>
+        </wadl:resource>
+
+      </wadl:resource>
+
+      <wadl:resource path="~/person-activities">
+        <wadl:method name="POST" id="addActivity">
+          <wadl:request>
+            <wadl:representation mediaType="application/xml" element="tns:activity"/>
+          </wadl:request>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="~/mailbox">
+        <wadl:doc><![CDATA[https://developer.linkedin.com/documents/invitation-api]]></wadl:doc>
+        <wadl:method name="POST" id="addInvite">
+          <wadl:request>
+            <wadl:representation mediaType="application/xml" element="tns:mailboxitem"/>
+          </wadl:request>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="~/group-memberships{fields}">
+        <wadl:param name="membership-state" style="query" type="tns:membershipstate"/>
+        <wadl:param href="#fields-selector"/>
+        <wadl:method name="GET" id="getGroupMemberships">
+          <wadl:request>
+            <wadl:param href="#count"/>
+            <wadl:param href="#start"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#groupmemberships"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="~/group-memberships">
+        <wadl:method name="POST" id="addGroupMembership">
+          <wadl:request>
+            <wadl:representation href="#groupmembership"/>
+          </wadl:request>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="~/group-memberships/{group-id}{fields}">
+        <wadl:method name="GET" id="getGroupMembershipSettings">
+          <wadl:request>
+            <wadl:param href="#group-id"/>
+            <wadl:param href="#fields-selector"/>
+            <wadl:param href="#count"/>
+            <wadl:param href="#start"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#groupmemberships"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="~/group-memberships/{group-id}">
+        <wadl:method name="PUT" id="updateGroupMembership">
+          <wadl:request>
+            <wadl:param href="#group-id"/>
+            <wadl:representation href="#groupmembership"/>
+          </wadl:request>
+        </wadl:method>
+
+        <wadl:method name="DELETE" id="removeGroupMembership">
+          <wadl:request>
+            <wadl:param href="#group-id"/>
+          </wadl:request>
+        </wadl:method>
+
+        <wadl:resource path="posts{fields}">
+          <wadl:method name="GET" id="getPosts">
+            <wadl:request>
+              <wadl:param href="#group-id"/>
+              <wadl:param href="#start"/>
+              <wadl:param href="#count"/>
+              <wadl:param href="#order"/>
+              <wadl:param href="#role"/>
+              <wadl:param href="#category"/>
+              <wadl:param href="#modified-since"/>
+              <wadl:param href="#fields-selector"/>
+            </wadl:request>
+            <wadl:response>
+              <wadl:representation href="#posts"/>
+            </wadl:response>
+          </wadl:method>
+        </wadl:resource>
+
+      </wadl:resource>
+
+      <wadl:resource path="~/job-bookmarks">
+
+        <wadl:method name="GET" id="getJobBookmarks">
+          <wadl:response>
+            <wadl:representation href="#job-bookmarks"/>
+          </wadl:response>
+        </wadl:method>
+
+        <wadl:method name="POST" id="addJobBookmark">
+          <wadl:request>
+            <wadl:representation href="#job-bookmark"/>
+          </wadl:request>
+        </wadl:method>
+
+        <wadl:resource path="{job-id}">
+          <wadl:method name="DELETE" id="removeJobBookmark">
+            <wadl:request>
+              <wadl:param href="#job-id"/>
+            </wadl:request>
+          </wadl:method>
+        </wadl:resource>
+      </wadl:resource>
+
+      <wadl:resource path="~/suggestions">
+
+        <wadl:resource path="groups{fields}">
+          <wadl:method name="GET" id="getSuggestedGroups">
+            <wadl:request>
+              <wadl:param href="#fields-selector"/>
+            </wadl:request>
+            <wadl:response>
+              <wadl:representation href="#groups"/>
+            </wadl:response>
+          </wadl:method>
+        </wadl:resource>
+
+        <wadl:resource path="groups">
+
+          <wadl:resource path="{group-id}">
+            <wadl:method name="DELETE" id="removeGroupSuggestion">
+              <wadl:request>
+                <wadl:param href="#group-id"/>
+              </wadl:request>
+            </wadl:method>
+
+            <wadl:resource path="posts{fields}">
+              <wadl:method name="GET" id="getSuggestedGroupPosts">
+                <wadl:request>
+                  <wadl:param href="#group-id"/>
+                  <wadl:param href="#start"/>
+                  <wadl:param href="#count"/>
+                  <wadl:param href="#order"/>
+                  <wadl:param href="#role"/>
+                  <wadl:param href="#category"/>
+                  <wadl:param href="#modified-since"/>
+                  <wadl:param href="#fields-selector"/>
+                </wadl:request>
+                <wadl:response>
+                  <wadl:representation href="#posts"/>
+                </wadl:response>
+              </wadl:method>
+            </wadl:resource>
+
+          </wadl:resource>
+        </wadl:resource>
+
+        <wadl:resource path="to-follow/companies{fields}">
+          <wadl:method name="GET" id="getSuggestedCompanies">
+            <wadl:request>
+              <wadl:param href="#fields-selector"/>
+            </wadl:request>
+            <wadl:response>
+              <wadl:representation href="#companies"/>
+            </wadl:response>
+          </wadl:method>
+        </wadl:resource>
+
+        <wadl:resource path="job-suggestions{fields}">
+          <wadl:method name="GET" id="getSuggestedJobs">
+            <wadl:request>
+              <wadl:param href="#fields-selector"/>
+            </wadl:request>
+            <wadl:response>
+              <wadl:representation mediaType="application/xml" element="tns:jobsuggestions"/>
+            </wadl:response>
+          </wadl:method>
+        </wadl:resource>
+
+      </wadl:resource>
+
+      <wadl:resource path="~/following/companies{fields}">
+        <wadl:method name="GET" id="getFollowedCompanies">
+          <wadl:request>
+            <wadl:param href="#fields-selector"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#companies"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="~/following/companies">
+        <wadl:method name="POST" id="followCompany">
+          <wadl:request>
+            <wadl:representation href="#company"/>
+          </wadl:request>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="~/following/companies/id={company-id}">
+        <wadl:method name="DELETE" id="stopFollowingCompany">
+          <wadl:request>
+            <wadl:param href="#company-id"/>
+          </wadl:request>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="id={person-id}{fields}">
+        <wadl:method name="GET" id="getPersonById">
+          <wadl:request>
+            <wadl:param href="#person-id"/>
+            <wadl:param href="#fields-selector"/>
+            <wadl:param href="#secure-urls"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#person"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="id={person-id}/connections{fields}">
+        <wadl:method name="GET" id="getConnectionsById">
+          <wadl:request>
+            <wadl:param href="#person-id"/>
+            <wadl:param href="#fields-selector"/>
+            <wadl:param href="#secure-urls"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#connections"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="id={person-id}/network/updates{fields}">
+        <wadl:param href="#scope"/>
+        <wadl:param href="#type"/>
+        <wadl:param href="#count"/>
+        <wadl:param href="#start"/>
+        <wadl:param href="#after"/>
+        <wadl:param href="#before"/>
+        <wadl:param href="#show-hidden-members"/>
+        <wadl:method name="GET" id="getNetworkUpdatesById">
+          <wadl:request>
+            <wadl:param href="#person-id"/>
+            <wadl:param href="#fields-selector"/>
+            <wadl:param href="#secure-urls"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#updates"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="url={public-profile-url}{fields}">
+        <wadl:method name="GET" id="getPersonByUrl">
+          <wadl:request>
+            <wadl:param href="#public-profile-url"/>
+            <wadl:param href="#fields-selector"/>
+            <wadl:param href="#secure-urls"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#person"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="url={public-profile-url}/connections{fields}">
+        <wadl:method name="GET" id="getConnectionsByUrl">
+          <wadl:request>
+            <wadl:param href="#public-profile-url"/>
+            <wadl:param href="#fields-selector"/>
+            <wadl:param href="#secure-urls"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#connections"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+    </wadl:resource>
+
+    <!-- Groups Resource -->
+    <wadl:resource path="groups" id="Groups">
+      <wadl:doc><![CDATA[https://developer.linkedin.com/documents/groups-api]]></wadl:doc>
+
+      <wadl:resource path="{group-id}{fields}">
+        <wadl:method name="GET" id="getGroup">
+          <wadl:request>
+            <wadl:param href="#group-id"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#group"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="{group-id}">
+
+        <wadl:resource path="posts{fields}" type="tns:get-posts"/>
+
+        <wadl:resource path="posts">
+          <wadl:method name="POST" id="addPost">
+            <wadl:request>
+              <wadl:param href="#group-id"/>
+              <wadl:representation href="#post"/>
+            </wadl:request>
+          </wadl:method>
+        </wadl:resource>
+      </wadl:resource>
+
+    </wadl:resource>
+
+    <!-- Posts Resource -->
+    <wadl:resource path="posts" id="Posts">
+      <wadl:doc><![CDATA[https://developer.linkedin.com/documents/commenting-reading-comments-and-likes-network-updates]]></wadl:doc>
+
+      <wadl:resource path="{post-id}{fields}">
+        <wadl:method name="GET" id="getPost">
+          <wadl:request>
+            <wadl:param href="#post-id"/>
+            <wadl:param href="#count"/>
+            <wadl:param href="#start"/>
+            <wadl:param href="#fields-selector"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#post"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="{post-id}/relation-to-viewer/is-liked">
+        <wadl:method name="PUT" id="likePost">
+          <wadl:request>
+            <wadl:param href="#post-id"/>
+            <wadl:representation href="#is-liked"/>
+          </wadl:request>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="{post-id}/relation-to-viewer/is-following">
+        <wadl:method name="PUT" id="followPost">
+          <wadl:request>
+            <wadl:param href="#post-id"/>
+            <wadl:representation href="#is-following"/>
+          </wadl:request>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="{post-id}/category/code">
+        <wadl:method name="PUT" id="flagCategory">
+          <wadl:request>
+            <wadl:param href="#post-id"/>
+            <wadl:representation mediaType="application/xml" element="tns:postcategorycode"/>
+          </wadl:request>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="{post-id}">
+        <wadl:method name="DELETE" id="removePost">
+          <wadl:request>
+            <wadl:param href="#post-id"/>
+          </wadl:request>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="{post-id}/comments{fields}">
+        <wadl:method name="GET" id="getPostComments">
+          <wadl:request>
+            <wadl:param href="#post-id"/>
+            <wadl:param href="#count"/>
+            <wadl:param href="#start"/>
+            <wadl:param href="#fields-selector"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#comments"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="{post-id}/comments">
+        <wadl:method name="POST" id="addComment">
+          <wadl:request>
+            <wadl:param href="#post-id"/>
+            <wadl:representation href="#comment"/>
+          </wadl:request>
+        </wadl:method>
+      </wadl:resource>
+
+    </wadl:resource>
+
+    <!-- Comments Resource -->
+    <wadl:resource path="comments" id="Comments">
+      <wadl:doc><![CDATA[https://developer.linkedin.com/documents/commenting-reading-comments-and-likes-network-updates]]></wadl:doc>
+
+      <wadl:resource path="{comment-id}{fields}">
+        <wadl:method name="GET" id="getComment">
+          <wadl:request>
+            <wadl:param href="#comment-id"/>
+            <wadl:param href="#fields-selector"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#comment"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="{comment-id}">
+        <wadl:method name="DELETE" id="removeComment">
+          <wadl:request>
+            <wadl:param href="#comment-id"/>
+          </wadl:request>
+        </wadl:method>
+      </wadl:resource>
+
+    </wadl:resource>
+
+    <!--Companies Resource -->
+    <wadl:resource id="Companies">
+      <wadl:doc><![CDATA[https://developer.linkedin.com/documents/companies]]></wadl:doc>
+
+      <wadl:resource path="companies{fields}">
+        <wadl:method name="GET" id="getCompanies">
+          <wadl:request>
+            <wadl:param href="#fields-selector"/>
+            <wadl:param name="email-domain" style="query"/>
+            <wadl:param name="is-company-admin" style="query" type="xsd:boolean"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#companies"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="companies">
+
+        <wadl:resource path="{company-id}{fields}">
+          <wadl:method name="GET" id="getCompanyById">
+            <wadl:request>
+              <wadl:param href="#company-id"/>
+              <wadl:param href="#fields-selector"/>
+            </wadl:request>
+            <wadl:response>
+              <wadl:representation href="#company"/>
+            </wadl:response>
+          </wadl:method>
+        </wadl:resource>
+
+        <wadl:resource path="universal-name={universal-name}{fields}">
+          <wadl:method name="GET" id="getCompanyByName">
+            <wadl:request>
+              <wadl:param name="universal-name" style="template"/>
+              <wadl:param href="#fields-selector"/>
+            </wadl:request>
+            <wadl:response>
+              <wadl:representation href="#company"/>
+            </wadl:response>
+          </wadl:method>
+        </wadl:resource>
+
+        <wadl:resource path="{company-id}">
+
+          <!-- Company updates -->
+          <wadl:resource path="updates{fields}">
+            <wadl:method name="GET" id="getCompanyUpdates">
+              <wadl:request>
+                <wadl:param href="#company-id"/>
+                <wadl:param href="#fields-selector"/>
+                <wadl:param href="#event-type"/>
+                <wadl:param href="#start"/>
+                <wadl:param href="#count"/>
+              </wadl:request>
+              <wadl:response>
+                <wadl:representation href="#updates"/>
+              </wadl:response>
+            </wadl:method>
+          </wadl:resource>
+
+          <wadl:resource path="updates/key={update-key}">
+            <wadl:resource path="update-comments{fields}">
+              <wadl:method name="GET" id="getCompanyUpdateComments">
+                <wadl:request>
+                  <wadl:param href="#company-id"/>
+                  <wadl:param href="#update-key"/>
+                  <wadl:param href="#fields-selector"/>
+                  <wadl:param href="#secure-urls"/>
+                </wadl:request>
+                <wadl:response>
+                  <wadl:representation mediaType="application/xml" element="tns:comments"/>
+                </wadl:response>
+              </wadl:method>
+            </wadl:resource>
+
+            <wadl:resource path="update-comments">
+            <wadl:method name="POST" id="addCompanyUpdateComment">
+                <wadl:request>
+                  <wadl:param href="#company-id"/>
+                  <wadl:param href="#update-key"/>
+                  <wadl:representation href="#update-comment"/>
+                </wadl:request>
+              </wadl:method>
+            </wadl:resource>
+
+            <wadl:resource path="update-comments-as-company">
+              <wadl:method name="POST" id="addCompanyUpdateCommentAsCompany">
+                <wadl:request>
+                  <wadl:param href="#company-id"/>
+                  <wadl:param href="#update-key"/>
+                  <wadl:representation href="#update-comment"/>
+                </wadl:request>
+              </wadl:method>
+            </wadl:resource>
+
+            <wadl:resource path="likes{fields}">
+              <wadl:method name="GET" id="getCompanyUpdateLikes">
+                <wadl:request>
+                  <wadl:param href="#company-id"/>
+                  <wadl:param href="#update-key"/>
+                  <wadl:param href="#fields-selector"/>
+                  <wadl:param href="#secure-urls"/>
+                </wadl:request>
+                <wadl:response>
+                  <wadl:representation mediaType="application/xml" element="tns:likes"/>
+                </wadl:response>
+              </wadl:method>
+            </wadl:resource>
+
+            <wadl:resource path="is-liked">
+              <wadl:method name="PUT" id="likeCompanyUpdate">
+                <wadl:request>
+                  <wadl:param href="#company-id"/>
+                  <wadl:param href="#update-key"/>
+                  <wadl:representation href="#is-liked"/>
+                </wadl:request>
+              </wadl:method>
+            </wadl:resource>
+
+          </wadl:resource>
+
+          <!-- Company shares -->
+          <wadl:resource path="shares">
+            <wadl:doc><![CDATA[https://developer.linkedin.com/documents/share-api]]></wadl:doc>
+            <wadl:method name="POST" id="addShare">
+              <wadl:request>
+                <wadl:param href="#company-id"/>
+                <wadl:representation mediaType="application/xml" element="tns:share"/>
+              </wadl:request>
+            </wadl:method>
+          </wadl:resource>
+
+          <wadl:resource path="is-company-share-enabled">
+            <wadl:method name="GET" id="isShareEnabled">
+              <wadl:request>
+                <wadl:param href="#company-id"/>
+              </wadl:request>
+              <wadl:response>
+                <wadl:representation mediaType="application/xml" element="tns:iscompanyshareenabled"/>
+              </wadl:response>
+            </wadl:method>
+          </wadl:resource>
+
+          <wadl:resource path="relation-to-viewer/is-company-share-enabled">
+            <wadl:method name="GET" id="isViewerShareEnabled">
+              <wadl:request>
+                <wadl:param href="#company-id"/>
+              </wadl:request>
+              <wadl:response>
+                <wadl:representation mediaType="application/xml" element="tns:iscompanyshareenabled"/>
+              </wadl:response>
+            </wadl:method>
+          </wadl:resource>
+
+          <!-- Company Analytics -->
+          <wadl:resource path="historical-follow-statistics">
+            <wadl:method name="GET" id="getHistoricalFollowStatistics">
+              <wadl:request>
+                <wadl:param href="#company-id"/>
+                <wadl:param href="#start-timestamp"/>
+                <wadl:param href="#end-timestamp"/>
+                <wadl:param href="#time-granularity"/>
+              </wadl:request>
+              <wadl:response>
+                <wadl:representation mediaType="application/xml" element="tns:historicalfollowstatistics"/>
+              </wadl:response>
+            </wadl:method>
+          </wadl:resource>
+
+          <wadl:resource path="historical-status-update-statistics">
+            <wadl:method name="GET" id="getHistoricalStatusUpdateStatistics">
+              <wadl:request>
+                <wadl:param href="#company-id"/>
+                <wadl:param href="#start-timestamp"/>
+                <wadl:param href="#end-timestamp"/>
+                <wadl:param href="#time-granularity"/>
+                <wadl:param name="update-key" style="query"/>
+              </wadl:request>
+              <wadl:response>
+                <wadl:representation mediaType="application/xml" element="tns:historicalstatusupdatestatistics"/>
+              </wadl:response>
+            </wadl:method>
+          </wadl:resource>
+
+          <wadl:resource path="company-statistics">
+            <wadl:method name="GET" id="getStatistics">
+              <wadl:request>
+                <wadl:param href="#company-id"/>
+              </wadl:request>
+              <wadl:response>
+                <wadl:representation mediaType="application/xml" element="tns:companystatistics"/>
+              </wadl:response>
+            </wadl:method>
+          </wadl:resource>
+
+          <wadl:resource path="num-followers">
+            <wadl:method name="GET" id="getNumberOfFollowers">
+              <wadl:request>
+                <wadl:param href="#company-id"/>
+                <wadl:param name="geos" style="query" repeating="true"/>
+                <wadl:param name="companySizes" style="query" repeating="true"/>
+                <wadl:param name="jobFunc" style="query" repeating="true"/>
+                <wadl:param name="industries" style="query" repeating="true"/>
+                <wadl:param name="seniorities" style="query" repeating="true"/>
+              </wadl:request>
+              <wadl:response>
+                <wadl:representation mediaType="application/xml" element="tns:numfollowers"/>
+              </wadl:response>
+            </wadl:method>
+          </wadl:resource>
+
+        </wadl:resource>
+
+      </wadl:resource>
+
+    </wadl:resource>
+
+    <!-- Jobs -->
+    <wadl:resource path="jobs" id="Jobs">
+      <wadl:doc><![CDATA[https://developer.linkedin.com/documents/jobs]]></wadl:doc>
+
+      <wadl:method name="POST" id="addJob">
+        <wadl:request>
+          <wadl:representation mediaType="application/xml" element="tns:job"/>
+        </wadl:request>
+      </wadl:method>
+
+      <wadl:resource path="{job-id}${fields}">
+        <wadl:method name="GET" id="getJob">
+          <wadl:request>
+            <wadl:param href="#job-id"/>
+            <wadl:param href="#fields-selector"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation mediaType="application/xml" element="tns:job"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+      <wadl:resource path="partner-job-id={partner-job-id}">
+
+        <wadl:method name="PUT" id="editJob">
+          <wadl:request>
+            <wadl:param href="#partner-job-id"/>
+            <wadl:representation mediaType="application/xml" element="tns:job"/>
+          </wadl:request>
+        </wadl:method>
+
+        <wadl:method name="DELETE" id="removeJob">
+          <wadl:request>
+            <wadl:param href="#partner-job-id"/>
+          </wadl:request>
+        </wadl:method>
+
+      </wadl:resource>
+
+    </wadl:resource>
+
+    <!-- Search -->
+    <wadl:resource id="SearchResource">
+
+      <!-- People Search -->
+      <wadl:resource path="people-search{fields}">
+        <wadl:doc><![CDATA[https://developer.linkedin.com/documents/people-search-api]]></wadl:doc>
+        <wadl:method name="GET" id="searchPeople">
+          <wadl:request>
+            <wadl:param href="#fields-selector"/>
+            <wadl:param href="#keywords"/>
+            <wadl:param name="first-name" style="query" type="tns:first-name"/>
+            <wadl:param name="last-name" style="query" type="tns:last-name"/>
+            <wadl:param href="#company-name"/>
+            <wadl:param name="current-company" style="query" type="tns:current-company"/>
+            <wadl:param name="title" style="query" type="tns:title"/>
+            <wadl:param name="current-title" style="query" type="tns:current-title"/>
+            <wadl:param name="school-name" style="query" type="tns:school-name"/>
+            <wadl:param name="current-school" style="query" type="tns:current-school"/>
+            <wadl:param href="#country-code"/>
+            <wadl:param href="#postal-code"/>
+            <wadl:param href="#distance"/>
+            <wadl:param href="#facet"/>
+            <wadl:param href="#facets"/>
+            <wadl:param href="#start"/>
+            <wadl:param href="#count"/>
+            <wadl:param name="sort" style="query"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation mediaType="application/xml" element="tns:peoplesearch"/>
+          </wadl:response>
+        </wadl:method>
+
+      </wadl:resource>
+
+      <!-- Company Search -->
+      <wadl:resource path="company-search{fields}">
+        <wadl:doc><![CDATA[https://developer.linkedin.com/documents/company-search]]></wadl:doc>
+        <wadl:method name="GET" id="searchCompanies">
+          <wadl:request>
+            <wadl:param href="#fields-selector"/>
+            <wadl:param href="#keywords"/>
+            <wadl:param name="hq-only" style="query"/>
+            <wadl:param href="#facet"/>
+            <wadl:param href="#facets"/>
+            <wadl:param href="#start"/>
+            <wadl:param href="#count"/>
+            <wadl:param name="sort" style="query"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#company-search"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+      <!-- Job Search -->
+      <wadl:resource path="job-search{fields}">
+        <wadl:doc><![CDATA[https://developer.linkedin.com/documents/job-search-api]]></wadl:doc>
+        <wadl:method name="GET" id="searchJobs">
+          <wadl:request>
+            <wadl:param href="#fields-selector"/>
+            <wadl:param href="#keywords"/>
+            <wadl:param href="#company-name"/>
+            <wadl:param name="job-title" style="query"/>
+            <wadl:param href="#country-code"/>
+            <wadl:param href="#postal-code"/>
+            <wadl:param href="#distance"/>
+            <wadl:param href="#facet"/>
+            <wadl:param href="#facets"/>
+            <wadl:param href="#start"/>
+            <wadl:param href="#count"/>
+            <wadl:param name="sort" style="query"/>
+          </wadl:request>
+          <wadl:response>
+            <wadl:representation href="#job-search"/>
+          </wadl:response>
+        </wadl:method>
+      </wadl:resource>
+
+    </wadl:resource>
+
+  </wadl:resources>
+
+  <!-- id path param -->
+  <wadl:param name="person-id" style="template" required="true" id="person-id"/>
+
+  <!-- field selector suffix -->
+  <wadl:param name="fields" style="template" id="fields-selector"/>
+
+  <!-- return secure urls in profile -->
+  <wadl:param name="secure-urls" style="query" type="xsd:boolean" id="secure-urls"/>
+
+  <!-- public profile url param -->
+  <wadl:param name="public-profile-url" style="template" type="xsd:anyURI" id="public-profile-url"/>
+
+  <!-- group Id param -->
+  <wadl:param name="group-id" style="template" type="xsd:integer" required="true" id="group-id"/>
+
+  <!-- post Id param -->
+  <wadl:param name="post-id" style="template" required="true" id="post-id"/>
+
+  <!-- comment Id param -->
+  <wadl:param name="comment-id" style="template" required="true" id="comment-id"/>
+
+  <!-- company Id param -->
+  <wadl:param name="company-id" style="template" type="xsd:integer" required="true" id="company-id"/>
+
+  <!-- job Id param -->
+  <wadl:param name="job-id" style="template" type="xsd:integer" required="true" id="job-id"/>
+
+  <!-- partner-job Id param -->
+  <wadl:param name="partner-job-id" style="template" type="xsd:integer" required="true" id="partner-job-id"/>
+
+  <!-- posts params -->
+  <wadl:param name="order" style="query" id="order">
+    <wadl:option value="recency"/>
+    <wadl:option value="popularity"/>
+  </wadl:param>
+
+  <wadl:param name="role" style="query" id="role">
+    <wadl:option value="creator"/>
+    <wadl:option value="commenter"/>
+    <wadl:option value="follower"/>
+  </wadl:param>
+
+  <wadl:param name="category" style="query" id="category">
+    <wadl:option value="discussion"/>
+  </wadl:param>
+
+  <wadl:param name="modified-since" style="query" id="modified-since" type="xsd:integer"/>
+
+  <wadl:param name="scope" style="query" type="tns:scope" id="scope"/>
+
+  <wadl:param name="type" style="query" id="type">
+    <wadl:option value="APPS"/>
+    <wadl:option value="CMPY"/>
+    <wadl:option value="CONN"/>
+    <wadl:option value="JOBS"/>
+    <wadl:option value="JGRP"/>
+    <wadl:option value="PICT"/>
+    <wadl:option value="PFOL"/>
+    <wadl:option value="PRFX"/>
+    <wadl:option value="RECU"/>
+    <wadl:option value="PRFU"/>
+    <wadl:option value="SHAR"/>
+    <wadl:option value="STAT"/>
+    <wadl:option value="VIRL"/>
+  </wadl:param>
+
+  <wadl:param name="keywords" style="query" type="tns:keywords" id="keywords"/>
+
+  <wadl:param name="facet" style="query" id="facet"/>
+
+  <wadl:param name="facets" style="query" id="facets"/>
+
+  <wadl:param name="start" style="query" type="xsd:integer" id="start"/>
+
+  <wadl:param name="count" style="query" type="xsd:integer" id="count"/>
+
+  <wadl:param name="company-name" style="query" type="tns:company-name" id="company-name"/>
+
+  <wadl:param name="country-code" style="query" type="tns:country-code" id="country-code"/>
+
+  <wadl:param name="postal-code" style="query" type="tns:postal-code" id="postal-code"/>
+
+  <wadl:param name="distance" style="query" type="tns:distance" id="distance"/>
+
+  <wadl:param name="after" style="query" type="xsd:integer" id="after"/>
+
+  <wadl:param name="before" style="query" type="xsd:integer" id="before"/>
+
+  <wadl:param name="show-hidden-members" style="query" type="xsd:boolean" id="show-hidden-members"/>
+
+  <!-- update-key path param -->
+  <wadl:param name="update-key" style="template" id="update-key"/>
+
+  <wadl:param name="event-type" style="query" id="event-type">
+    <wadl:option value="job-posting"/>
+    <wadl:option value="new-product"/>
+    <wadl:option value="status-update"/>
+  </wadl:param>
+
+  <wadl:param name="start-timestamp" style="query" type="xsd:integer" id="start-timestamp"/>
+  <wadl:param name="end-timestamp" style="query" type="xsd:integer" id="end-timestamp"/>
+  <wadl:param name="time-granularity" style="query" id="time-granularity">
+    <wadl:option value="day"/>
+    <wadl:option value="month"/>
+  </wadl:param>
+
+  <!-- representation types -->
+  <wadl:representation mediaType="application/xml" element="tns:person" id="person"/>
+
+  <wadl:representation mediaType="application/xml" element="tns:connections" id="connections"/>
+
+  <wadl:representation mediaType="application/xml" element="tns:updates" id="updates"/>
+
+  <wadl:representation mediaType="application/xml" element="tns:groupmembership" id="groupmembership"/>
+  <wadl:representation mediaType="application/xml" element="tns:groupmemberships" id="groupmemberships"/>
+
+  <wadl:representation mediaType="application/xml" element="tns:group" id="group"/>
+  <wadl:representation mediaType="application/xml" element="tns:groups" id="groups"/>
+
+  <wadl:representation mediaType="application/xml" element="tns:post" id="post"/>
+  <wadl:representation mediaType="application/xml" element="tns:posts" id="posts"/>
+
+  <wadl:representation mediaType="application/xml" element="tns:comment" id="comment"/>
+  <wadl:representation mediaType="application/xml" element="tns:comments" id="comments"/>
+
+  <wadl:representation mediaType="application/xml" element="tns:company" id="company"/>
+  <wadl:representation mediaType="application/xml" element="tns:companies" id="companies"/>
+  <wadl:representation mediaType="application/xml" element="tns:companysearch" id="company-search"/>
+
+  <wadl:representation mediaType="application/xml" element="tns:isliked" id="is-liked"/>
+
+  <wadl:representation mediaType="application/xml" element="tns:isfollowing" id="is-following"/>
+
+  <wadl:representation mediaType="application/xml" element="tns:updatecomment" id="update-comment"/>
+
+  <wadl:representation mediaType="application/xml" element="tns:jobbookmark" id="job-bookmark"/>
+  <wadl:representation mediaType="application/xml" element="tns:jobbookmarks" id="job-bookmarks"/>
+  <wadl:representation mediaType="application/xml" element="tns:jobsearch" id="job-search"/>
+
+</wadl:application>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/src/main/resources/wadl.xsd
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/src/main/resources/wadl.xsd b/components/camel-linkedin/camel-linkedin-api/src/main/resources/wadl.xsd
new file mode 100644
index 0000000..1f71474
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/src/main/resources/wadl.xsd
@@ -0,0 +1,263 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+  targetNamespace="http://wadl.dev.java.net/2009/02"
+  xmlns:tns="http://wadl.dev.java.net/2009/02"
+  xmlns:xml="http://www.w3.org/XML/1998/namespace"
+  elementFormDefault="qualified">
+
+  <xs:import namespace="http://www.w3.org/XML/1998/namespace"
+    schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+
+  <xs:element name="application">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="tns:doc" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:element ref="tns:grammars" minOccurs="0"/>
+        <xs:element ref="tns:resources" minOccurs="0"
+          maxOccurs="unbounded"/>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element ref="tns:resource_type"/>
+          <xs:element ref="tns:method"/>
+          <xs:element ref="tns:representation"/>
+          <xs:element ref="tns:param"/>
+        </xs:choice>
+        <xs:any namespace="##other" processContents="lax" minOccurs="0"
+          maxOccurs="unbounded"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:element name="doc">
+    <xs:complexType mixed="true">
+      <xs:sequence>
+        <xs:any namespace="##other" processContents="lax" minOccurs="0"
+          maxOccurs="unbounded"/>
+      </xs:sequence>
+      <xs:attribute name="title" type="xs:string"/>
+      <xs:attribute ref="xml:lang"/>
+      <xs:anyAttribute namespace="##other" processContents="lax"/>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:element name="grammars">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="tns:doc" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:element minOccurs="0" maxOccurs="unbounded" ref="tns:include"/>
+        <xs:any namespace="##other" processContents="lax" minOccurs="0"
+          maxOccurs="unbounded"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:element name="resources">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="tns:doc" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:element ref="tns:resource" maxOccurs="unbounded"/>
+        <xs:any namespace="##other" processContents="lax" minOccurs="0"
+          maxOccurs="unbounded"/>
+      </xs:sequence>
+      <xs:attribute name="base" type="xs:anyURI"/>
+      <xs:anyAttribute namespace="##other" processContents="lax"/>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:element name="resource">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="tns:doc" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:element ref="tns:param" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element ref="tns:method"/>
+          <xs:element ref="tns:resource"/>
+        </xs:choice>
+        <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"
+          processContents="lax"/>
+      </xs:sequence>
+      <xs:attribute name="id" type="xs:ID"/>
+      <xs:attribute name="type" type="tns:resource_type_list"/>
+      <xs:attribute name="queryType" type="xs:string"
+        default="application/x-www-form-urlencoded"/>
+      <xs:attribute name="path" type="xs:string"/>
+      <xs:anyAttribute namespace="##other" processContents="lax"/>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:simpleType name="resource_type_list">
+    <xs:list itemType="xs:anyURI"/>
+  </xs:simpleType>
+
+  <xs:element name="resource_type">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="tns:doc" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:element ref="tns:param" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element ref="tns:method"/>
+          <xs:element ref="tns:resource"/>
+        </xs:choice>
+        <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"
+          processContents="lax"/>
+      </xs:sequence>
+      <xs:attribute name="id" type="xs:ID"/>
+      <xs:anyAttribute namespace="##other" processContents="lax"/>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:element name="method">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="tns:doc" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:element ref="tns:request" minOccurs="0"/>
+        <xs:element ref="tns:response" minOccurs="0"
+          maxOccurs="unbounded"/>
+        <xs:any namespace="##other" processContents="lax" minOccurs="0"
+          maxOccurs="unbounded"/>
+      </xs:sequence>
+      <xs:attribute name="id" type="xs:ID"/>
+      <xs:attribute name="name" type="tns:Method"/>
+      <xs:attribute name="href" type="xs:anyURI"/>
+      <xs:anyAttribute namespace="##other" processContents="lax"/>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:simpleType name="Method">
+    <xs:union memberTypes="tns:HTTPMethods xs:NMTOKEN"/>
+  </xs:simpleType>
+
+  <xs:simpleType name="HTTPMethods">
+    <xs:restriction base="xs:NMTOKEN">
+      <xs:enumeration value="GET"/>
+      <xs:enumeration value="POST"/>
+      <xs:enumeration value="PUT"/>
+      <xs:enumeration value="HEAD"/>
+      <xs:enumeration value="DELETE"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:element name="include">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="tns:doc" minOccurs="0" maxOccurs="unbounded"/>
+      </xs:sequence>
+      <xs:attribute name="href" type="xs:anyURI"/>
+      <xs:anyAttribute namespace="##other" processContents="lax"/>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:element name="request">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="tns:doc" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:element ref="tns:param" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:element ref="tns:representation" minOccurs="0"
+          maxOccurs="unbounded"/>
+        <xs:any namespace="##other" processContents="lax" minOccurs="0"
+          maxOccurs="unbounded"/>
+      </xs:sequence>
+      <xs:anyAttribute namespace="##other" processContents="lax"/>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:element name="response">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="tns:doc" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:element ref="tns:param" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:element ref="tns:representation" minOccurs="0"
+          maxOccurs="unbounded"/>
+        <xs:any namespace="##other" processContents="lax" minOccurs="0"
+          maxOccurs="unbounded"/>
+      </xs:sequence>
+      <xs:attribute name="status" type="tns:statusCodeList"/>
+      <xs:anyAttribute namespace="##other" processContents="lax"/>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:simpleType name="uriList">
+    <xs:list itemType="xs:anyURI"/>
+  </xs:simpleType>
+
+  <xs:element name="representation">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="tns:doc" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:element ref="tns:param" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:any namespace="##other" processContents="lax" minOccurs="0"
+          maxOccurs="unbounded"/>
+      </xs:sequence>
+      <xs:attribute name="id" type="xs:ID"/>
+      <xs:attribute name="element" type="xs:QName"/>
+      <xs:attribute name="mediaType" type="xs:string"/>
+      <xs:attribute name="href" type="xs:anyURI"/>
+      <xs:attribute name="profile" type="tns:uriList"/>
+      <xs:anyAttribute namespace="##other" processContents="lax"/>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:simpleType name="statusCodeList">
+    <xs:list itemType="xs:unsignedInt"/>
+  </xs:simpleType>
+
+  <xs:simpleType name="ParamStyle">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="plain"/>
+      <xs:enumeration value="query"/>
+      <xs:enumeration value="matrix"/>
+      <xs:enumeration value="header"/>
+      <xs:enumeration value="template"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:element name="param">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="tns:doc" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:element ref="tns:option" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:element ref="tns:link" minOccurs="0"/>
+        <xs:any namespace="##other" processContents="lax" minOccurs="0"
+          maxOccurs="unbounded"/>
+      </xs:sequence>
+      <xs:attribute name="href" type="xs:anyURI"/>
+      <xs:attribute name="name" type="xs:NMTOKEN"/>
+      <xs:attribute name="style" type="tns:ParamStyle"/>
+      <xs:attribute name="id" type="xs:ID"/>
+      <xs:attribute name="type" type="xs:QName" default="xs:string"/>
+      <xs:attribute name="default" type="xs:string"/>
+      <xs:attribute name="required" type="xs:boolean" default="false"/>
+      <xs:attribute name="repeating" type="xs:boolean" default="false"/>
+      <xs:attribute name="fixed" type="xs:string"/>
+      <xs:attribute name="path" type="xs:string"/>
+      <xs:anyAttribute namespace="##other" processContents="lax"/>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:element name="option">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="tns:doc" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:any namespace="##other" processContents="lax" minOccurs="0"
+          maxOccurs="unbounded"/>
+      </xs:sequence>
+      <xs:attribute name="value" type="xs:string" use="required"/>
+      <xs:attribute name="mediaType" type="xs:string"/>
+      <xs:anyAttribute namespace="##other" processContents="lax"/>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:element name="link">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="tns:doc" minOccurs="0" maxOccurs="unbounded"/>
+        <xs:any namespace="##other" processContents="lax" minOccurs="0"
+          maxOccurs="unbounded"/>
+      </xs:sequence>
+      <xs:attribute name="resource_type" type="xs:anyURI"/>
+      <xs:attribute name="rel" type="xs:token"/>
+      <xs:attribute name="rev" type="xs:token"/>
+      <xs:anyAttribute namespace="##other" processContents="lax"/>
+    </xs:complexType>
+  </xs:element>
+
+</xs:schema>

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/src/test/java/org/apache/camel/component/linkedin/api/AbstractResourceIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/src/test/java/org/apache/camel/component/linkedin/api/AbstractResourceIntegrationTest.java b/components/camel-linkedin/camel-linkedin-api/src/test/java/org/apache/camel/component/linkedin/api/AbstractResourceIntegrationTest.java
new file mode 100644
index 0000000..1d4c536
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/src/test/java/org/apache/camel/component/linkedin/api/AbstractResourceIntegrationTest.java
@@ -0,0 +1,125 @@
+/**
+ * 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.linkedin.api;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+import javax.ws.rs.WebApplicationException;
+
+import org.apache.camel.component.linkedin.api.model.Error;
+import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Base class for resource tests.
+ */
+public class AbstractResourceIntegrationTest extends Assert {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(PeopleResourceIntegrationTest.class);
+    protected static final String DEFAULT_FIELDS = "";
+
+    protected static LinkedInOAuthRequestFilter requestFilter;
+    private static Properties properties;
+    private static OAuthToken token;
+    private static List<Object> resourceList = new ArrayList<Object>();
+
+    @BeforeClass
+    public static void beforeClass() throws Exception {
+        properties = new Properties();
+        properties.load(PeopleResourceIntegrationTest.class.getResourceAsStream("/test-options.properties"));
+
+        requestFilter = createOAuthHelper();
+    }
+
+    private static LinkedInOAuthRequestFilter createOAuthHelper() throws IOException {
+        final String userName = properties.getProperty("userName");
+        final String userPassword = properties.getProperty("userPassword");
+        final String clientId = properties.getProperty("clientId");
+        final String clientSecret = properties.getProperty("clientSecret");
+        final String redirectUri = properties.getProperty("redirectUri");
+
+        final OAuthScope[] scopes;
+        final String scope = properties.getProperty("scope");
+        if (scope != null) {
+            scopes = OAuthScope.fromValues(scope.split(","));
+        } else {
+            scopes = null;
+        }
+
+        final OAuthSecureStorage secureStorage = new OAuthSecureStorage() {
+            @Override
+            public OAuthToken getOAuthToken() {
+                return token;
+            }
+
+            @Override
+            public void saveOAuthToken(OAuthToken newToken) {
+                token = newToken;
+            }
+        };
+
+        final OAuthParams oAuthParams = new OAuthParams(userName, userPassword, secureStorage,
+            clientId, clientSecret, redirectUri, scopes);
+        return new LinkedInOAuthRequestFilter(oAuthParams, null, false);
+    }
+
+    @AfterClass
+    public static void afterClass() throws Exception {
+        // close all proxies
+        for (Object resource : resourceList) {
+            try {
+                WebClient.client(resource).close();
+            } catch (Exception ignore) {
+            }
+        }
+        if (requestFilter != null) {
+            requestFilter.close();
+        }
+        // TODO save and load token from test-options.properties
+    }
+
+    protected static <T> T getResource(Class<T> resourceClass) {
+        if (requestFilter == null) {
+            throw new IllegalStateException(AbstractResourceIntegrationTest.class.getName() +
+                ".beforeClass must be invoked before getResource");
+        }
+        final T resource = JAXRSClientFactory.create(LinkedInOAuthRequestFilter.BASE_ADDRESS, resourceClass,
+//            Arrays.asList(new Object[] { requestFilter, new LinkedInExceptionResponseFilter() } ));
+            Arrays.asList(new Object[]{requestFilter}));
+        resourceList.add(resource);
+        return resource;
+    }
+
+    protected void execute(Runnable runnable) {
+        try {
+            runnable.run();
+        } catch (WebApplicationException e) {
+            final org.apache.camel.component.linkedin.api.model.Error error = e.getResponse().readEntity(Error.class);
+            assertNotNull(error);
+            LOG.error("Error: {}", error.getMessage());
+            throw new LinkedInException(error, e.getResponse());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/src/test/java/org/apache/camel/component/linkedin/api/PeopleResourceIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/src/test/java/org/apache/camel/component/linkedin/api/PeopleResourceIntegrationTest.java b/components/camel-linkedin/camel-linkedin-api/src/test/java/org/apache/camel/component/linkedin/api/PeopleResourceIntegrationTest.java
new file mode 100644
index 0000000..6256b6a
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/src/test/java/org/apache/camel/component/linkedin/api/PeopleResourceIntegrationTest.java
@@ -0,0 +1,99 @@
+/**
+ * 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.linkedin.api;
+
+import java.util.Date;
+
+import org.apache.camel.component.linkedin.api.model.JobSuggestions;
+import org.apache.camel.component.linkedin.api.model.Person;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Integration test for {@link PeopleResource}.
+ */
+public class PeopleResourceIntegrationTest extends AbstractResourceIntegrationTest {
+
+    private static PeopleResource peopleResource;
+
+    @BeforeClass
+    public static void beforeClass() throws Exception {
+        AbstractResourceIntegrationTest.beforeClass();
+
+        final Class<PeopleResource> resourceClass = PeopleResource.class;
+        PeopleResourceIntegrationTest.peopleResource = getResource(resourceClass);
+    }
+
+    @Test
+    public void testGetPerson() throws Exception {
+        execute(new Runnable() {
+            @Override
+            public void run() {
+                final Person person = peopleResource.getPerson(":(id)", true);
+                assertNotNull(person);
+                assertNotNull(person.getId());
+                LOG.debug("getPerson result: " + person);
+            }
+        });
+    }
+
+    @Test(expected = LinkedInException.class)
+    public void testLinkedInError() throws Exception {
+        execute(new Runnable() {
+            @Override
+            public void run() {
+                peopleResource.getPerson("bad_fields_selector", true);
+            }
+        });
+    }
+
+    @Ignore("CXF swallows application exceptions from ClientResponseFilters")
+    @Test(expected = LinkedInException.class)
+    public void testLinkedInException() throws Exception {
+        try {
+            peopleResource.getPerson("bad_fields_selector", true);
+        } catch (LinkedInException e) {
+            assertNotNull(e.getError());
+            LOG.debug("getPerson error: " + e.getMessage());
+            throw e;
+        }
+    }
+
+    @Test
+    public void testOAuthTokenRefresh() throws Exception {
+        peopleResource.getPerson("", false);
+
+        // mark OAuth token as expired
+        final OAuthToken oAuthToken = requestFilter.getOAuthToken();
+        oAuthToken.setExpiryTime(new Date().getTime());
+
+        peopleResource.getPerson("", false);
+    }
+
+    @Test
+    public void testGetSuggestedJobs() throws Exception {
+        execute(new Runnable() {
+            @Override
+            public void run() {
+                final JobSuggestions suggestedJobs = peopleResource.getSuggestedJobs(DEFAULT_FIELDS);
+                assertNotNull(suggestedJobs);
+                LOG.debug("Suggested Jobs " + suggestedJobs.getJobs());
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/src/test/java/org/apache/camel/component/linkedin/api/SearchResourceIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/src/test/java/org/apache/camel/component/linkedin/api/SearchResourceIntegrationTest.java b/components/camel-linkedin/camel-linkedin-api/src/test/java/org/apache/camel/component/linkedin/api/SearchResourceIntegrationTest.java
new file mode 100644
index 0000000..002000b
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/src/test/java/org/apache/camel/component/linkedin/api/SearchResourceIntegrationTest.java
@@ -0,0 +1,47 @@
+/**
+ * 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.linkedin.api;
+
+import org.apache.camel.component.linkedin.api.model.CompanySearch;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Integration test for {@link org.apache.camel.component.linkedin.api.SearchResource}
+ */
+public class SearchResourceIntegrationTest extends AbstractResourceIntegrationTest {
+
+    private static SearchResource searchResource;
+
+    @BeforeClass
+    public static void beforeClass() throws Exception {
+        AbstractResourceIntegrationTest.beforeClass();
+        searchResource = getResource(SearchResource.class);
+    }
+
+    @Test
+    public void testSearchCompanies() {
+        execute(new Runnable() {
+            @Override
+            public void run() {
+                final CompanySearch companySearch = searchResource.searchCompanies(DEFAULT_FIELDS, "linkedin", null, null,
+                    null, null, null, null);
+                assertNotNull(companySearch);
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/pom.xml b/components/camel-linkedin/camel-linkedin-component/pom.xml
new file mode 100644
index 0000000..42311e2
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/pom.xml
@@ -0,0 +1,280 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<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.component.linkedin</groupId>
+    <artifactId>camel-linkedin-parent</artifactId>
+    <version>2.14-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>camel-linkedin</artifactId>
+  <packaging>bundle</packaging>
+  <name>Camel LinkedIn Component</name>
+  <description>Camel Component for LinkedIn</description>
+
+  <properties>
+    <schemeName>linkedin</schemeName>
+    <componentName>LinkedIn</componentName>
+    <componentPackage>org.apache.camel.component.linkedin</componentPackage>
+    <outPackage>org.apache.camel.component.linkedin.internal</outPackage>
+
+    <camel.osgi.export.pkg>${componentPackage}</camel.osgi.export.pkg>
+    <camel.osgi.private.pkg>${outPackage}</camel.osgi.private.pkg>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel.component.linkedin</groupId>
+      <artifactId>camel-linkedin-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <!-- Camel annotations in runtime 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>org.apache.camel.component.linkedin</groupId>
+      <artifactId>camel-linkedin-api</artifactId>
+      <version>${project.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>comments</apiName>
+                  <proxyClass>org.apache.camel.component.linkedin.api.CommentsResource</proxyClass>
+                  <fromJavadoc/>
+                </api>
+                <api>
+                  <apiName>companies</apiName>
+                  <proxyClass>org.apache.camel.component.linkedin.api.CompaniesResource</proxyClass>
+                  <fromJavadoc/>
+                  <nullableOptions>
+                    <nullableOption>companySizes</nullableOption>
+                    <nullableOption>count</nullableOption>
+                    <nullableOption>email_domain</nullableOption>
+                    <nullableOption>end_timestamp</nullableOption>
+                    <nullableOption>event_type</nullableOption>
+                    <nullableOption>geos</nullableOption>
+                    <nullableOption>industries</nullableOption>
+                    <nullableOption>is_company_admin</nullableOption>
+                    <nullableOption>jobFunc</nullableOption>
+                    <nullableOption>secure_urls</nullableOption>
+                    <nullableOption>seniorities</nullableOption>
+                    <nullableOption>start</nullableOption>
+                    <nullableOption>start_timestamp</nullableOption>
+                    <nullableOption>time_granularity</nullableOption>
+                  </nullableOptions>
+                </api>
+                <api>
+                  <apiName>groups</apiName>
+                  <proxyClass>org.apache.camel.component.linkedin.api.GroupsResource</proxyClass>
+                  <fromJavadoc/>
+                </api>
+                <api>
+                  <apiName>jobs</apiName>
+                  <proxyClass>org.apache.camel.component.linkedin.api.JobsResource</proxyClass>
+                  <fromJavadoc/>
+                </api>
+                <api>
+                  <apiName>people</apiName>
+                  <proxyClass>org.apache.camel.component.linkedin.api.PeopleResource</proxyClass>
+                  <fromJavadoc/>
+                  <nullableOptions>
+                    <nullableOption>after</nullableOption>
+                    <nullableOption>before</nullableOption>
+                    <nullableOption>category</nullableOption>
+                    <nullableOption>count</nullableOption>
+                    <nullableOption>membership_state</nullableOption>
+                    <nullableOption>modified_since</nullableOption>
+                    <nullableOption>order</nullableOption>
+                    <nullableOption>public_profile_url</nullableOption>
+                    <nullableOption>role</nullableOption>
+                    <nullableOption>scope</nullableOption>
+                    <nullableOption>secure_urls</nullableOption>
+                    <nullableOption>show_hidden_members</nullableOption>
+                    <nullableOption>start</nullableOption>
+                    <nullableOption>type</nullableOption>
+                  </nullableOptions>
+                </api>
+                <api>
+                  <apiName>posts</apiName>
+                  <proxyClass>org.apache.camel.component.linkedin.api.PostsResource</proxyClass>
+                  <fromJavadoc/>
+                  <nullableOptions>
+                    <nullableOption>count</nullableOption>
+                    <nullableOption>start</nullableOption>
+                  </nullableOptions>
+                </api>
+                <api>
+                  <apiName>search</apiName>
+                  <proxyClass>org.apache.camel.component.linkedin.api.SearchResource</proxyClass>
+                  <fromJavadoc/>
+                  <nullableOptions>
+                    <nullableOption>company_name</nullableOption>
+                    <nullableOption>count</nullableOption>
+                    <nullableOption>country_code</nullableOption>
+                    <nullableOption>current_company</nullableOption>
+                    <nullableOption>current_school</nullableOption>
+                    <nullableOption>current_title</nullableOption>
+                    <nullableOption>distance</nullableOption>
+                    <nullableOption>facet</nullableOption>
+                    <nullableOption>facets</nullableOption>
+                    <nullableOption>first_name</nullableOption>
+                    <nullableOption>hq_only</nullableOption>
+                    <nullableOption>job_title</nullableOption>
+                    <nullableOption>keywords</nullableOption>
+                    <nullableOption>last_name</nullableOption>
+                    <nullableOption>postal_code</nullableOption>
+                    <nullableOption>school_name</nullableOption>
+                    <nullableOption>sort</nullableOption>
+                    <nullableOption>start</nullableOption>
+                    <nullableOption>title</nullableOption>
+                  </nullableOptions>
+                </api>
+              </apis>
+              <aliases>
+                <alias>
+                  <methodPattern>(add|get|remove|search)(.+)</methodPattern>
+                  <methodAlias>$2</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>
+        <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>
+
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInComponent.java b/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInComponent.java
new file mode 100644
index 0000000..4434f8c
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInComponent.java
@@ -0,0 +1,106 @@
+/**
+ * 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.linkedin;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.component.linkedin.api.LinkedInOAuthRequestFilter;
+import org.apache.camel.component.linkedin.api.OAuthParams;
+import org.apache.camel.component.linkedin.internal.CachingOAuthSecureStorage;
+import org.apache.camel.component.linkedin.internal.LinkedInApiCollection;
+import org.apache.camel.component.linkedin.internal.LinkedInApiName;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.util.component.AbstractApiComponent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Represents the component that manages {@link LinkedInEndpoint}.
+ */
+@UriEndpoint(scheme = "linkedin", consumerClass = LinkedInConsumer.class, consumerPrefix = "consumer")
+public class LinkedInComponent extends AbstractApiComponent<LinkedInApiName, LinkedInConfiguration, LinkedInApiCollection> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(LinkedInComponent.class);
+
+    private LinkedInOAuthRequestFilter requestFilter;
+
+    public LinkedInComponent() {
+        super(LinkedInEndpoint.class, LinkedInApiName.class, LinkedInApiCollection.getCollection());
+    }
+
+    public LinkedInComponent(CamelContext context) {
+        super(context, LinkedInEndpoint.class, LinkedInApiName.class, LinkedInApiCollection.getCollection());
+    }
+
+    @Override
+    protected LinkedInApiName getApiName(String apiNameStr) throws IllegalArgumentException {
+        return LinkedInApiName.fromValue(apiNameStr);
+    }
+
+    @Override
+    protected Endpoint createEndpoint(String uri, String methodName, LinkedInApiName apiName,
+                                      LinkedInConfiguration endpointConfiguration) {
+        return new LinkedInEndpoint(uri, this, apiName, methodName, endpointConfiguration);
+    }
+
+    public synchronized LinkedInOAuthRequestFilter getRequestFilter(LinkedInConfiguration endpointConfiguration) {
+        if (endpointConfiguration.equals(configuration)) {
+            if (requestFilter == null) {
+                requestFilter = createRequestFilter(this.configuration);
+            }
+            return requestFilter;
+        } else {
+            return createRequestFilter(endpointConfiguration);
+        }
+    }
+
+    private static LinkedInOAuthRequestFilter createRequestFilter(LinkedInConfiguration configuration) {
+        // validate configuration
+        configuration.validate();
+
+        return new LinkedInOAuthRequestFilter(getOAuthParams(configuration),
+            configuration.getHttpParams(), configuration.isLazyAuth());
+    }
+
+    private static OAuthParams getOAuthParams(LinkedInConfiguration configuration) {
+        return new OAuthParams(configuration.getUserName(), configuration.getUserPassword(),
+            new CachingOAuthSecureStorage(configuration.getSecureStorage()), configuration.getClientId(), configuration.getClientSecret(),
+            configuration.getRedirectUri(), configuration.getScopes());
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        if (requestFilter != null) {
+            closeLogException(requestFilter);
+        }
+    }
+
+    protected void closeRequestFilter(LinkedInOAuthRequestFilter requestFilter) {
+        // only close if not a shared filter
+        if (this.requestFilter != requestFilter) {
+            closeLogException(requestFilter);
+        }
+    }
+
+    private void closeLogException(LinkedInOAuthRequestFilter requestFilter) {
+        try {
+            requestFilter.close();
+        } catch (Exception e) {
+            LOG.warn("Error closing OAuth2 request filter: " + e.getMessage(), e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInConfiguration.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInConfiguration.java b/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInConfiguration.java
new file mode 100644
index 0000000..8dd9fa1
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInConfiguration.java
@@ -0,0 +1,155 @@
+/**
+ * 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.linkedin;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import org.apache.camel.component.linkedin.api.OAuthScope;
+import org.apache.camel.component.linkedin.api.OAuthSecureStorage;
+import org.apache.camel.spi.UriParams;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+/**
+ * Component configuration for LinkedIn component.
+ */
+@UriParams
+public class LinkedInConfiguration {
+
+    private String userName;
+    private String userPassword;
+
+    private OAuthSecureStorage secureStorage;
+
+    private String clientId;
+    private String clientSecret;
+
+    private OAuthScope[] scopes;
+    private String redirectUri;
+
+
+    private Map<String, Object> httpParams;
+
+    private boolean lazyAuth = true;
+
+    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 OAuthSecureStorage getSecureStorage() {
+        return secureStorage;
+    }
+
+    public void setSecureStorage(OAuthSecureStorage secureStorage) {
+        this.secureStorage = secureStorage;
+    }
+
+    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 OAuthScope[] getScopes() {
+        return scopes;
+    }
+
+    public void setScopes(OAuthScope[] scopes) {
+        this.scopes = scopes;
+    }
+
+    public String getRedirectUri() {
+        return redirectUri;
+    }
+
+    public void setRedirectUri(String redirectUri) {
+        this.redirectUri = redirectUri;
+    }
+
+    public Map<String, Object> getHttpParams() {
+        return httpParams;
+    }
+
+    public void setHttpParams(Map<String, Object> httpParams) {
+        this.httpParams = httpParams;
+    }
+
+    public boolean isLazyAuth() {
+        return lazyAuth;
+    }
+
+    public void setLazyAuth(boolean lazyAuth) {
+        this.lazyAuth = lazyAuth;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof LinkedInConfiguration) {
+            final LinkedInConfiguration other = (LinkedInConfiguration) obj;
+            return (userName == null ? other.userName == null : userName.equals(other.userName))
+                && (userPassword == null ? other.userPassword == null : userPassword.equals(other.userPassword))
+                && secureStorage == other.secureStorage
+                && (clientId == null ? other.clientId == null : clientId.equals(other.clientId))
+                && (clientSecret == null ? other.clientSecret == null : clientSecret.equals(other.clientSecret))
+                && (redirectUri == null ? other.redirectUri == null : redirectUri.equals(other.redirectUri))
+                && Arrays.equals(scopes, other.scopes)
+                && (httpParams == null ? other.httpParams == null : httpParams.equals(other.httpParams))
+                && (lazyAuth == other.lazyAuth);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder().append(userName).append(userPassword).append(secureStorage)
+            .append(clientId).append(clientSecret)
+            .append(redirectUri).append(scopes).append(httpParams).append(lazyAuth).toHashCode();
+    }
+
+    public void validate() throws IllegalArgumentException {
+        ObjectHelper.notEmpty(userName, "userName");
+        if (ObjectHelper.isEmpty(userPassword) && secureStorage == null) {
+            throw new IllegalArgumentException("Property userPassword or secureStorage is required");
+        }
+        ObjectHelper.notEmpty(clientId, "clientId");
+        ObjectHelper.notEmpty(clientSecret, "clientSecret");
+        ObjectHelper.notEmpty(redirectUri, "redirectUri");
+    }
+}


[10/23] camel git commit: Fixed test-salesforce-login.properties check

Posted by dh...@apache.org.
Fixed test-salesforce-login.properties check


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

Branch: refs/heads/trunk
Commit: ec0e3a736c6660aee5123cdbe99a7581ead7dec6
Parents: 8a39820
Author: Dhiraj Bokde <db...@fusesource.com>
Authored: Wed Jun 5 14:38:25 2013 -0700
Committer: Dhiraj Bokde <db...@fusesource.com>
Committed: Wed Jun 5 14:38:25 2013 -0700

----------------------------------------------------------------------
 .../component/salesforce/LoginConfigHelper.java | 52 ++++++++++++--------
 .../CamelSalesforceMojoIntegrationTest.java     | 33 +++++++------
 2 files changed, 50 insertions(+), 35 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/ec0e3a73/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java
index 1f8b480..e3c07a9 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.salesforce;
 import org.junit.Assert;
 
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Properties;
@@ -27,33 +28,42 @@ public class LoginConfigHelper extends Assert {
 
     private static final String TEST_LOGIN_PROPERTIES = "test-salesforce-login.properties";
 
-    public static SalesforceLoginConfig getLoginConfig() throws IllegalAccessException, IOException {
+    public static SalesforceLoginConfig getLoginConfig() throws IOException {
 
         // load test-salesforce-login properties
         Properties properties = new Properties();
-        InputStream stream = new FileInputStream(TEST_LOGIN_PROPERTIES);
-        if (null == stream) {
-            throw new IllegalArgumentException("Create a properties file named " +
+        InputStream stream = null;
+        try {
+            stream = new FileInputStream(TEST_LOGIN_PROPERTIES);
+            properties.load(stream);
+
+            final SalesforceLoginConfig config = new SalesforceLoginConfig(
+                properties.getProperty("loginUrl", SalesforceLoginConfig.DEFAULT_LOGIN_URL),
+                properties.getProperty("clientId"),
+                properties.getProperty("clientSecret"),
+                properties.getProperty("userName"),
+                properties.getProperty("password"),
+                Boolean.parseBoolean(properties.getProperty("lazyLogin", "false")));
+
+            assertNotNull("Null loginUrl", config.getLoginUrl());
+            assertNotNull("Null clientId", config.getClientId());
+            assertNotNull("Null clientSecret", config.getClientSecret());
+            assertNotNull("Null userName", config.getUserName());
+            assertNotNull("Null password", config.getPassword());
+
+            return config;
+
+        } catch (FileNotFoundException e) {
+            throw new FileNotFoundException("Create a properties file named " +
                 TEST_LOGIN_PROPERTIES + " with clientId, clientSecret, userName, and password" +
                 " for a Salesforce account with the Merchandise object from Salesforce Guides.");
+        } finally {
+            if (stream != null) {
+                try {
+                    stream.close();
+                } catch (IOException ignore) {}
+            }
         }
-        properties.load(stream);
-
-        final SalesforceLoginConfig config = new SalesforceLoginConfig(
-            properties.getProperty("loginUrl", SalesforceLoginConfig.DEFAULT_LOGIN_URL),
-            properties.getProperty("clientId"),
-            properties.getProperty("clientSecret"),
-            properties.getProperty("userName"),
-            properties.getProperty("password"),
-            Boolean.parseBoolean(properties.getProperty("lazyLogin", "false")));
-
-        assertNotNull("Null loginUrl", config.getLoginUrl());
-        assertNotNull("Null clientId", config.getClientId());
-        assertNotNull("Null clientSecret", config.getClientSecret());
-        assertNotNull("Null userName", config.getUserName());
-        assertNotNull("Null password", config.getPassword());
-
-        return config;
     }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/ec0e3a73/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 781c592..b580436 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
@@ -20,10 +20,7 @@ import org.apache.maven.plugin.logging.SystemStreamLog;
 import org.junit.Assert;
 import org.junit.Test;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
 import java.util.Properties;
 
 public class CamelSalesforceMojoIntegrationTest {
@@ -66,20 +63,28 @@ public class CamelSalesforceMojoIntegrationTest {
         // TODO check that the generated code compiles
     }
 
-    private void setLoginProperties(CamelSalesforceMojo mojo) throws IllegalAccessException, IOException {
+    private void setLoginProperties(CamelSalesforceMojo mojo) throws IOException {
         // load test-salesforce-login properties
         Properties properties = new Properties();
-        InputStream stream = new FileInputStream(TEST_LOGIN_PROPERTIES);
-        if (null == stream) {
-            throw new IllegalAccessException("Create a properties file named " +
-                TEST_LOGIN_PROPERTIES + " with clientId, clientSecret, userName, password and a testId" +
+        InputStream stream = null;
+        try {
+            stream = new FileInputStream(TEST_LOGIN_PROPERTIES);
+            properties.load(stream);
+            mojo.clientId= properties.getProperty("clientId");
+            mojo.clientSecret= properties.getProperty("clientSecret");
+            mojo.userName= properties.getProperty("userName");
+            mojo.password= properties.getProperty("password");
+        } catch (FileNotFoundException e) {
+            throw new FileNotFoundException("Create a properties file named " +
+                TEST_LOGIN_PROPERTIES + " with clientId, clientSecret, userName, and password" +
                 " for a Salesforce account with the Merchandise object from Salesforce Guides.");
+        } finally {
+            if (stream != null) {
+                try {
+                    stream.close();
+                } catch (IOException ignore) {}
+            }
         }
-        properties.load(stream);
-        mojo.clientId= properties.getProperty("clientId");
-        mojo.clientSecret= properties.getProperty("clientSecret");
-        mojo.userName= properties.getProperty("userName");
-        mojo.password= properties.getProperty("password");
     }
 
 }


[18/23] camel git commit: Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/camel into linkedin-component

Posted by dh...@apache.org.
Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/camel into linkedin-component


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

Branch: refs/heads/linkedin-component
Commit: 32dcec96095621217d6cf2724d4934f6a4b2187a
Parents: b490a90 b8f687a
Author: Dhiraj Bokde <dh...@yahoo.com>
Authored: Thu Jul 10 18:05:28 2014 -0700
Committer: Dhiraj Bokde <dh...@yahoo.com>
Committed: Thu Jul 10 18:05:28 2014 -0700

----------------------------------------------------------------------
 apache-camel/pom.xml                            |   6 +-
 .../src/main/descriptors/common-bin.xml         |   5 +-
 .../java/org/apache/camel/RecipientList.java    |   1 +
 .../mbean/ManagedBacklogDebuggerMBean.java      |   6 +
 .../mbean/ManagedBacklogTracerMBean.java        |   6 +
 .../mbean/ManagedCamelContextMBean.java         |   2 +-
 .../ManagedStreamCachingStrategyMBean.java      |   2 +-
 .../mbean/ManagedThreadPoolMBean.java           |   6 +
 .../management/mbean/ManagedTracerMBean.java    |   6 +
 .../apache/camel/component/bean/MethodInfo.java |   1 +
 .../component/file/GenericFileEndpoint.java     |  11 +
 .../GenericFileExclusiveReadLockStrategy.java   |   7 +-
 .../FileChangedExclusiveReadLockStrategy.java   |   2 +
 .../strategy/FileProcessStrategyFactory.java    |   4 +
 .../FileRenameExclusiveReadLockStrategy.java    |  15 +-
 .../GenericFileProcessStrategyFactory.java      |   4 +
 ...ericFileRenameExclusiveReadLockStrategy.java |   5 +
 .../MarkerFileExclusiveReadLockStrategy.java    |  18 +
 .../apache/camel/impl/DefaultCamelContext.java  |   5 +
 .../org/apache/camel/impl/JndiRegistry.java     |   8 +-
 .../mbean/ManagedBacklogDebugger.java           |   8 +
 .../management/mbean/ManagedBacklogTracer.java  |   8 +
 .../management/mbean/ManagedThreadPool.java     |   8 +
 .../camel/management/mbean/ManagedTracer.java   |   8 +
 .../apache/camel/model/MulticastDefinition.java |  37 +-
 .../camel/model/RecipientListDefinition.java    |  38 +-
 .../camel/model/RouteDefinitionHelper.java      |  12 +-
 .../org/apache/camel/model/SplitDefinition.java |  35 +-
 .../apache/camel/model/ThrottleDefinition.java  |   2 +-
 .../org/apache/camel/processor/Enricher.java    |  18 +-
 .../camel/processor/MulticastProcessor.java     |  45 +-
 .../apache/camel/processor/RecipientList.java   |  11 +-
 .../camel/processor/RecipientListProcessor.java |  12 +-
 .../org/apache/camel/processor/Splitter.java    |  11 +-
 .../org/apache/camel/processor/Throttler.java   |   3 +-
 .../ThrottlerRejectedExecutionException.java    |  28 ++
 .../apache/camel/support/RecordableReader.java  |  94 ++++
 .../support/XMLTokenExpressionIterator.java     |  41 +-
 .../org/apache/camel/util/MessageHelper.java    |   3 +-
 .../bean/BeanMethodWithExchangeTest.java        |  68 +++
 ...ConsumerBridgeRouteExceptionHandlerTest.java |   5 +
 .../FileConsumerCustomExceptionHandlerTest.java |   5 +
 .../FileChangedReadLockMarkerFileFalseTest.java |  32 ++
 .../org/apache/camel/impl/JndiRegistryTest.java |  59 +++
 .../SplitterParallelAggregateTest.java          | 135 ++++++
 .../apache/camel/processor/SplitterTest.java    |  21 +
 .../apache/camel/processor/ThrottlerTest.java   |   5 +-
 .../enricher/EnricherSendEventTest.java         | 118 +++++
 .../support/RecordableInputStreamTest.java      |   9 +-
 .../camel/support/RecordableReaderTest.java     | 104 ++++
 .../XMLTokenExpressionIteratorCharsetTest.java  | 116 +++++
 .../support/XMLTokenExpressionIteratorTest.java |  33 ++
 .../websocket/WebsocketComponent.java           |   1 +
 .../atmosphere/websocket/WebsocketEndpoint.java |   5 +
 ...ponentConfigurationAndDocumentationTest.java |  58 +++
 .../camel/dataformat/bindy/FormatFactory.java   |   8 +-
 components/camel-box/pom.xml                    |   8 +-
 .../component/box/AbstractBoxTestSupport.java   |  16 +
 .../apache/camel/component/cxf/CxfProducer.java |   4 +-
 .../component/cxf/jaxrs/CxfRsProducer.java      |  62 ++-
 .../src/main/resources/META-INF/spring.schemas  |   3 +
 .../component/cxf/jaxrs/CxfRsProducerTest.java  |   2 +
 .../component/cxf/jaxrs/CxfRsSpringProducer.xml |   3 +-
 .../FtpChangedExclusiveReadLockStrategy.java    |   5 +
 .../strategy/FtpProcessStrategyFactory.java     |   8 +
 .../SftpChangedExclusiveReadLockStrategy.java   |   5 +
 .../component/gae/auth/GAuthComponent.java      |   8 +-
 .../camel/component/gae/auth/GAuthEndpoint.java |   8 +
 .../component/gae/http/GHttpComponent.java      |   3 +
 .../camel/component/gae/http/GHttpEndpoint.java |   9 +-
 .../component/gae/login/GLoginComponent.java    |   8 +-
 .../component/gae/login/GLoginEndpoint.java     |  10 +
 .../component/gae/mail/GMailComponent.java      |   8 +-
 .../camel/component/gae/mail/GMailEndpoint.java |   8 +
 .../component/gae/task/GTaskComponent.java      |   3 +
 .../camel/component/gae/task/GTaskEndpoint.java |   4 +
 ...ponentConfigurationAndDocumentationTest.java |  57 +++
 ...ponentConfigurationAndDocumentationTest.java |  58 +++
 ...ponentConfigurationAndDocumentationTest.java |  57 +++
 ...ponentConfigurationAndDocumentationTest.java |  57 +++
 ...ponentConfigurationAndDocumentationTest.java |  56 +++
 .../component/hazelcast/HazelcastComponent.java |  37 +-
 ...astComponentInstanceReferenceSpringTest.java |  49 ++
 .../hazelcast/HazelcastListProducerTest.java    |   8 +-
 ...mel-context-hazelcast-instance-reference.xml |  49 ++
 .../component/netty/NettyWorkerPoolBuilder.java |   2 +-
 .../component/rabbitmq/RabbitMQConsumer.java    |   1 -
 .../component/rabbitmq/RabbitMQProducer.java    |   8 +-
 .../camel/scala/dsl/SMulticastDefinition.scala  |   5 +
 .../camel/scala/dsl/SSplitDefinition.scala      |   4 +-
 .../apache/camel/scala/dsl/MulticastTest.scala  |   2 +-
 .../camel/builder/script/ScriptBuilder.java     |   4 +
 .../script/LanguagePythonStatementsTest.java    |  46 ++
 .../camel-script/src/test/resources/mypython.py |   3 +
 .../component/servlet/ServletComponent.java     |   6 +
 .../src/main/resources/META-INF/spring.schemas  |   3 +
 .../src/main/resources/META-INF/spring.schemas  |   3 +
 .../src/main/resources/META-INF/spring.schemas  |   6 +
 .../SpringJmxDumpCBRRoutesAsXmlTest.java        |  55 +++
 .../SpringJmxDumpCBRRouteAsXmlTest.xml          |  43 ++
 .../apache/camel/spring/processor/throttler.xml |   2 +-
 components/camel-test-spring/pom.xml            |  39 +-
 components/camel-test-spring3/pom.xml           |  92 ++++
 .../CamelSpringDelegatingTestContextLoader.java | 321 +++++++++++++
 .../spring/CamelSpringJUnit4ClassRunner.java    |  88 ++++
 .../spring/CamelSpringTestContextLoader.java    | 473 +++++++++++++++++++
 ...gTestContextLoaderTestExecutionListener.java |  36 ++
 .../test/spring/CamelSpringTestHelper.java      |  99 ++++
 .../test/spring/CamelSpringTestSupport.java     | 220 +++++++++
 .../apache/camel/test/spring/DisableJmx.java    |  43 ++
 .../spring/DisableJmxTestExecutionListener.java |  39 ++
 .../apache/camel/test/spring/ExcludeRoutes.java |  44 ++
 .../test/spring/LazyLoadTypeConverters.java     |  44 ++
 .../apache/camel/test/spring/MockEndpoints.java |  43 ++
 .../camel/test/spring/MockEndpointsAndSkip.java |  43 ++
 .../camel/test/spring/ProvidesBreakpoint.java   |  36 ++
 .../camel/test/spring/ShutdownTimeout.java      |  49 ++
 .../spring/StopWatchTestExecutionListener.java  |  60 +++
 .../apache/camel/test/spring/UseAdviceWith.java |  49 ++
 .../src/main/resources/META-INF/LICENSE.txt     | 203 ++++++++
 .../src/main/resources/META-INF/NOTICE.txt      |  11 +
 .../AdviceWithOnExceptionMultipleIssueTest.java | 116 +++++
 .../test/issues/MockEndpointsAndSkipTest.java   |  46 ++
 .../patterns/DebugSpringCamelContextTest.java   |  40 ++
 .../camel/test/patterns/DebugSpringTest.java    |  81 ++++
 .../camel/test/patterns/MyProduceBean.java      |  41 ++
 .../apache/camel/test/patterns/MySender.java    |  25 +
 .../camel/test/patterns/ProduceBeanTest.java    |  42 ++
 .../test/patterns/ProducerBeanInjectTest.java   |  38 ++
 .../spring/CamelSpringActiveProfileTest.java    |  56 +++
 ...ssRunnerDisableJmxInheritedOverrideTest.java |  32 ++
 ...Unit4ClassRunnerDisableJmxInheritedTest.java |  21 +
 ...elSpringJUnit4ClassRunnerDisableJmxTest.java |  33 ++
 ...pringJUnit4ClassRunnerExcludeRoutesTest.java |  29 ++
 ...LoadTypeConvertersInheritedOverrideTest.java |  33 ++
 ...nnerLazyLoadTypeConvertersInheritedTest.java |  21 +
 ...t4ClassRunnerLazyLoadTypeConvertersTest.java |  33 ++
 ...nit4ClassRunnerMockEndpointsAndSkipTest.java |  56 +++
 ...pringJUnit4ClassRunnerMockEndpointsTest.java |  57 +++
 .../CamelSpringJUnit4ClassRunnerPlainTest.java  | 126 +++++
 ...sRunnerProvidesBreakpointInherritedTest.java |  22 +
 ...JUnit4ClassRunnerProvidesBreakpointTest.java |  67 +++
 ...nerShutdownTimeoutInheritedOverrideTest.java |  34 ++
 ...ClassRunnerShutdownTimeoutInheritedTest.java |  22 +
 ...ingJUnit4ClassRunnerShutdownTimeoutTest.java |  34 ++
 ...pringJUnit4ClassRunnerUseAdviceWithTest.java |  52 ++
 ...CamelSpringTestSupportActiveProfileTest.java |  51 ++
 .../camel/test/spring/TestRouteBuilder.java     |  30 ++
 .../src/test/resources/jndi.properties          |  22 +
 .../src/test/resources/log4j.properties         |  37 ++
 .../AdviceWithOnExceptionMultipleIssueTest.xml  |  47 ++
 .../test/issues/MockEndpointsAndSkipTest.xml    |  35 ++
 .../test/patterns/ProduceBeanInjectTest.xml     |  39 ++
 .../camel/test/patterns/ProduceBeanTest.xml     |  33 ++
 .../camel/test/patterns/applicationContext.xml  |  38 ++
 .../CamelSpringActiveProfileTest-context.xml    |  41 ++
 ...SpringJUnit4ClassRunnerPlainTest-context.xml |  50 ++
 .../apache/camel/test/spring/test.properties    |  18 +
 .../camel/dataformat/zipfile/ZipIterator.java   |  12 +-
 components/pom.xml                              |   9 +-
 examples/camel-example-box-osgi/README.txt      |  38 ++
 examples/camel-example-box-osgi/pom.xml         |  85 ++++
 .../src/main/resources/META-INF/LICENSE.txt     | 203 ++++++++
 .../src/main/resources/META-INF/NOTICE.txt      |  11 +
 .../resources/META-INF/spring/camel-context.xml |  55 +++
 .../src/test/resources/log4j.properties         |  31 ++
 parent/pom.xml                                  |  45 +-
 .../features/src/main/resources/features.xml    |  31 ++
 tests/camel-itest-spring32/pom.xml              |  52 +-
 .../camel/itest/async/MyAsyncComponent.java     |  37 ++
 .../camel/itest/async/MyAsyncEndpoint.java      |  73 +++
 .../camel/itest/async/MyAsyncProducer.java      |  77 +++
 .../ibatis/AsyncEndpointTransacted2Test.java    |  96 ++++
 .../ibatis/AsyncEndpointTransactedTest.java     |  88 ++++
 .../apache/camel/itest/ibatis/DummyTable.java   |  35 ++
 .../camel/itest/ibatis/DummyTableImpl.java      |  54 +++
 .../camel/itest/ibatis/ExceptionRethrower.java  |  30 ++
 .../camel/itest/ibatis/LoggingPipelineTest.java |  95 ++++
 .../ibatis/PartiallyTransactedPipelineTest.java |  99 ++++
 ...edExceptionClauseAfterTransactedTagTest.java |  99 ++++
 .../itest/ibatis/TransactedFullExampleTest.java | 127 +++++
 .../ibatis/TransactedOnCompletionTest.java      |  99 ++++
 .../itest/ibatis/TransactedOnExceptionTest.java |  99 ++++
 .../itest/ibatis/TransactedPipelineTest.java    |  94 ++++
 .../itest/ibatis/TransactedTryCatchTest.java    | 107 +++++
 .../src/test/resources/ibatis-config.xml        |   8 +
 .../ibatis/AsyncEndpointTransacted2Test.xml     |  52 ++
 .../ibatis/AsyncEndpointTransactedTest.xml      |  41 ++
 .../camel/itest/ibatis/LoggingPipelineTest.xml  |  43 ++
 .../ibatis/PartiallyTransactedPipelineTest.xml  |  37 ++
 ...nsactedExceptionClauseAfterTransactedTag.xml |  46 ++
 .../itest/ibatis/TransactedFullExampleTest.xml  |  58 +++
 .../itest/ibatis/TransactedOnCompletionTest.xml |  39 ++
 .../itest/ibatis/TransactedOnExceptionTest.xml  |  44 ++
 .../itest/ibatis/TransactedPipelineTest.xml     |  36 ++
 .../itest/ibatis/TransactedTryCatchTest.xml     |  48 ++
 .../camel/itest/ibatis/database-context.xml     |  44 ++
 .../src/test/resources/table.xml                |  13 +
 .../src/test/resources/transactions.properties  |  43 ++
 tests/camel-itest/pom.xml                       |  34 +-
 .../apache/camel/itest/http/Http4RouteTest.java |  37 +-
 .../ibatis/AsyncEndpointTransacted2Test.java    |  96 ----
 .../ibatis/AsyncEndpointTransactedTest.java     |  88 ----
 .../apache/camel/itest/ibatis/DummyTable.java   |  35 --
 .../camel/itest/ibatis/DummyTableImpl.java      |  54 ---
 .../camel/itest/ibatis/ExceptionRethrower.java  |  30 --
 .../camel/itest/ibatis/LoggingPipelineTest.java |  95 ----
 .../ibatis/PartiallyTransactedPipelineTest.java |  99 ----
 ...edExceptionClauseAfterTransactedTagTest.java |  99 ----
 .../itest/ibatis/TransactedFullExampleTest.java | 127 -----
 .../ibatis/TransactedOnCompletionTest.java      |  99 ----
 .../itest/ibatis/TransactedOnExceptionTest.java |  99 ----
 .../itest/ibatis/TransactedPipelineTest.java    |  94 ----
 .../itest/ibatis/TransactedTryCatchTest.java    | 107 -----
 .../src/test/resources/ibatis-config.xml        |   8 -
 .../ibatis/AsyncEndpointTransacted2Test.xml     |  52 --
 .../ibatis/AsyncEndpointTransactedTest.xml      |  41 --
 .../camel/itest/ibatis/LoggingPipelineTest.xml  |  43 --
 .../ibatis/PartiallyTransactedPipelineTest.xml  |  37 --
 ...nsactedExceptionClauseAfterTransactedTag.xml |  46 --
 .../itest/ibatis/TransactedFullExampleTest.xml  |  58 ---
 .../itest/ibatis/TransactedOnCompletionTest.xml |  39 --
 .../itest/ibatis/TransactedOnExceptionTest.xml  |  44 --
 .../itest/ibatis/TransactedPipelineTest.xml     |  36 --
 .../itest/ibatis/TransactedTryCatchTest.xml     |  48 --
 .../camel/itest/ibatis/database-context.xml     |  44 --
 tests/camel-itest/src/test/resources/table.xml  |  13 -
 .../src/test/resources/transactions.properties  |  43 --
 tooling/camel-manual/pom.xml                    |  14 +-
 229 files changed, 8106 insertions(+), 1846 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/32dcec96/components/camel-box/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/camel/blob/32dcec96/components/camel-box/src/test/java/org/apache/camel/component/box/AbstractBoxTestSupport.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/camel/blob/32dcec96/components/pom.xml
----------------------------------------------------------------------


[16/23] camel git commit: CAMEL-6568: Initial version of LinkedIn component

Posted by dh...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/src/main/resources/linkedin-api-schema.xsd
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/src/main/resources/linkedin-api-schema.xsd b/components/camel-linkedin/camel-linkedin-api/src/main/resources/linkedin-api-schema.xsd
new file mode 100644
index 0000000..ed19f73
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/src/main/resources/linkedin-api-schema.xsd
@@ -0,0 +1,2255 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
+  <!-- Copied with permission from the linkedin-j library https://code.google.com/p/linkedin-j/ -->
+  <xs:element name="activity">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element minOccurs="0" ref="timestamp"/>
+        <xs:element minOccurs="0" ref="content-type"/>
+        <xs:element ref="body"/>
+        <xs:element minOccurs="0" ref="app-id"/>
+      </xs:sequence>
+      <xs:attribute name="locale" use="required" type="xs:string"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="content-type">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:enumeration value="linkedin-html"/>
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+  <xs:element name="app-id" type="xs:NMTOKEN"/>
+  <xs:element name="error">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="status" type="xs:integer"/>
+        <xs:element ref="timestamp"/>
+        <xs:element ref="error-code"/>
+        <xs:element ref="message"/>
+        <xs:element ref="request-id"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="error-code" type="xs:string"/>
+  <xs:element name="message" type="xs:string"/>
+  <xs:element name="request-id" type="xs:string"/>
+  <xs:element name="mailbox-item">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="recipients"/>
+        <xs:element ref="subject"/>
+        <xs:element ref="body"/>
+        <xs:element minOccurs="0" ref="item-content"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="recipients">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="recipient"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="recipient">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="person"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="subject" type="xs:string"/>
+  <xs:element name="item-content">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="invitation-request"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="invitation-request">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="connect-type"/>
+        <xs:element ref="authorization"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="connect-type">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:enumeration value="friend"/>
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+  <xs:element name="authorization">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="name"/>
+        <xs:element ref="value"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="network">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="network-stats"/>
+        <xs:element ref="updates"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="network-stats">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="property"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="property">
+    <xs:complexType>
+      <xs:simpleContent>
+        <xs:extension base="xs:integer">
+          <xs:attribute name="key" use="required" type="xs:string"/>
+        </xs:extension>
+      </xs:simpleContent>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="updates">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="update"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+      <xs:attribute name="count" type="xs:integer"/>
+      <xs:attribute name="start" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="update">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="timestamp"/>
+        <xs:element ref="update-key"/>
+        <xs:element ref="update-type"/>
+        <xs:element ref="update-content"/>
+        <xs:element ref="is-commentable"/>
+        <xs:element ref="is-likable"/>
+        <xs:element ref="is-liked"/>
+        <xs:element ref="num-likes"/>
+        <xs:element minOccurs="0" ref="update-comments"/>
+        <xs:element minOccurs="0" ref="likes"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="update-key" type="xs:string"/>
+  <xs:element name="update-type">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:enumeration value="ANSW"/>
+        <xs:enumeration value="APPM"/>
+        <xs:enumeration value="APPS"/>
+        <xs:enumeration value="CMPY"/>
+        <xs:enumeration value="CONN"/>
+        <xs:enumeration value="NCON"/>
+        <xs:enumeration value="CCEM"/>
+        <xs:enumeration value="JOBP"/>
+        <xs:enumeration value="JGRP"/>
+        <xs:enumeration value="MSFC"/>
+        <xs:enumeration value="PFOL"/>
+        <xs:enumeration value="PICU"/>
+        <xs:enumeration value="PREC"/>
+        <xs:enumeration value="PRFU"/>
+        <xs:enumeration value="PROF"/>
+        <xs:enumeration value="QSTN"/>
+        <xs:enumeration value="STAT"/>
+        <xs:enumeration value="SVPR"/>
+        <xs:enumeration value="PRFX"/>
+        <xs:enumeration value="SHAR"/>
+        <xs:enumeration value="VIRL"/>
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+  <xs:element name="group">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="name"/>
+        <xs:element ref="short-description"/>
+        <xs:element ref="description"/>
+        <xs:element ref="relation-to-viewer"/>
+        <xs:element ref="counts-by-category"/>
+        <xs:element ref="is-open-to-non-members"/>
+        <xs:element name="category" type="GroupCategory"/>
+        <xs:element ref="site-group-url"/>
+        <xs:element ref="contact-email"/>
+        <xs:element ref="locale"/>
+        <xs:element ref="allow-member-invites"/>
+        <xs:element ref="small-logo-url"/>
+        <xs:element ref="large-logo-url"/>
+        <xs:element ref="posts"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="short-description" type="xs:string"/>
+  <xs:element name="counts-by-category">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="count-for-category"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="count-for-category">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="category"/>
+        <xs:element ref="count"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="is-open-to-non-members" type="xs:boolean"/>
+  <xs:element name="site-group-url" type="xs:anyURI"/>
+  <xs:element name="locale" type="xs:NCName"/>
+  <xs:element name="allow-member-invites" type="xs:boolean"/>
+  <xs:element name="small-logo-url" type="xs:anyURI"/>
+  <xs:element name="large-logo-url" type="xs:anyURI"/>
+  <xs:element name="membership-state">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="code">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:enumeration value="blocked"/>
+              <xs:enumeration value="non-member"/>
+              <xs:enumeration value="awaiting-confirmation"/>
+              <xs:enumeration value="awaiting-parent-group-confirmation"/>
+              <xs:enumeration value="member"/>
+              <xs:enumeration value="moderator"/>
+              <xs:enumeration value="manager"/>
+              <xs:enumeration value="owner"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:element>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="contact-email" type="xs:string"/>
+  <xs:element name="update-content">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element minOccurs="0" ref="person"/>
+        <xs:element minOccurs="0" ref="update-action"/>
+        <xs:element minOccurs="0" ref="job"/>
+        <xs:element minOccurs="0" ref="question"/>
+        <xs:element minOccurs="0" ref="company"/>
+        <xs:element minOccurs="0" ref="company-job-update"/>
+        <xs:element minOccurs="0" ref="company-status-update"/>
+        <xs:element minOccurs="0" ref="company-person-update"/>
+        <xs:element minOccurs="0" ref="company-profile-update"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="update-action">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="action"/>
+        <xs:element ref="original-update"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="original-update">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="timestamp"/>
+        <xs:element ref="update-key"/>
+        <xs:element ref="update-type"/>
+        <xs:element ref="update-content"/>
+        <xs:element ref="updated-fields"/>
+        <xs:element ref="is-commentable"/>
+        <xs:element minOccurs="0" ref="update-comments"/>
+        <xs:element ref="is-likable"/>
+        <xs:element ref="is-liked"/>
+        <xs:element ref="num-likes"/>
+        <xs:element minOccurs="0" ref="likes"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="updated-fields">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="update-field">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="name" type="xs:string"/>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+      </xs:sequence>
+      <xs:attribute name="count" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="posts">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="post"/>
+      </xs:sequence>
+      <xs:attribute name="count" use="required" type="xs:integer"/>
+      <xs:attribute name="start" use="required" type="xs:integer"/>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="post">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element name="type">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="code">
+                <xs:simpleType>
+                  <xs:restriction base="xs:string">
+                    <xs:enumeration value="standard"/>
+                    <xs:enumeration value="news"/>
+                  </xs:restriction>
+                </xs:simpleType>
+              </xs:element>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+        <xs:element minOccurs="0" ref="category"/>
+        <xs:element ref="creation-timestamp"/>
+        <xs:element ref="creator"/>
+        <xs:element ref="summary"/>
+        <xs:element ref="title"/>
+        <xs:element ref="likes"/>
+        <xs:element ref="relation-to-viewer"/>
+        <xs:element ref="attachment"/>
+        <xs:element ref="comments"/>
+        <xs:element minOccurs="0" ref="site-group-post-url"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:complexType name="GroupCategory">
+    <xs:sequence>
+      <xs:element name="code">
+        <xs:simpleType>
+          <xs:restriction base="xs:string">
+            <xs:enumeration value="alumni"/>
+            <xs:enumeration value="corporate"/>
+            <xs:enumeration value="conference"/>
+            <xs:enumeration value="network"/>
+            <xs:enumeration value="philanthropic"/>
+            <xs:enumeration value="professional"/>
+            <xs:enumeration value="other"/>
+          </xs:restriction>
+        </xs:simpleType>
+      </xs:element>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:element name="category">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="code">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:enumeration value="discussion"/>
+              <xs:enumeration value="job"/>
+              <xs:enumeration value="promotion"/>
+              <xs:enumeration value="linkedin-job"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:element>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="creator">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element minOccurs="0" ref="id"/>
+        <xs:element ref="first-name"/>
+        <xs:element ref="last-name"/>
+        <xs:element ref="headline"/>
+        <xs:element ref="picture-url"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="attachment">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="summary"/>
+        <xs:element ref="title"/>
+        <xs:element ref="content-domain"/>
+        <xs:element ref="content-url"/>
+        <xs:element ref="image-url"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="content-domain" type="xs:NCName"/>
+  <xs:element name="content-url" type="xs:anyURI"/>
+  <xs:element name="image-url" type="xs:anyURI"/>
+  <xs:element name="comments">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element minOccurs="0" maxOccurs="unbounded" ref="comment"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="comment">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="creation-timestamp"/>
+        <xs:element ref="creator"/>
+        <xs:element ref="id"/>
+        <xs:element ref="relation-to-viewer"/>
+        <xs:element ref="text"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="site-group-post-url" type="xs:anyURI"/>
+  <xs:element name="job">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="partner-job-id"/>
+        <xs:element ref="contract-id"/>
+        <xs:element minOccurs="0" ref="customer-job-code"/>
+        <xs:element minOccurs="0" ref="active"/>
+        <xs:sequence minOccurs="0">
+          <xs:element ref="posting-date"/>
+          <xs:element ref="expiration-date"/>
+        </xs:sequence>
+        <xs:sequence>
+          <xs:element ref="company"/>
+          <xs:element ref="description"/>
+          <xs:element ref="description-snippet"/>
+          <xs:element ref="position"/>
+          <xs:element ref="skills-and-experience"/>
+          <xs:element ref="expiration-timestamp"/>
+          <xs:element ref="job-poster"/>
+          <xs:element ref="location-description"/>
+          <xs:element ref="posting-timestamp"/>
+          <xs:element ref="salary"/>
+          <xs:element ref="site-job-request"/>
+          <xs:element ref="site-job-url"/>
+        </xs:sequence>
+        <xs:sequence minOccurs="0">
+          <xs:element ref="referral-bonus"/>
+          <xs:element ref="poster"/>
+          <xs:element ref="how-to-apply"/>
+          <xs:element ref="tracking-pixel-url"/>
+          <xs:element ref="renewal"/>
+        </xs:sequence>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="partner-job-id" type="xs:string"/>
+  <xs:element name="contract-id" type="xs:integer"/>
+  <xs:element name="customer-job-code" type="xs:string"/>
+  <xs:element name="active" type="xs:boolean"/>
+  <xs:element name="posting-date">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="year"/>
+        <xs:element ref="month"/>
+        <xs:element ref="day"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="expiration-date">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="year"/>
+        <xs:element ref="month"/>
+        <xs:element ref="day"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="expiration-timestamp" type="xs:integer"/>
+  <xs:element name="description-snippet" type="xs:string"/>
+  <xs:element name="job-poster">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="first-name"/>
+        <xs:element ref="last-name"/>
+        <xs:element ref="headline"/>
+        <xs:element minOccurs="0" ref="relation-to-viewer"/>
+        <xs:sequence minOccurs="0">
+          <xs:element ref="api-standard-profile-request"/>
+          <xs:element ref="site-standard-profile-request"/>
+        </xs:sequence>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="location-description" type="xs:string"/>
+  <xs:element name="posting-timestamp" type="xs:integer"/>
+  <xs:element name="salary" type="xs:string"/>
+  <xs:element name="site-job-url" type="xs:anyURI"/>
+  <xs:element name="referral-bonus" type="xs:string"/>
+  <xs:element name="poster">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="display"/>
+        <xs:element ref="role"/>
+        <xs:element ref="email-address"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="display" type="xs:boolean"/>
+  <xs:element name="role">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="code">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:enumeration value="H"/>
+              <xs:enumeration value="R"/>
+              <xs:enumeration value="S"/>
+              <xs:enumeration value="W"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:element>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="email-address" type="xs:string"/>
+  <xs:element name="how-to-apply">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="application-url"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="application-url" type="xs:anyURI"/>
+  <xs:element name="tracking-pixel-url" type="xs:anyURI"/>
+  <xs:element name="renewal">
+    <xs:complexType/>
+  </xs:element>
+  <xs:element name="companies">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="company"/>
+      </xs:sequence>
+      <xs:attribute name="count" type="xs:integer"/>
+      <xs:attribute name="start" type="xs:integer"/>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="question">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="title"/>
+        <xs:element ref="author"/>
+        <xs:element ref="question-categories"/>
+        <xs:element ref="web-url"/>
+        <xs:element ref="answers"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="question-categories">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="question-category"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="question-category">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="code"/>
+        <xs:element ref="name"/>
+      </xs:sequence>
+      <xs:attribute name="key" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="answers">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="answer"/>
+      </xs:sequence>
+      <xs:attribute name="count" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="answer">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="web-url"/>
+        <xs:element ref="author"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="company-job-update">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="job"/>
+        <xs:element ref="action"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="company-status-update">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="share"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="company-person-update">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="person"/>
+        <xs:element ref="action"/>
+        <xs:element ref="old-position"/>
+        <xs:element ref="new-position"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="old-position">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="title"/>
+        <xs:element ref="company"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="new-position">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="title"/>
+        <xs:element ref="company"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="company-profile-update">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="editor"/>
+        <xs:element ref="action"/>
+        <xs:element ref="profile-field"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="editor">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="first-name"/>
+        <xs:element ref="last-name"/>
+        <xs:element ref="headline"/>
+        <xs:element ref="api-standard-profile-request"/>
+        <xs:element ref="site-standard-profile-request"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="profile-field">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="code">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:enumeration value="description"/>
+              <xs:enumeration value="speciality"/>
+              <xs:enumeration value="logo"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:element>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="is-commentable" type="xs:boolean"/>
+  <xs:element name="update-comments">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="update-comment"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="is-likable" type="xs:boolean"/>
+  <xs:element name="num-likes" type="xs:integer"/>
+  <xs:element name="likes">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="like"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="like">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element minOccurs="0" ref="timestamp"/>
+        <xs:element ref="person"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="people">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="person"/>
+      </xs:sequence>
+      <xs:attribute name="count" use="required" type="xs:integer"/>
+      <xs:attribute name="start" use="required" type="xs:integer"/>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="person">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element minOccurs="0" ref="id"/>
+        <xs:sequence minOccurs="0">
+          <xs:element ref="first-name"/>
+          <xs:element ref="last-name"/>
+          <xs:element ref="headline"/>
+        </xs:sequence>
+        <xs:sequence minOccurs="0">
+          <xs:element ref="location"/>
+          <xs:element name="industry" type="xs:string"/>
+        </xs:sequence>
+        <xs:sequence minOccurs="0">
+          <xs:element ref="connections"/>
+          <xs:element ref="current-status"/>
+          <xs:element ref="current-share"/>
+          <xs:element ref="distance"/>
+          <xs:element ref="current-status-timestamp"/>
+          <xs:element ref="num-recommenders"/>
+          <xs:element ref="num-connections"/>
+          <xs:element ref="num-connections-capped"/>
+          <xs:element ref="relation-to-viewer"/>
+          <xs:element ref="summary"/>
+          <xs:element ref="public-profile-url"/>
+          <xs:element ref="interests"/>
+          <xs:element ref="associations"/>
+          <xs:element ref="honors"/>
+          <xs:element name="specialties" type="xs:string"/>
+          <xs:element ref="certifications"/>
+          <xs:element ref="patents"/>
+          <xs:element ref="publications"/>
+          <xs:element ref="skills"/>
+          <xs:element ref="languages"/>
+        </xs:sequence>
+        <xs:element minOccurs="0" ref="positions"/>
+        <xs:element minOccurs="0" ref="three-current-positions"/>
+        <xs:element minOccurs="0" ref="three-past-positions"/>
+        <xs:sequence minOccurs="0">
+          <xs:element ref="educations"/>
+          <xs:element ref="member-url-resources"/>
+        </xs:sequence>
+        <xs:sequence minOccurs="0">
+          <xs:element ref="api-standard-profile-request"/>
+          <xs:element ref="site-standard-profile-request"/>
+        </xs:sequence>
+        <xs:element minOccurs="0" ref="picture-url"/>
+        <xs:element minOccurs="0" ref="recommendations-given"/>
+        <xs:element minOccurs="0" ref="recommendations-received"/>
+        <xs:element minOccurs="0" ref="member-groups"/>
+        <xs:element minOccurs="0" ref="person-activities"/>
+        <xs:element minOccurs="0" ref="im-accounts"/>
+        <xs:element minOccurs="0" ref="twitter-accounts"/>
+        <xs:element minOccurs="0" ref="date-of-birth"/>
+        <xs:element minOccurs="0" ref="main-address"/>
+        <xs:element minOccurs="0" ref="phone-numbers"/>
+        <xs:element minOccurs="0" ref="following"/>
+      </xs:sequence>
+      <xs:attribute name="path"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="first-name" type="xs:string"/>
+  <xs:element name="last-name" type="xs:string"/>
+  <xs:element name="headline" type="xs:string"/>
+  <xs:element name="certifications">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="certification"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="certification">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="name"/>
+        <xs:element ref="authority"/>
+        <xs:element ref="number"/>
+        <xs:element ref="start-date"/>
+        <xs:element ref="end-date"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="authority">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="languages">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="language"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="patents">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="patent"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="patent">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="title"/>
+        <xs:element ref="date"/>
+        <xs:element ref="url"/>
+        <xs:element ref="summary"/>
+        <xs:element ref="number"/>
+        <xs:element ref="status"/>
+        <xs:element ref="office"/>
+        <xs:element ref="inventors"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="number" type="xs:string"/>
+  <xs:element name="office">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="inventors">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="inventor"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="inventor">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="name"/>
+        <xs:element ref="person"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="publications">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="publication"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="publication">
+    <xs:complexType>
+      <xs:sequence minOccurs="0">
+        <xs:element ref="date"/>
+        <xs:element ref="id"/>
+        <xs:element ref="summary"/>
+        <xs:element ref="title"/>
+        <xs:element ref="url"/>
+        <xs:element ref="authors"/>
+        <xs:element ref="publisher"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="authors">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" name="author" type="publication-author"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:complexType name="publication-author">
+    <xs:sequence>
+      <xs:element ref="id"/>
+      <xs:element ref="name"/>
+      <xs:element ref="person"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:element name="publisher">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="skills">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="skill"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="status">
+    <xs:complexType>
+      <xs:sequence minOccurs="0">
+        <xs:element ref="id"/>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="date">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="year"/>
+        <xs:element ref="month"/>
+        <xs:element ref="day"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="language">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="proficiency"/>
+        <xs:element ref="id"/>
+        <xs:element name="language" type="name-type"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:complexType name="name-type">
+    <xs:sequence>
+      <xs:element ref="name"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:element name="skill">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="proficiency"/>
+        <xs:element ref="years"/>
+        <xs:element ref="id"/>
+        <xs:element name="skill" type="name-type"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="years">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="proficiency">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="level"/>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="level">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:enumeration value="elementary"/>
+        <xs:enumeration value="limited_working"/>
+        <xs:enumeration value="professional_working"/>
+        <xs:enumeration value="full_professional"/>
+        <xs:enumeration value="native_or_bilingual"/>
+        <xs:enumeration value="beginner"/>
+        <xs:enumeration value="intermediate"/>
+        <xs:enumeration value="advanced"/>
+        <xs:enumeration value="expert"/>
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+  <xs:element name="current-share">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="timestamp"/>
+        <xs:element ref="comment"/>
+        <xs:element ref="content"/>
+        <xs:element ref="visibility"/>
+        <xs:element ref="source"/>
+        <xs:element ref="author"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="source">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="service-provider"/>
+        <xs:element ref="application"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="service-provider">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="application">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="location">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="description"/>
+        <xs:element ref="is-headquarters"/>
+        <xs:element ref="is-active"/>
+        <xs:element ref="address"/>
+        <xs:element ref="contact-info"/>
+        <xs:element ref="name"/>
+        <xs:element ref="postal-code"/>
+        <xs:element ref="country"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="is-headquarters" type="xs:boolean"/>
+  <xs:element name="is-active" type="xs:boolean"/>
+  <xs:element name="address">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="street1"/>
+        <xs:element minOccurs="0" ref="street2"/>
+        <xs:element ref="city"/>
+        <xs:element minOccurs="0" ref="state"/>
+        <xs:element ref="postal-code"/>
+        <xs:sequence minOccurs="0">
+          <xs:element ref="country-code"/>
+          <xs:element ref="region-code"/>
+        </xs:sequence>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="street1" type="xs:string"/>
+  <xs:element name="street2" type="xs:string"/>
+  <xs:element name="city" type="xs:string"/>
+  <xs:element name="state" type="xs:string"/>
+  <xs:element name="country-code" type="xs:string"/>
+  <xs:element name="region-code" type="xs:string"/>
+  <xs:element name="postal-code" type="xs:string"/>
+  <xs:element name="contact-info">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element minOccurs="0" ref="phone1"/>
+        <xs:element minOccurs="0" ref="phone2"/>
+        <xs:element minOccurs="0" ref="fax"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="phone1" type="xs:string"/>
+  <xs:element name="phone2" type="xs:string"/>
+  <xs:element name="fax" type="xs:string"/>
+  <xs:element name="country">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="code"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="code" type="xs:string"/>
+  <xs:element name="current-status-timestamp" type="xs:integer"/>
+  <xs:element name="num-recommenders" type="xs:integer"/>
+  <xs:element name="num-connections" type="xs:integer"/>
+  <xs:element name="num-connections-capped" type="xs:boolean"/>
+  <xs:element name="public-profile-url" type="xs:anyURI"/>
+  <xs:element name="relation-to-viewer">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="related-connections"/>
+        <xs:element ref="distance"/>
+        <xs:element minOccurs="0" ref="membership-state"/>
+        <xs:element ref="is-following"/>
+        <xs:element ref="is-liked"/>
+        <xs:element minOccurs="0" ref="available-actions"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="is-following">
+    <xs:complexType>
+      <xs:simpleContent>
+        <xs:extension base="xs:boolean"/>
+      </xs:simpleContent>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="following">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="people"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="available-actions">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="action"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="interests" type="xs:string"/>
+  <xs:element name="associations" type="xs:string"/>
+  <xs:element name="honors" type="xs:string"/>
+  <xs:element name="specialties">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element minOccurs="0" maxOccurs="unbounded" ref="specialty"/>
+      </xs:sequence>
+      <xs:attribute name="total" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="specialty" type="xs:string"/>
+  <xs:element name="positions">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="position"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="three-current-positions">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="position"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="three-past-positions">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="position"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="position">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element minOccurs="0" ref="id"/>
+        <xs:element minOccurs="0" ref="title"/>
+        <xs:element minOccurs="0" ref="summary"/>
+        <xs:element minOccurs="0" ref="start-date"/>
+        <xs:element minOccurs="0" ref="end-date"/>
+        <xs:element ref="is-current"/>
+        <xs:element ref="company"/>
+        <xs:element ref="description"/>
+        <xs:element ref="description-snippet"/>
+        <xs:element ref="skills-and-experience"/>
+        <xs:element minOccurs="0" ref="location"/>
+        <xs:element ref="job-functions"/>
+        <xs:element ref="industries"/>
+        <xs:element ref="job-type"/>
+        <xs:element ref="experience-level"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="title" type="xs:string"/>
+  <xs:element name="is-current" type="xs:boolean"/>
+  <xs:element name="skills-and-experience" type="xs:string"/>
+  <xs:element name="job-functions">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="job-function"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="job-function">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="code">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:enumeration value="acct"/>
+              <xs:enumeration value="adm"/>
+              <xs:enumeration value="advr"/>
+              <xs:enumeration value="anls"/>
+              <xs:enumeration value="art"/>
+              <xs:enumeration value="bd"/>
+              <xs:enumeration value="cnsl"/>
+              <xs:enumeration value="cust"/>
+              <xs:enumeration value="dist"/>
+              <xs:enumeration value="dsgn"/>
+              <xs:enumeration value="edu"/>
+              <xs:enumeration value="eng"/>
+              <xs:enumeration value="fin"/>
+              <xs:enumeration value="genb"/>
+              <xs:enumeration value="hr"/>
+              <xs:enumeration value="it"/>
+              <xs:enumeration value="lgl"/>
+              <xs:enumeration value="mgmt"/>
+              <xs:enumeration value="mnfc"/>
+              <xs:enumeration value="mrkt"/>
+              <xs:enumeration value="othr"/>
+              <xs:enumeration value="pr"/>
+              <xs:enumeration value="prch"/>
+              <xs:enumeration value="prdm"/>
+              <xs:enumeration value="prjm"/>
+              <xs:enumeration value="prod"/>
+              <xs:enumeration value="qa"/>
+              <xs:enumeration value="rsch"/>
+              <xs:enumeration value="sale"/>
+              <xs:enumeration value="sci"/>
+              <xs:enumeration value="stra"/>
+              <xs:enumeration value="supl"/>
+              <xs:enumeration value="trng"/>
+              <xs:enumeration value="wrt"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:element>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="industries">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="industry"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="job-type">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="code">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:enumeration value="F"/>
+              <xs:enumeration value="P"/>
+              <xs:enumeration value="C"/>
+              <xs:enumeration value="T"/>
+              <xs:enumeration value="O"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:element>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="experience-level">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="code">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:enumeration value="0"/>
+              <xs:enumeration value="1"/>
+              <xs:enumeration value="2"/>
+              <xs:enumeration value="3"/>
+              <xs:enumeration value="4"/>
+              <xs:enumeration value="5"/>
+              <xs:enumeration value="6"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:element>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="company">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element minOccurs="0" ref="id"/>
+        <xs:element minOccurs="0" ref="universal-name"/>
+        <xs:element ref="description"/>
+        <xs:element name="industry" type="xs:string"/>
+        <xs:element ref="logo-url"/>
+        <xs:element ref="name"/>
+        <xs:element ref="type"/>
+        <xs:element ref="company-type"/>
+        <xs:element ref="size"/>
+        <xs:element ref="stock-exchange"/>
+        <xs:element ref="ticker"/>
+        <xs:element ref="specialties"/>
+        <xs:element ref="blog-rss-url"/>
+        <xs:element ref="twitter-id"/>
+        <xs:element ref="square-logo-url"/>
+        <xs:element ref="locations"/>
+        <xs:element ref="founded-year"/>
+        <xs:element ref="end-year"/>
+        <xs:element ref="num-followers"/>
+        <xs:element ref="email-domains"/>
+        <xs:element ref="website-url"/>
+        <xs:element name="status" type="company-status"/>
+        <xs:element ref="employee-count-range"/>
+      </xs:sequence>
+      <xs:attribute name="key"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:complexType name="company-status">
+    <xs:sequence>
+      <xs:element name="code">
+        <xs:simpleType>
+          <xs:restriction base="xs:string">
+            <xs:enumeration value="OPR"/>
+            <xs:enumeration value="OPS"/>
+            <xs:enumeration value="RRG"/>
+            <xs:enumeration value="OOB"/>
+            <xs:enumeration value="ACQ"/>
+          </xs:restriction>
+        </xs:simpleType>
+      </xs:element>
+      <xs:element ref="name"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:element name="universal-name" type="xs:string"/>
+  <xs:element name="logo-url" type="xs:anyURI"/>
+  <xs:element name="website-url" type="xs:anyURI"/>
+  <xs:element name="company-search">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="companies"/>
+        <xs:element ref="num-results"/>
+        <xs:element ref="facets"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="type" type="xs:string"/>
+  <xs:complexType name="product-type">
+    <xs:sequence>
+      <xs:element ref="code"/>
+      <xs:element ref="name"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:element name="company-type">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="code">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:enumeration value="C"/>
+              <xs:enumeration value="D"/>
+              <xs:enumeration value="E"/>
+              <xs:enumeration value="G"/>
+              <xs:enumeration value="N"/>
+              <xs:enumeration value="O"/>
+              <xs:enumeration value="P"/>
+              <xs:enumeration value="S"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:element>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="size" type="xs:NMTOKEN"/>
+  <xs:element name="stock-exchange">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="code">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:enumeration value="ASE"/>
+              <xs:enumeration value="NYS"/>
+              <xs:enumeration value="NMS"/>
+              <xs:enumeration value="LSE"/>
+              <xs:enumeration value="FRA"/>
+              <xs:enumeration value="GER"/>
+              <xs:enumeration value="PAR"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:element>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="ticker" type="xs:string"/>
+  <xs:element name="blog-rss-url" type="xs:anyURI"/>
+  <xs:element name="twitter-id" type="xs:string"/>
+  <xs:element name="square-logo-url" type="xs:anyURI"/>
+  <xs:element name="group-memberships">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="group-membership"/>
+      </xs:sequence>
+      <xs:attribute name="count" use="required" type="xs:integer"/>
+      <xs:attribute name="start" use="required" type="xs:integer"/>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="group-membership">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="group"/>
+        <xs:element ref="person"/>
+        <xs:element ref="membership-state"/>
+        <xs:element ref="contact-email"/>
+        <xs:element ref="show-group-logo-in-profile"/>
+        <xs:element ref="allow-messages-from-members"/>
+        <xs:element ref="email-digest-frequency"/>
+        <xs:element ref="email-announcements-from-managers"/>
+        <xs:element ref="email-for-every-new-post"/>
+      </xs:sequence>
+      <xs:attribute name="key" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="show-group-logo-in-profile" type="xs:boolean"/>
+  <xs:element name="allow-messages-from-members" type="xs:boolean"/>
+  <xs:element name="email-digest-frequency">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="code">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:enumeration value="none"/>
+              <xs:enumeration value="daily"/>
+              <xs:enumeration value="weekly"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:element>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="email-announcements-from-managers" type="xs:boolean"/>
+  <xs:element name="email-for-every-new-post" type="xs:boolean"/>
+  <xs:element name="groups">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="group"/>
+      </xs:sequence>
+      <xs:attribute name="count" use="required" type="xs:integer"/>
+      <xs:attribute name="start" use="required" type="xs:integer"/>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="job-bookmarks">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="job-bookmark"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="job-bookmark">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="is-applied"/>
+        <xs:element ref="is-saved"/>
+        <xs:element ref="saved-timestamp"/>
+        <xs:element minOccurs="0" ref="applied-timestamp"/>
+        <xs:element ref="job"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="is-applied" type="xs:boolean"/>
+  <xs:element name="is-saved" type="xs:boolean"/>
+  <xs:element name="saved-timestamp" type="xs:integer"/>
+  <xs:element name="applied-timestamp" type="xs:integer"/>
+  <xs:element name="job-suggestions">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="jobs"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="job-search">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="jobs"/>
+        <xs:element ref="facets"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="jobs">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="job"/>
+      </xs:sequence>
+      <xs:attribute name="count" use="required" type="xs:integer"/>
+      <xs:attribute name="start" use="required" type="xs:integer"/>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="products">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="product"/>
+      </xs:sequence>
+      <xs:attribute name="count" use="required" type="xs:integer"/>
+      <xs:attribute name="start" use="required" type="xs:integer"/>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="product">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="name"/>
+        <xs:element name="type" type="product-type"/>
+        <xs:element ref="description"/>
+        <xs:element ref="logo-url"/>
+        <xs:element ref="creation-timestamp"/>
+        <xs:element ref="features"/>
+        <xs:element ref="num-recommendations"/>
+        <xs:element ref="product-deal"/>
+        <xs:element ref="sales-persons"/>
+        <xs:element ref="video"/>
+        <xs:element minOccurs="0" ref="recommendations"/>
+        <xs:element ref="product-category"/>
+        <xs:element ref="website-url"/>
+        <xs:element minOccurs="0" ref="disclaimer"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="creation-timestamp" type="xs:integer"/>
+  <xs:element name="features">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="feature"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="feature" type="xs:string"/>
+  <xs:element name="num-recommendations" type="xs:integer"/>
+  <xs:element name="text" type="xs:string"/>
+  <xs:element name="product-deal">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="title"/>
+        <xs:element ref="url"/>
+        <xs:element ref="text"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="sales-persons">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="person" maxOccurs="unbounded"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="video">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="title"/>
+        <xs:element ref="url"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="recommendations">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="recommendation"/>
+      </xs:sequence>
+      <xs:attribute name="count" use="required" type="xs:integer"/>
+      <xs:attribute name="start" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="product-category">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="code"/>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="disclaimer" type="xs:string"/>
+  <xs:element name="locations">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="location"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="founded-year" type="xs:integer"/>
+  <xs:element name="end-year" type="xs:integer"/>
+  <xs:element name="num-followers">
+      <xs:complexType>
+        <xs:simpleContent>
+            <xs:extension base="xs:integer"/>
+        </xs:simpleContent>
+      </xs:complexType>
+  </xs:element>
+  <xs:element name="email-domains">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="email-domain" maxOccurs="unbounded"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="email-domain" type="xs:string"/>
+  <xs:element name="employee-count-range">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="code"/>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="action">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="code"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="educations">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="education"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="education">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="school-name"/>
+        <xs:element ref="degree"/>
+        <xs:element ref="notes"/>
+        <xs:element ref="activities"/>
+        <xs:element ref="field-of-study"/>
+        <xs:element ref="start-date"/>
+        <xs:element ref="end-date"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="school-name" type="xs:string"/>
+  <xs:element name="degree" type="xs:string"/>
+  <xs:element name="notes" type="xs:string"/>
+  <xs:element name="activities" type="xs:string"/>
+  <xs:element name="field-of-study" type="xs:string"/>
+  <xs:element name="member-url-resources">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="member-url"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="member-url">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="url"/>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="member-groups">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="member-group"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="member-group">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="name"/>
+        <xs:element ref="site-group-request"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="site-group-request">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="url"/>
+        <xs:element minOccurs="0" ref="headers"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="site-job-request">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="url"/>
+        <xs:element minOccurs="0" ref="headers"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="person-activities">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="activity"/>
+      </xs:sequence>
+      <xs:attribute name="count" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="api-standard-profile-request">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="url"/>
+        <xs:element ref="headers"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="site-standard-profile-request">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="url"/>
+        <xs:element minOccurs="0" ref="headers"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="picture-url" type="xs:anyURI"/>
+  <xs:element name="recommendations-given">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="recommendation"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="recommendations-received">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="recommendation"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="recommendation">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="recommendation-type"/>
+        <xs:element minOccurs="0" ref="recommendation-text"/>
+        <xs:element minOccurs="0" ref="recommendation-snippet"/>
+        <xs:element ref="recommender"/>
+        <xs:element ref="recommendee"/>
+        <xs:element minOccurs="0" ref="web-url"/>
+        <xs:element ref="product-id"/>
+        <xs:element ref="timestamp"/>
+        <xs:element minOccurs="0" ref="text"/>
+        <xs:element ref="reply"/>
+        <xs:element ref="likes"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="product-id" type="xs:integer"/>
+  <xs:element name="reply" type="xs:string"/>
+  <xs:element name="recommendation-type">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="code">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:enumeration value="business-partner"/>
+              <xs:enumeration value="colleague"/>
+              <xs:enumeration value="education"/>
+              <xs:enumeration value="service-provider"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:element>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="recommendation-snippet" type="xs:string"/>
+  <xs:element name="recommendation-text" type="xs:string"/>
+  <xs:element name="recommendee">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="first-name"/>
+        <xs:element ref="last-name"/>
+        <xs:element ref="headline"/>
+        <xs:element ref="picture-url"/>
+        <xs:element ref="api-standard-profile-request"/>
+        <xs:element ref="site-standard-profile-request"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="recommender">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="first-name"/>
+        <xs:element ref="last-name"/>
+        <xs:element ref="headline"/>
+        <xs:element ref="picture-url"/>
+        <xs:element ref="api-standard-profile-request"/>
+        <xs:element ref="site-standard-profile-request"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="web-url" type="xs:anyURI"/>
+  <xs:element name="body" type="xs:string"/>
+  <xs:element name="name" type="xs:string"/>
+  <xs:element name="value" type="xs:NMTOKEN"/>
+  <xs:element name="timestamp" type="xs:integer"/>
+  <xs:element name="current-status" type="xs:string"/>
+  <xs:element name="update-comment">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:sequence minOccurs="0">
+          <xs:element ref="id"/>
+          <xs:element ref="sequence-number"/>
+        </xs:sequence>
+        <xs:element name="comment" type="xs:string"/>
+        <xs:sequence minOccurs="0">
+          <xs:element ref="person"/>
+          <xs:element ref="timestamp"/>
+        </xs:sequence>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="sequence-number" type="xs:integer"/>
+  <xs:element name="connections">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element minOccurs="0" maxOccurs="unbounded" ref="person"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+      <xs:attribute name="count" type="xs:integer"/>
+      <xs:attribute name="start" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="related-connections">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="person"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="id" type="xs:NMTOKEN"/>
+  <xs:element name="industry">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="code"/>
+        <xs:element ref="name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="distance">
+    <xs:complexType>
+      <xs:simpleContent>
+        <xs:extension base="xs:integer"/>
+      </xs:simpleContent>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="summary" type="xs:string"/>
+  <xs:element name="start-date">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="year"/>
+        <xs:element minOccurs="0" ref="month"/>
+        <xs:element minOccurs="0" ref="day"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="end-date">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="year"/>
+        <xs:element minOccurs="0" ref="month"/>
+        <xs:element minOccurs="0" ref="day"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="url" type="xs:anyURI"/>
+  <xs:element name="headers">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="http-header"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="http-header">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="name"/>
+        <xs:element ref="value"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="author">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="first-name"/>
+        <xs:element ref="last-name"/>
+        <xs:element ref="headline"/>
+        <xs:element minOccurs="0" ref="relation-to-viewer"/>
+        <xs:element ref="api-standard-profile-request"/>
+        <xs:element ref="site-standard-profile-request"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="im-accounts">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element minOccurs="0" maxOccurs="unbounded" ref="im-account"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="im-account">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="im-account-type"/>
+        <xs:element ref="im-account-name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="im-account-type">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:enumeration value="aim"/>
+        <xs:enumeration value="gtalk"/>
+        <xs:enumeration value="icq"/>
+        <xs:enumeration value="msn"/>
+        <xs:enumeration value="skype"/>
+        <xs:enumeration value="yahoo"/>
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+  <xs:element name="im-account-name" type="xs:string"/>
+  <xs:element name="twitter-accounts">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element minOccurs="0" maxOccurs="unbounded" ref="twitter-account"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="twitter-account">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="provider-account-id"/>
+        <xs:element ref="provider-account-name"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="provider-account-id" type="xs:integer"/>
+  <xs:element name="provider-account-name" type="xs:string"/>
+  <xs:element name="date-of-birth">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="year"/>
+        <xs:element ref="month"/>
+        <xs:element ref="day"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="day" type="xs:integer"/>
+  <xs:element name="main-address" type="xs:string"/>
+  <xs:element name="phone-numbers">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element minOccurs="0" maxOccurs="unbounded" ref="phone-number"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="phone-number">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="phone-number" type="xs:string"/>
+        <xs:element ref="phone-type"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="year" type="xs:integer"/>
+  <xs:element name="month" type="xs:integer"/>
+  <xs:element name="phone-type">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:enumeration value="home"/>
+        <xs:enumeration value="work"/>
+        <xs:enumeration value="mobile"/>
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+  <xs:element name="people-search">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="num-results"/>
+        <xs:element minOccurs="0" ref="people"/>
+        <xs:element minOccurs="0" ref="facets"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="num-results" type="xs:integer"/>
+  <xs:element name="facets">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="facet"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="facet">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="name"/>
+        <xs:element name="code">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:enumeration value="location"/>
+              <xs:enumeration value="industry"/>
+              <xs:enumeration value="network"/>
+              <xs:enumeration value="language"/>
+              <xs:enumeration value="current-company"/>
+              <xs:enumeration value="past-company"/>
+              <xs:enumeration value="school"/>
+              <xs:enumeration value="company-size"/>
+              <xs:enumeration value="num-followers-range"/>
+              <xs:enumeration value="fortune"/>
+              <xs:enumeration value="company"/>
+              <xs:enumeration value="date-posted"/>
+              <xs:enumeration value="job-function"/>
+              <xs:enumeration value="experience-level"/>
+              <xs:enumeration value="salary"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:element>
+        <xs:element minOccurs="0" ref="buckets"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="buckets">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="bucket"/>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="bucket">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="name"/>
+        <xs:element ref="code"/>
+        <xs:element ref="count"/>
+        <xs:element minOccurs="0" ref="selected"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="selected" type="xs:boolean"/>
+  <xs:element name="share">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="id"/>
+        <xs:element ref="timestamp"/>
+        <xs:element ref="comment"/>
+        <xs:element ref="content"/>
+        <xs:element ref="visibility"/>
+        <xs:element ref="source"/>
+        <xs:element ref="author"/>
+        <xs:element minOccurs="0" ref="attribution"/>
+        <xs:element ref="share-target-reach"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="content">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element minOccurs="0" ref="id"/>
+        <xs:element ref="title"/>
+        <xs:element ref="submitted-url"/>
+        <xs:element minOccurs="0" ref="shortened-url"/>
+        <xs:element ref="submitted-image-url"/>
+        <xs:element minOccurs="0" ref="description"/>
+        <xs:element minOccurs="0" ref="thumbnail-url"/>
+        <xs:element minOccurs="0" ref="resolved-url"/>
+        <xs:element minOccurs="0" ref="eyebrow-url"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="description" type="xs:string"/>
+  <xs:element name="submitted-url" type="xs:anyURI"/>
+  <xs:element name="shortened-url" type="xs:anyURI"/>
+  <xs:element name="submitted-image-url" type="xs:anyURI"/>
+  <xs:element name="thumbnail-url" type="xs:anyURI"/>
+  <xs:element name="resolved-url" type="xs:anyURI"/>
+  <xs:element name="eyebrow-url" type="xs:anyURI"/>
+  <xs:element name="visibility">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="code">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:enumeration value="anyone"/>
+              <xs:enumeration value="all-members"/>
+              <xs:enumeration value="connections-only"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:element>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="attribution">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="share"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="is-liked">
+    <xs:complexType>
+      <xs:simpleContent>
+        <xs:extension base="xs:boolean"/>
+      </xs:simpleContent>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="is-company-share-enabled">
+    <xs:complexType>
+      <xs:simpleContent>
+        <xs:extension base="xs:boolean"/>
+      </xs:simpleContent>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="count" type="xs:integer"/>
+  <xs:element name="historical-follow-statistics">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="statistic" minOccurs="0" maxOccurs="unbounded">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="time" type="xs:integer"/>
+              <xs:element name="total-follower-count" type="xs:integer"/>
+              <xs:element name="organic-follower-count" type="xs:integer"/>
+              <xs:element name="paid-follower-count" type="xs:integer"/>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="historical-status-update-statistics">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="statistic" minOccurs="0" maxOccurs="unbounded">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="time" type="xs:integer"/>
+              <xs:element name="like-count" type="xs:integer"/>
+              <xs:element name="impression-count" type="xs:integer"/>
+              <xs:element name="click-count" type="xs:integer"/>
+              <xs:element name="comment-count" type="xs:integer"/>
+              <xs:element name="share-count" type="xs:integer"/>
+              <xs:element name="engagement" type="xs:integer"/>
+              <xs:element name="unique-count" type="xs:integer"/>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+      </xs:sequence>
+      <xs:attribute name="total" use="required" type="xs:integer"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="company-statistics">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="status-update-statistics">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="views-by-month">
+                <xs:complexType>
+                  <xs:sequence>
+                    <xs:element name="view-by-month" maxOccurs="unbounded" minOccurs="0">
+                      <xs:complexType>
+                        <xs:sequence>
+                          <xs:element name="date">
+                            <xs:complexType>
+                              <xs:sequence>
+                                <xs:element type="xs:short" name="year"/>
+                                <xs:element type="xs:integer" name="month"/>
+                              </xs:sequence>
+                            </xs:complexType>
+                          </xs:element>
+                          <xs:element type="xs:integer" name="clicks"/>
+                          <xs:element type="xs:integer" name="likes"/>
+                          <xs:element type="xs:integer" name="comments"/>
+                          <xs:element type="xs:integer" name="shares"/>
+                          <xs:element type="xs:integer" name="impressions"/>
+                          <xs:element type="xs:float" name="engagement" minOccurs="0"/>
+                        </xs:sequence>
+                      </xs:complexType>
+                    </xs:element>
+                  </xs:sequence>
+                  <xs:attribute type="xs:integer" name="total"/>
+                </xs:complexType>
+              </xs:element>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+        <xs:element name="follow-statistics">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element type="xs:integer" name="count"/>
+              <xs:element type="xs:integer" name="employee-count"/>
+              <xs:element type="xs:integer" name="non-employee-count"/>
+              <xs:element name="seniorities">
+                <xs:complexType>
+                  <xs:sequence>
+                    <xs:element name="seniority" maxOccurs="unbounded" minOccurs="0">
+                      <xs:complexType>
+                        <xs:sequence>
+                          <xs:element type="xs:integer" name="entry-key"/>
+                          <xs:element type="xs:integer" name="entry-value"/>
+                        </xs:sequence>
+                      </xs:complexType>
+                    </xs:element>
+                  </xs:sequence>
+                  <xs:attribute type="xs:integer" name="total"/>
+                </xs:complexType>
+              </xs:element>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="share-target-reach">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="share-targets">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="share-target" maxOccurs="unbounded" minOccurs="0">
+                <xs:complexType>
+                  <xs:sequence>
+                    <xs:element type="xs:string" name="code"/>
+                    <xs:element name="tvalues">
+                      <xs:complexType>
+                        <xs:sequence>
+                          <xs:element type="xs:string" name="tvalue"/>
+                        </xs:sequence>
+                      </xs:complexType>
+                    </xs:element>
+                  </xs:sequence>
+                </xs:complexType>
+              </xs:element>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+</xs:schema>


[09/23] camel git commit: Removed redundant ignores

Posted by dh...@apache.org.
Removed redundant ignores


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

Branch: refs/heads/trunk
Commit: 8a398209ab371b61052022305c8f229053f0ea22
Parents: c87d4c0
Author: Dhiraj Bokde <db...@fusesource.com>
Authored: Wed Jun 5 02:56:27 2013 -0700
Committer: Dhiraj Bokde <db...@fusesource.com>
Committed: Wed Jun 5 02:56:27 2013 -0700

----------------------------------------------------------------------
 .../camel-salesforce/camel-salesforce-component/.gitignore     | 6 ------
 .../camel-salesforce/camel-salesforce-maven-plugin/.gitignore  | 5 -----
 2 files changed, 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/8a398209/components/camel-salesforce/camel-salesforce-component/.gitignore
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/.gitignore b/components/camel-salesforce/camel-salesforce-component/.gitignore
deleted file mode 100644
index acf55cc..0000000
--- a/components/camel-salesforce/camel-salesforce-component/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-target
-*.ipr
-*.iml
-*.iws
-# Salesforce login properties
-*test-login.properties*

http://git-wip-us.apache.org/repos/asf/camel/blob/8a398209/components/camel-salesforce/camel-salesforce-maven-plugin/.gitignore
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/.gitignore b/components/camel-salesforce/camel-salesforce-maven-plugin/.gitignore
deleted file mode 100644
index 7bbe0e0..0000000
--- a/components/camel-salesforce/camel-salesforce-maven-plugin/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-target
-*.iml
-*.iws
-*.ipr
-*test-login.properties*


[02/23] camel git commit: Added Salesforce component

Posted by dh...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/PushTopicHelper.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/PushTopicHelper.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/PushTopicHelper.java
new file mode 100644
index 0000000..b1c7f4d
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/PushTopicHelper.java
@@ -0,0 +1,206 @@
+package org.apache.camel.component.salesforce.internal.streaming;
+
+import org.apache.camel.CamelException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.eclipse.jetty.http.HttpStatus;
+import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.CreateSObjectResult;
+import org.apache.camel.component.salesforce.internal.client.RestClient;
+import org.apache.camel.component.salesforce.internal.client.SyncResponseCallback;
+import org.apache.camel.component.salesforce.internal.dto.PushTopic;
+import org.apache.camel.component.salesforce.internal.dto.QueryRecordsPushTopic;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+public class PushTopicHelper {
+    private static final Logger LOG = LoggerFactory.getLogger(PushTopicHelper.class);
+    private static final ObjectMapper objectMapper = new ObjectMapper();
+    private static final String PUSH_TOPIC_OBJECT_NAME = "PushTopic";
+    private static final long API_TIMEOUT = 60; // Rest API call timeout
+    private final SalesforceEndpointConfig config;
+    private final String topicName;
+    private final RestClient restClient;
+
+    public PushTopicHelper(SalesforceEndpointConfig config, String topicName, RestClient restClient) {
+        this.config = config;
+        this.topicName = topicName;
+        this.restClient = restClient;
+    }
+
+    public void createOrUpdateTopic() throws CamelException {
+        final String query = config.getSObjectQuery();
+
+        final SyncResponseCallback callback = new SyncResponseCallback();
+        // lookup Topic first
+        try {
+            // use SOQL to lookup Topic, since Name is not an external ID!!!
+            restClient.query("SELECT Id, Name, Query, ApiVersion, IsActive, " +
+                "NotifyForFields, NotifyForOperations, Description " +
+                "FROM PushTopic WHERE Name = '" + topicName + "'",
+                callback);
+
+            if (!callback.await(API_TIMEOUT, TimeUnit.SECONDS)) {
+                throw new SalesforceException("API call timeout!", null);
+            }
+            if (callback.getException() != null) {
+                throw callback.getException();
+            }
+            QueryRecordsPushTopic records = objectMapper.readValue(callback.getResponse(),
+                QueryRecordsPushTopic.class);
+            if (records.getTotalSize() == 1) {
+
+                PushTopic topic = records.getRecords().get(0);
+                LOG.info("Found existing topic {}: {}", topicName, topic);
+
+                // check if we need to update topic query, notifyForFields or notifyForOperations
+                if (!query.equals(topic.getQuery()) ||
+                    (config.getNotifyForFields() != null &&
+                        !config.getNotifyForFields().equals(topic.getNotifyForFields())) ||
+                    (config.getNotifyForOperations() != null &&
+                        !config.getNotifyForOperations().equals(topic.getNotifyForOperations()))
+                    ) {
+
+                    if (!config.isUpdateTopic()) {
+                        String msg = "Query doesn't match existing Topic and updateTopic is set to false";
+                        throw new CamelException(msg);
+                    }
+
+                    // otherwise update the topic
+                    updateTopic(topic.getId());
+                }
+
+            } else {
+                createTopic();
+            }
+
+        } catch (SalesforceException e) {
+            throw new CamelException(
+                String.format("Error retrieving Topic %s: %s", topicName, e.getMessage()),
+                e);
+        } catch (IOException e) {
+            throw new CamelException(
+                String.format("Un-marshaling error retrieving Topic %s: %s", topicName, e.getMessage()),
+                e);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new CamelException(
+                String.format("Un-marshaling error retrieving Topic %s: %s", topicName, e.getMessage()),
+                e);
+        } finally {
+            // close stream to close HttpConnection
+            if (callback.getResponse() != null) {
+                try {
+                    callback.getResponse().close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    private void createTopic() throws CamelException {
+        final PushTopic topic = new PushTopic();
+        topic.setName(topicName);
+        topic.setApiVersion(Double.valueOf(config.getApiVersion()));
+        topic.setQuery(config.getSObjectQuery());
+        topic.setDescription("Topic created by Camel Salesforce component");
+        topic.setNotifyForFields(config.getNotifyForFields());
+        topic.setNotifyForOperations(config.getNotifyForOperations());
+
+        LOG.info("Creating Topic {}: {}", topicName, topic);
+        final SyncResponseCallback callback = new SyncResponseCallback();
+        try {
+            restClient.createSObject(PUSH_TOPIC_OBJECT_NAME,
+                new ByteArrayInputStream(objectMapper.writeValueAsBytes(topic)), callback);
+
+            if (!callback.await(API_TIMEOUT, TimeUnit.SECONDS)) {
+                throw new SalesforceException("API call timeout!", null);
+            }
+            if (callback.getException() != null) {
+                throw callback.getException();
+            }
+
+            CreateSObjectResult result = objectMapper.readValue(callback.getResponse(), CreateSObjectResult.class);
+            if (!result.getSuccess()) {
+                final SalesforceException salesforceException = new SalesforceException(
+                    result.getErrors(), HttpStatus.BAD_REQUEST_400);
+                throw new CamelException(
+                    String.format("Error creating Topic %s: %s", topicName, result.getErrors()),
+                    salesforceException);
+            }
+        } catch (SalesforceException e) {
+            throw new CamelException(
+                String.format("Error creating Topic %s: %s", topicName, e.getMessage()),
+                e);
+        } catch (IOException e) {
+            throw new CamelException(
+                String.format("Un-marshaling error creating Topic %s: %s", topicName, e.getMessage()),
+                e);
+        } catch (InterruptedException e) {
+            throw new CamelException(
+                String.format("Un-marshaling error creating Topic %s: %s", topicName, e.getMessage()),
+                e);
+        } finally {
+            if (callback.getResponse() != null) {
+                try {
+                    callback.getResponse().close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    private void updateTopic(String topicId) throws CamelException {
+        final String query = config.getSObjectQuery();
+        LOG.info("Updating Topic {} with Query [{}]", topicName, query);
+
+        final SyncResponseCallback callback = new SyncResponseCallback();
+        try {
+            // update the query, notifyForFields and notifyForOperations fields
+            final PushTopic topic = new PushTopic();
+            topic.setQuery(query);
+            topic.setNotifyForFields(config.getNotifyForFields());
+            topic.setNotifyForOperations(config.getNotifyForOperations());
+
+            restClient.updateSObject("PushTopic", topicId,
+                new ByteArrayInputStream(objectMapper.writeValueAsBytes(topic)),
+                callback);
+
+            if (!callback.await(API_TIMEOUT, TimeUnit.SECONDS)) {
+                throw new SalesforceException("API call timeout!", null);
+            }
+            if (callback.getException() != null) {
+                throw callback.getException();
+            }
+
+        } catch (SalesforceException e) {
+            throw new CamelException(
+                String.format("Error updating topic %s with query [%s] : %s", topicName, query, e.getMessage()),
+                e);
+        } catch (InterruptedException e) {
+            // reset interrupt status
+            Thread.currentThread().interrupt();
+            throw new CamelException(
+                String.format("Error updating topic %s with query [%s] : %s", topicName, query, e.getMessage()),
+                e);
+        } catch (IOException e) {
+            throw new CamelException(
+                String.format("Error updating topic %s with query [%s] : %s", topicName, query, e.getMessage()),
+                e);
+        } finally {
+            if (callback.getResponse() != null) {
+                try {
+                    callback.getResponse().close();
+                } catch (IOException ignore) {
+                }
+            }
+        }
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/SubscriptionHelper.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/SubscriptionHelper.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/SubscriptionHelper.java
new file mode 100644
index 0000000..b3bd50f
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/SubscriptionHelper.java
@@ -0,0 +1,372 @@
+/**
+ * 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.internal.streaming;
+
+import org.apache.camel.CamelException;
+import org.apache.camel.Service;
+import org.cometd.bayeux.Message;
+import org.cometd.bayeux.client.ClientSessionChannel;
+import org.cometd.client.BayeuxClient;
+import org.cometd.client.transport.ClientTransport;
+import org.cometd.client.transport.LongPollingTransport;
+import org.eclipse.jetty.client.ContentExchange;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.http.HttpHeaders;
+import org.eclipse.jetty.http.HttpSchemes;
+import org.apache.camel.component.salesforce.SalesforceComponent;
+import org.apache.camel.component.salesforce.SalesforceConsumer;
+import org.apache.camel.component.salesforce.internal.SalesforceSession;
+import org.apache.camel.component.salesforce.internal.client.SalesforceSecurityListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.cometd.bayeux.Channel.*;
+import static org.cometd.bayeux.Message.ERROR_FIELD;
+import static org.cometd.bayeux.Message.SUBSCRIPTION_FIELD;
+
+public class SubscriptionHelper implements Service {
+    private static final Logger LOG = LoggerFactory.getLogger(SubscriptionHelper.class);
+
+    private static final int CONNECT_TIMEOUT = 110;
+    private static final int CHANNEL_TIMEOUT = 40;
+
+    private static final String EXCEPTION_FIELD = "exception";
+
+    private final SalesforceComponent component;
+    private final SalesforceSession session;
+    private final BayeuxClient client;
+
+    private final Map<SalesforceConsumer, ClientSessionChannel.MessageListener> listenerMap;
+
+    private boolean started;
+    private ClientSessionChannel.MessageListener handshakeListener;
+    private ClientSessionChannel.MessageListener connectListener;
+
+    private String handshakeError;
+    private Exception handshakeException;
+    private String connectError;
+    private boolean reconnecting;
+
+    public SubscriptionHelper(SalesforceComponent component) throws Exception {
+        this.component = component;
+        this.session = component.getSession();
+
+        this.listenerMap = new ConcurrentHashMap<SalesforceConsumer, ClientSessionChannel.MessageListener>();
+
+        // create CometD client
+        this.client = createClient();
+    }
+
+    @Override
+    public void start() throws Exception {
+        if (started) {
+            // no need to start again
+            return;
+        }
+
+        // listener for handshake error or exception
+        if (handshakeListener == null) {
+            // first start
+            handshakeListener = new ClientSessionChannel.MessageListener() {
+                public void onMessage(ClientSessionChannel channel, Message message) {
+                    LOG.debug("[CHANNEL:META_HANDSHAKE]: {}", message);
+
+                    if (!message.isSuccessful()) {
+                        String error = (String) message.get(ERROR_FIELD);
+                        if (error != null) {
+                            handshakeError = error;
+                        }
+                        Exception exception = (Exception) message.get(EXCEPTION_FIELD);
+                        if (exception != null) {
+                            handshakeException = exception;
+                        }
+                    } else if (!listenerMap.isEmpty()) {
+                        reconnecting = true;
+                    }
+                }
+            };
+        }
+        client.getChannel(META_HANDSHAKE).addListener(handshakeListener);
+
+        // listener for connect error
+        if (connectListener == null) {
+            connectListener = new ClientSessionChannel.MessageListener() {
+                public void onMessage(ClientSessionChannel channel, Message message) {
+                    LOG.debug("[CHANNEL:META_CONNECT]: {}", message);
+
+                    if (!message.isSuccessful()) {
+                        String error = (String) message.get(ERROR_FIELD);
+                        if (error != null) {
+                            connectError = error;
+                        }
+                    } else if (reconnecting) {
+
+                        reconnecting = false;
+
+                        LOG.debug("Refreshing subscriptions to {} channels on reconnect", listenerMap.size());
+                        // reconnected to Salesforce, subscribe to existing channels
+                        final Map<SalesforceConsumer, ClientSessionChannel.MessageListener> map =
+                            new HashMap<SalesforceConsumer, ClientSessionChannel.MessageListener>();
+                        map.putAll(listenerMap);
+                        listenerMap.clear();
+                        for (Map.Entry<SalesforceConsumer, ClientSessionChannel.MessageListener> entry :
+                            map.entrySet()) {
+                            final SalesforceConsumer consumer = entry.getKey();
+                            final String topicName = consumer.getTopicName();
+                            try {
+                                subscribe(topicName, consumer);
+                            } catch (CamelException e) {
+                                // let the consumer handle the exception
+                                consumer.handleException(
+                                    String.format("Error refreshing subscription to topic [%s]: %s",
+                                        topicName, e.getMessage()),
+                                    e);
+                            }
+                        }
+
+                    }
+                }
+            };
+        }
+        client.getChannel(META_CONNECT).addListener(connectListener);
+
+        // connect to Salesforce cometd endpoint
+        client.handshake();
+
+        final long waitMs = MILLISECONDS.convert(CONNECT_TIMEOUT, SECONDS);
+        if (!client.waitFor(waitMs, BayeuxClient.State.CONNECTED)) {
+            if (handshakeException != null) {
+                throw new CamelException(
+                    String.format("Exception during HANDSHAKE: %s", handshakeException.getMessage()),
+                    handshakeException);
+            } else if (handshakeError != null) {
+                throw new CamelException(String.format("Error during HANDSHAKE: %s", handshakeError));
+            } else if (connectError != null) {
+                throw new CamelException(String.format("Error during CONNECT: %s", connectError));
+            } else {
+                throw new CamelException(
+                    String.format("Handshake request timeout after %s seconds", CONNECT_TIMEOUT));
+            }
+        }
+
+        started = true;
+    }
+
+    @Override
+    public void stop() {
+        if (started) {
+            started = false;
+            // TODO find and log any disconnect errors
+            client.disconnect();
+            client.getChannel(META_CONNECT).removeListener(connectListener);
+            client.getChannel(META_HANDSHAKE).removeListener(handshakeListener);
+        }
+    }
+
+    private BayeuxClient createClient() throws Exception {
+        // use default Jetty client from SalesforceComponent, its shared by all consumers
+        final HttpClient httpClient = component.getConfig().getHttpClient();
+
+        Map<String, Object> options = new HashMap<String, Object>();
+        options.put(ClientTransport.TIMEOUT_OPTION, httpClient.getTimeout());
+
+        // check login access token
+        if (session.getAccessToken() == null) {
+            // lazy login here!
+            session.login(null);
+        }
+
+        LongPollingTransport transport = new LongPollingTransport(options, httpClient) {
+            @Override
+            protected void customize(ContentExchange exchange) {
+                super.customize(exchange);
+                // add SalesforceSecurityListener to handle token expiry
+                final String accessToken = session.getAccessToken();
+                try {
+                    final boolean isHttps = HttpSchemes.HTTPS.equals(String.valueOf(exchange.getScheme()));
+                    exchange.setEventListener(new SalesforceSecurityListener(
+                        httpClient.getDestination(exchange.getAddress(), isHttps),
+                        exchange, session, accessToken));
+                } catch (IOException e) {
+                    throw new RuntimeException(
+                        String.format("Error adding SalesforceSecurityListener to exchange %s", e.getMessage()),
+                        e);
+                }
+
+                // add current security token obtained from session
+                exchange.addRequestHeader(HttpHeaders.AUTHORIZATION,
+                "OAuth " + accessToken);
+            }
+        };
+
+        BayeuxClient client = new BayeuxClient(getEndpointUrl(), transport);
+
+        client.setDebugEnabled(false);
+
+        return client;
+    }
+
+    public void subscribe(final String topicName, final SalesforceConsumer consumer) throws CamelException {
+        // create subscription for consumer
+        final String channelName = getChannelName(topicName);
+
+        // channel message listener
+        LOG.info("Subscribing to channel {}...", channelName);
+        final ClientSessionChannel.MessageListener listener = new ClientSessionChannel.MessageListener() {
+
+            @Override
+            public void onMessage(ClientSessionChannel channel, Message message) {
+                LOG.debug("Received Message: {}", message);
+                // convert CometD message to Camel Message
+                consumer.processMessage(channel, message);
+            }
+
+        };
+
+        final ClientSessionChannel clientChannel = client.getChannel(channelName);
+
+        // listener for subscribe error
+        final CountDownLatch latch = new CountDownLatch(1);
+        final String[] subscribeError = {null};
+        final ClientSessionChannel.MessageListener subscriptionListener = new ClientSessionChannel.MessageListener() {
+            public void onMessage(ClientSessionChannel channel, Message message) {
+                LOG.debug("[CHANNEL:META_SUBSCRIBE]: {}", message);
+                final String subscribedChannelName = message.get(SUBSCRIPTION_FIELD).toString();
+                if (channelName.equals(subscribedChannelName)) {
+
+                    if (!message.isSuccessful()) {
+                        String error = (String) message.get(ERROR_FIELD);
+                        if (error != null) {
+                            subscribeError[0] = error;
+                        }
+                    } else {
+                        // remember subscription
+                        LOG.info("Subscribed to channel {}", subscribedChannelName);
+                    }
+                    latch.countDown();
+                }
+            }
+        };
+        client.getChannel(META_SUBSCRIBE).addListener(subscriptionListener);
+
+        try {
+            clientChannel.subscribe(listener);
+
+            // confirm that a subscription was created
+            try {
+                if (!latch.await(CHANNEL_TIMEOUT, SECONDS)) {
+                    String message;
+                    if (subscribeError[0] != null) {
+                        message = String.format("Error subscribing to topic %s: %s",
+                            topicName, subscribeError[0]);
+                    } else {
+                        message = String.format("Timeout error subscribing to topic %s after %s seconds",
+                            topicName, CHANNEL_TIMEOUT);
+                    }
+                    throw new CamelException(message);
+                }
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                // probably shutting down, so forget subscription
+            }
+
+            listenerMap.put(consumer, listener);
+
+        } finally {
+            client.getChannel(META_SUBSCRIBE).removeListener(subscriptionListener);
+        }
+    }
+
+    private String getChannelName(String topicName) {
+        return "/topic/" + topicName;
+    }
+
+    public void unsubscribe(String topicName, SalesforceConsumer consumer) throws CamelException {
+
+        // channel name
+        final String channelName = getChannelName(topicName);
+
+        // listen for unsubscribe error
+        final CountDownLatch latch = new CountDownLatch(1);
+        final String[] unsubscribeError = {null};
+        final ClientSessionChannel.MessageListener unsubscribeListener = new ClientSessionChannel.MessageListener() {
+            public void onMessage(ClientSessionChannel channel, Message message) {
+                LOG.debug("[CHANNEL:META_UNSUBSCRIBE]: {}", message);
+                String unsubscribedChannelName = message.get(SUBSCRIPTION_FIELD).toString();
+                if (channelName.equals(unsubscribedChannelName)) {
+
+                    if (!message.isSuccessful()) {
+                        String error = (String) message.get(ERROR_FIELD);
+                        if (error != null) {
+                            unsubscribeError[0] = error;
+                        }
+                    } else {
+                        // forget subscription
+                        LOG.info("Unsubscribed from channel {}", unsubscribedChannelName);
+                    }
+                    latch.countDown();
+                }
+            }
+        };
+        client.getChannel(META_UNSUBSCRIBE).addListener(unsubscribeListener);
+
+        try {
+            // unsubscribe from channel
+            final ClientSessionChannel.MessageListener listener = listenerMap.remove(consumer);
+            if (listener != null) {
+
+                LOG.info("Unsubscribing from channel {}...", channelName);
+                final ClientSessionChannel clientChannel = client.getChannel(channelName);
+                clientChannel.unsubscribe(listener);
+
+                // confirm unsubscribe
+                try {
+                    if (!latch.await(CHANNEL_TIMEOUT, SECONDS)) {
+                        String message;
+                        if (unsubscribeError[0] != null) {
+                            message = String.format("Error unsubscribing from topic %s: %s",
+                                topicName, unsubscribeError[0]);
+                        } else {
+                            message = String.format("Timeout error unsubscribing from topic %s after %s seconds",
+                                topicName, CHANNEL_TIMEOUT);
+                        }
+                        throw new CamelException(message);
+                    }
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    // probably shutting down, forget unsubscribe and return
+                }
+
+            }
+        } finally {
+            client.getChannel(META_UNSUBSCRIBE).removeListener(unsubscribeListener);
+        }
+    }
+
+    public String getEndpointUrl() {
+        return component.getSession().getInstanceUrl() + "/cometd/" + component.getConfig().getApiVersion();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/resources/META-INF/services/org/apache/camel/component/salesforce
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/resources/META-INF/services/org/apache/camel/component/salesforce b/components/camel-salesforce/camel-salesforce-component/src/main/resources/META-INF/services/org/apache/camel/component/salesforce
new file mode 100644
index 0000000..ad8d689
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/resources/META-INF/services/org/apache/camel/component/salesforce
@@ -0,0 +1 @@
+class=org.apache.camel.component.salesforce.SalesforceComponent

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/AbstractBulkApiTestBase.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/AbstractBulkApiTestBase.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/AbstractBulkApiTestBase.java
new file mode 100644
index 0000000..c48d143
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/AbstractBulkApiTestBase.java
@@ -0,0 +1,105 @@
+/**
+ * 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 org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.salesforce.api.dto.bulk.BatchInfo;
+import org.apache.camel.component.salesforce.api.dto.bulk.BatchStateEnum;
+import org.apache.camel.component.salesforce.api.dto.bulk.JobInfo;
+import org.junit.experimental.theories.Theories;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public abstract class AbstractBulkApiTestBase extends AbstractSalesforceTestBase {
+
+    protected JobInfo createJob(JobInfo jobInfo) throws InterruptedException {
+        jobInfo = template().requestBody("direct:createJob", jobInfo, JobInfo.class);
+        assertNotNull("Missing JobId", jobInfo.getId());
+        return jobInfo;
+    }
+
+    @Override
+    protected RouteBuilder doCreateRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                // test createJob
+                from("direct:createJob").
+                    to("salesforce://createJob");
+
+                // test getJob
+                from("direct:getJob").
+                    to("salesforce:getJob");
+
+                // test closeJob
+                from("direct:closeJob").
+                    to("salesforce:closeJob");
+
+                // test abortJob
+                from("direct:abortJob").
+                    to("salesforce:abortJob");
+
+                // test createBatch
+                from("direct:createBatch").
+                    to("salesforce:createBatch");
+
+                // test getBatch
+                from("direct:getBatch").
+                    to("salesforce:getBatch");
+
+                // test getAllBatches
+                from("direct:getAllBatches").
+                    to("salesforce:getAllBatches");
+
+                // test getRequest
+                from("direct:getRequest").
+                    to("salesforce:getRequest");
+
+                // test getResults
+                from("direct:getResults").
+                    to("salesforce:getResults");
+
+                // test createBatchQuery
+                from("direct:createBatchQuery").
+                    to("salesforce:createBatchQuery?sObjectQuery=SELECT Name, Description__c, Price__c, Total_Inventory__c FROM Merchandise__c WHERE Name LIKE '%25Bulk API%25'");
+
+                // test getQueryResultIds
+                from("direct:getQueryResultIds").
+                    to("salesforce:getQueryResultIds");
+
+                // test getQueryResult
+                from("direct:getQueryResult").
+                    to("salesforce:getQueryResult");
+
+            }
+        };
+    }
+
+    protected boolean batchProcessed(BatchInfo batchInfo) {
+        BatchStateEnum state = batchInfo.getState();
+        return !(state == BatchStateEnum.QUEUED || state == BatchStateEnum.IN_PROGRESS);
+    }
+
+    protected BatchInfo getBatchInfo(BatchInfo batchInfo) throws InterruptedException {
+        batchInfo = template().requestBody("direct:getBatch", batchInfo, BatchInfo.class);
+
+        assertNotNull("Null batch", batchInfo);
+        assertNotNull("Null batch id", batchInfo.getId());
+
+        return batchInfo;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/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
new file mode 100644
index 0000000..3130a5b
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/AbstractSalesforceTestBase.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.salesforce;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.apache.camel.component.salesforce.dto.Merchandise__c;
+
+import java.io.IOException;
+
+public abstract class AbstractSalesforceTestBase extends CamelTestSupport {
+
+    @Override
+    public boolean isCreateCamelContextPerClass() {
+        // only create the context once for this class
+        return true;
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        // create the test component
+        createComponent();
+
+        return doCreateRouteBuilder();
+    }
+
+    protected abstract RouteBuilder doCreateRouteBuilder() throws Exception;
+
+    protected void createComponent() throws IllegalAccessException, IOException {
+        // create the component
+        SalesforceComponent component = new SalesforceComponent();
+        final SalesforceEndpointConfig config = new SalesforceEndpointConfig();
+        config.setApiVersion(System.getProperty("apiVersion", SalesforceEndpointConfig.DEFAULT_VERSION));
+        component.setConfig(config);
+        component.setLoginConfig(LoginConfigHelper.getLoginConfig());
+
+        // set DTO package
+        component.setPackages(new String[] {
+            Merchandise__c.class.getPackage().getName()
+        });
+
+        // add it to context
+        context().addComponent("salesforce", component);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/BulkApiBatchIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/BulkApiBatchIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/BulkApiBatchIntegrationTest.java
new file mode 100644
index 0000000..bed6a0c
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/BulkApiBatchIntegrationTest.java
@@ -0,0 +1,109 @@
+/**
+ * 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 org.apache.camel.component.salesforce.api.dto.bulk.*;
+import org.apache.camel.component.salesforce.dto.Merchandise__c;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theory;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class BulkApiBatchIntegrationTest extends AbstractBulkApiTestBase {
+    private static final String TEST_REQUEST_XML = "/test-request.xml";
+    private static final String TEST_REQUEST_CSV = "/test-request.csv";
+
+    @DataPoints
+    public static BatchTest[] getBatches() {
+        List<BatchTest> result = new ArrayList<BatchTest>();
+        BatchTest test = new BatchTest();
+        test.contentType = ContentType.XML;
+        test.stream = AbstractBulkApiTestBase.class.getResourceAsStream(TEST_REQUEST_XML);
+        result.add(test);
+
+        test = new BatchTest();
+        test.contentType = ContentType.CSV;
+        test.stream = AbstractBulkApiTestBase.class.getResourceAsStream(TEST_REQUEST_CSV);
+        result.add(test);
+
+        // TODO test ZIP_XML and ZIP_CSV
+        return result.toArray(new BatchTest[result.size()]);
+    }
+
+    @Theory
+    public void testBatchLifecycle(BatchTest request) throws Exception {
+        log.info("Testing Batch lifecycle with {} content", request.contentType);
+
+        // create an UPSERT test Job for this batch request
+        JobInfo jobInfo = new JobInfo();
+        jobInfo.setOperation(OperationEnum.UPSERT);
+        jobInfo.setContentType(request.contentType);
+        jobInfo.setObject(Merchandise__c.class.getSimpleName());
+        jobInfo.setExternalIdFieldName("Name");
+        jobInfo = createJob(jobInfo);
+
+        // test createBatch
+        Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put(SalesforceEndpointConfig.JOB_ID, jobInfo.getId());
+        headers.put(SalesforceEndpointConfig.CONTENT_TYPE, jobInfo.getContentType());
+        BatchInfo batchInfo  = template().requestBodyAndHeaders("direct:createBatch",
+            request.stream, headers, BatchInfo.class);
+        assertNotNull("Null batch", batchInfo);
+        assertNotNull("Null batch id", batchInfo.getId());
+
+        // test getAllBatches
+        @SuppressWarnings("unchecked")
+        List<BatchInfo> batches = template().requestBody("direct:getAllBatches", jobInfo, List.class);
+        assertNotNull("Null batches", batches);
+        assertFalse("Empty batch list", batches.isEmpty());
+
+        // test getBatch
+        batchInfo = batches.get(0);
+        batchInfo = getBatchInfo(batchInfo);
+
+        // test getRequest
+        InputStream requestStream  = template().requestBody("direct:getRequest", batchInfo, InputStream.class);
+        assertNotNull("Null batch request", requestStream);
+
+        // wait for batch to finish
+        log.info("Waiting for batch to finish...");
+        while (!batchProcessed(batchInfo)) {
+            // sleep 5 seconds
+            Thread.sleep(5000);
+            // check again
+            batchInfo = getBatchInfo(batchInfo);
+        }
+        log.info("Batch finished with state " + batchInfo.getState());
+        assertEquals("Batch did not succeed", BatchStateEnum.COMPLETED, batchInfo.getState());
+
+        // test getResults
+        InputStream results  = template().requestBody("direct:getResults", batchInfo, InputStream.class);
+        assertNotNull("Null batch results", results);
+
+        // close the test job
+        template().requestBody("direct:closeJob", jobInfo, JobInfo.class);
+    }
+
+    private static class BatchTest {
+        public InputStream stream;
+        public ContentType contentType;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/BulkApiJobIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/BulkApiJobIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/BulkApiJobIntegrationTest.java
new file mode 100644
index 0000000..9010aa4
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/BulkApiJobIntegrationTest.java
@@ -0,0 +1,111 @@
+/**
+ * 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 org.apache.camel.component.salesforce.api.dto.bulk.ContentType;
+import org.apache.camel.component.salesforce.api.dto.bulk.JobInfo;
+import org.apache.camel.component.salesforce.api.dto.bulk.JobStateEnum;
+import org.apache.camel.component.salesforce.api.dto.bulk.OperationEnum;
+import org.apache.camel.component.salesforce.dto.Merchandise__c;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BulkApiJobIntegrationTest extends AbstractBulkApiTestBase {
+
+    // test jobs for testJobLifecycle
+    @DataPoints
+    public static JobInfo[] getJobs() {
+        JobInfo jobInfo = new JobInfo();
+
+        // insert XML
+        jobInfo.setObject(Merchandise__c.class.getSimpleName());
+        jobInfo.setContentType(ContentType.XML);
+        jobInfo.setOperation(OperationEnum.INSERT);
+
+        List<JobInfo> result = new ArrayList<JobInfo>();
+        result.add(jobInfo);
+
+        // insert CSV
+        jobInfo = new JobInfo();
+        jobInfo.setObject(Merchandise__c.class.getSimpleName());
+        jobInfo.setContentType(ContentType.CSV);
+        jobInfo.setOperation(OperationEnum.INSERT);
+        result.add(jobInfo);
+
+        // update CSV
+        jobInfo = new JobInfo();
+        jobInfo.setObject(Merchandise__c.class.getSimpleName());
+        jobInfo.setContentType(ContentType.CSV);
+        jobInfo.setOperation(OperationEnum.UPDATE);
+        result.add(jobInfo);
+
+        // upsert CSV
+        jobInfo = new JobInfo();
+        jobInfo.setObject(Merchandise__c.class.getSimpleName());
+        jobInfo.setContentType(ContentType.CSV);
+        jobInfo.setOperation(OperationEnum.UPSERT);
+        jobInfo.setExternalIdFieldName("Name");
+        result.add(jobInfo);
+
+        // delete CSV
+        jobInfo = new JobInfo();
+        jobInfo.setObject(Merchandise__c.class.getSimpleName());
+        jobInfo.setContentType(ContentType.CSV);
+        jobInfo.setOperation(OperationEnum.DELETE);
+        result.add(jobInfo);
+
+        // hard delete CSV
+        jobInfo = new JobInfo();
+        jobInfo.setObject(Merchandise__c.class.getSimpleName());
+        jobInfo.setContentType(ContentType.CSV);
+        jobInfo.setOperation(OperationEnum.HARD_DELETE);
+        result.add(jobInfo);
+
+        // query CSV
+        jobInfo = new JobInfo();
+        jobInfo.setObject(Merchandise__c.class.getSimpleName());
+        jobInfo.setContentType(ContentType.CSV);
+        jobInfo.setOperation(OperationEnum.QUERY);
+        result.add(jobInfo);
+
+        return result.toArray(new JobInfo[result.size()]);
+    }
+
+    @Theory
+    public void testJobLifecycle(JobInfo jobInfo) throws Exception {
+        log.info("Testing Job lifecycle for {} of type {}", jobInfo.getOperation(), jobInfo.getContentType());
+
+        // test create
+        jobInfo = createJob(jobInfo);
+
+        // test get
+        jobInfo = template().requestBody("direct:getJob", jobInfo, JobInfo.class);
+        assertSame("Job should be OPEN", JobStateEnum.OPEN, jobInfo.getState());
+
+        // test close
+        jobInfo = template().requestBody("direct:closeJob", jobInfo, JobInfo.class);
+        assertSame("Job should be CLOSED", JobStateEnum.CLOSED, jobInfo.getState());
+
+        // test abort
+        jobInfo = template().requestBody("direct:abortJob", jobInfo, JobInfo.class);
+        assertSame("Job should be ABORTED", JobStateEnum.ABORTED, jobInfo.getState());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/BulkApiQueryIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/BulkApiQueryIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/BulkApiQueryIntegrationTest.java
new file mode 100644
index 0000000..0f22ee1
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/BulkApiQueryIntegrationTest.java
@@ -0,0 +1,85 @@
+/**
+ * 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 org.apache.camel.component.salesforce.api.dto.bulk.*;
+import org.apache.camel.component.salesforce.dto.Merchandise__c;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theory;
+
+import java.io.InputStream;
+import java.util.List;
+
+public class BulkApiQueryIntegrationTest extends AbstractBulkApiTestBase {
+
+    @DataPoints
+    public static ContentType[] getContentTypes() {
+        return new ContentType[] {
+            ContentType.XML,
+            ContentType.CSV
+        };
+    }
+
+    @Theory
+    public void testQueryLifecycle(ContentType contentType) throws Exception {
+        log.info("Testing Query lifecycle with {} content", contentType);
+
+        // create a QUERY test Job
+        JobInfo jobInfo = new JobInfo();
+        jobInfo.setOperation(OperationEnum.QUERY);
+        jobInfo.setContentType(contentType);
+        jobInfo.setObject(Merchandise__c.class.getSimpleName());
+        jobInfo = createJob(jobInfo);
+
+        // test createQuery
+        BatchInfo batchInfo = template().requestBody("direct:createBatchQuery", jobInfo, BatchInfo.class);
+        assertNotNull("Null batch query", batchInfo);
+        assertNotNull("Null batch query id", batchInfo.getId());
+
+        // test getRequest
+        InputStream requestStream = template().requestBody("direct:getRequest", batchInfo, InputStream.class);
+        assertNotNull("Null batch request", requestStream);
+
+        // wait for batch to finish
+        log.info("Waiting for query batch to finish...");
+        while (!batchProcessed(batchInfo)) {
+            // sleep 5 seconds
+            Thread.sleep(5000);
+            // check again
+            batchInfo = getBatchInfo(batchInfo);
+        }
+        log.info("Query finished with state " + batchInfo.getState());
+        assertEquals("Query did not succeed", BatchStateEnum.COMPLETED, batchInfo.getState());
+
+        // test getQueryResultList
+        @SuppressWarnings("unchecked")
+        List<String> resultIds = template().requestBody("direct:getQueryResultIds", batchInfo, List.class);
+        assertNotNull("Null query result ids", resultIds);
+        assertFalse("Empty result ids", resultIds.isEmpty());
+
+        // test getQueryResult
+        for (String resultId : resultIds) {
+            InputStream results = template().requestBodyAndHeader("direct:getQueryResult", batchInfo,
+                SalesforceEndpointConfig.RESULT_ID, resultId, InputStream.class);
+            assertNotNull("Null query result", results);
+        }
+
+        // close the test job
+        template().requestBody("direct:closeJob", jobInfo, JobInfo.class);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java
new file mode 100644
index 0000000..8c5d343
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java
@@ -0,0 +1,43 @@
+package org.apache.camel.component.salesforce;
+
+import org.junit.Assert;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+public class LoginConfigHelper extends Assert {
+
+    private static final String TEST_LOGIN_PROPERTIES = "test-salesforce-login.properties";
+
+    public static SalesforceLoginConfig getLoginConfig() throws IllegalAccessException, IOException {
+
+        // load test-salesforce-login properties
+        Properties properties = new Properties();
+        InputStream stream = new FileInputStream(TEST_LOGIN_PROPERTIES);
+        if (null == stream) {
+            throw new IllegalArgumentException("Create a properties file named " +
+                TEST_LOGIN_PROPERTIES + " with clientId, clientSecret, userName, and password" +
+                " for a Salesforce account with the Merchandise object from Salesforce Guides.");
+        }
+        properties.load(stream);
+
+        final SalesforceLoginConfig config = new SalesforceLoginConfig(
+            properties.getProperty("loginUrl", SalesforceLoginConfig.DEFAULT_LOGIN_URL),
+            properties.getProperty("clientId"),
+            properties.getProperty("clientSecret"),
+            properties.getProperty("userName"),
+            properties.getProperty("password"),
+            Boolean.parseBoolean(properties.getProperty("lazyLogin", "false")));
+
+        assertNotNull("Null loginUrl", config.getLoginUrl());
+        assertNotNull("Null clientId", config.getClientId());
+        assertNotNull("Null clientSecret", config.getClientSecret());
+        assertNotNull("Null userName", config.getUserName());
+        assertNotNull("Null password", config.getPassword());
+
+        return config;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
new file mode 100644
index 0000000..a33d17d
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
@@ -0,0 +1,408 @@
+/**
+ * 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 org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.salesforce.api.dto.*;
+import org.apache.camel.component.salesforce.dto.Document;
+import org.apache.camel.component.salesforce.dto.Line_Item__c;
+import org.apache.camel.component.salesforce.dto.Merchandise__c;
+import org.apache.camel.component.salesforce.dto.QueryRecordsLine_Item__c;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.util.HashMap;
+import java.util.List;
+
+public class RestApiIntegrationTest extends AbstractSalesforceTestBase {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RestApiIntegrationTest.class);
+    private static final String TEST_LINE_ITEM_ID = "1";
+    private static final String NEW_LINE_ITEM_ID = "100";
+    private static final String TEST_DOCUMENT_ID = "Test Document";
+
+    private static String testId;
+
+    @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);
+    }
+
+    @Test
+    public void testGetResources() throws Exception {
+        doTestGetResources("");
+        doTestGetResources("Xml");
+    }
+
+    private void doTestGetResources(String suffix) throws Exception {
+
+
+        RestResources resources = template().requestBody("direct:getResources" + suffix, null, RestResources.class);
+        assertNotNull(resources);
+        LOG.debug("Resources: {}", resources);
+    }
+
+    @Test
+    public void testGetGlobalObjects() throws Exception {
+        doTestGetGlobalObjects("");
+        doTestGetGlobalObjects("Xml");
+    }
+
+    private void doTestGetGlobalObjects(String suffix) throws Exception {
+
+
+        GlobalObjects globalObjects = template().requestBody("direct:getGlobalObjects" + suffix, null, GlobalObjects.class);
+        assertNotNull(globalObjects);
+        LOG.debug("GlobalObjects: {}", globalObjects);
+    }
+
+    @Test
+    public void testGetBasicInfo() throws Exception {
+        doTestGetBasicInfo("");
+        doTestGetBasicInfo("Xml");
+    }
+
+    private void doTestGetBasicInfo(String suffix) throws Exception {
+        SObjectBasicInfo objectBasicInfo = template().requestBody("direct:getBasicInfo" + suffix, null, SObjectBasicInfo.class);
+        assertNotNull(objectBasicInfo);
+        LOG.debug("SObjectBasicInfo: {}", objectBasicInfo);
+
+        // set test Id for testGetSObject
+        assertFalse("RecentItems is empty", objectBasicInfo.getRecentItems().isEmpty());
+        testId = objectBasicInfo.getRecentItems().get(0).getId();
+    }
+
+    @Test
+    public void testGetDescription() throws Exception {
+        doTestGetDescription("");
+        doTestGetDescription("Xml");
+    }
+
+    private void doTestGetDescription(String suffix) throws Exception {
+
+
+        SObjectDescription sObjectDescription = template().requestBody("direct:getDescription" + suffix, null, SObjectDescription.class);
+        assertNotNull(sObjectDescription);
+        LOG.debug("SObjectDescription: {}", sObjectDescription);
+    }
+
+    @Test
+    public void testGetSObject() throws Exception {
+        doTestGetSObject("");
+        doTestGetSObject("Xml");
+    }
+
+    private void doTestGetSObject(String suffix) throws Exception {
+        if (testId == null) {
+            // execute getBasicInfo to get test id from recent items
+            doTestGetBasicInfo("");
+        }
+
+        Merchandise__c merchandise = template().requestBody("direct:getSObject" + suffix, testId, Merchandise__c.class);
+        assertNotNull(merchandise);
+        if (suffix.isEmpty()) {
+            assertNull(merchandise.getTotal_Inventory__c());
+            assertNotNull(merchandise.getPrice__c());
+        } else {
+            assertNotNull(merchandise.getTotal_Inventory__c());
+            assertNull(merchandise.getPrice__c());
+        }
+        LOG.debug("SObjectById: {}", merchandise);
+    }
+
+    @Test
+    public void testCreateUpdateDelete() throws Exception {
+        doTestCreateUpdateDelete("");
+        doTestCreateUpdateDelete("Xml");
+    }
+
+    private void doTestCreateUpdateDelete(String suffix) throws InterruptedException {
+        Merchandise__c merchandise__c = new Merchandise__c();
+        merchandise__c.setName("Wee Wee Wee Plane");
+        merchandise__c.setDescription__c("Microlite plane");
+        merchandise__c.setPrice__c(2000.0);
+        merchandise__c.setTotal_Inventory__c(50.0);
+        CreateSObjectResult result = template().requestBody("direct:CreateSObject" + suffix,
+            merchandise__c, CreateSObjectResult.class);
+        assertNotNull(result);
+        assertTrue("Create success", result.getSuccess());
+        LOG.debug("Create: " + result);
+
+        // test JSON update
+        // make the plane cheaper
+        merchandise__c.setPrice__c(1500.0);
+        // change inventory to half
+        merchandise__c.setTotal_Inventory__c(25.0);
+        // also need to set the Id
+        merchandise__c.setId(result.getId());
+
+        assertNull(template().requestBodyAndHeader("direct:UpdateSObject" + suffix,
+            merchandise__c, SalesforceEndpointConfig.SOBJECT_ID, result.getId()));
+        LOG.debug("Update successful");
+
+        // delete the newly created SObject
+        assertNull(template().requestBody("direct:deleteSObject" + suffix, result.getId()));
+        LOG.debug("Delete successful");
+    }
+
+    @Test
+    public void testCreateUpdateDeleteWithId() throws Exception {
+        doTestCreateUpdateDeleteWithId("");
+        doTestCreateUpdateDeleteWithId("Xml");
+    }
+
+    private void doTestCreateUpdateDeleteWithId(String suffix) throws InterruptedException {
+        // get line item with Name 1
+        Line_Item__c line_item__c = template().requestBody("direct:getSObjectWithId" + suffix, TEST_LINE_ITEM_ID,
+            Line_Item__c.class);
+        assertNotNull(line_item__c);
+        LOG.debug("GetWithId: {}", line_item__c);
+
+        // test insert with id
+        // set the unit price and sold
+        line_item__c.setUnit_Price__c(1000.0);
+        line_item__c.setUnits_Sold__c(50.0);
+        // update line item with Name NEW_LINE_ITEM_ID
+        line_item__c.setName(NEW_LINE_ITEM_ID);
+
+        CreateSObjectResult result = template().requestBodyAndHeader("direct:upsertSObject" + suffix,
+            line_item__c, SalesforceEndpointConfig.SOBJECT_EXT_ID_VALUE, NEW_LINE_ITEM_ID,
+            CreateSObjectResult.class);
+        assertNotNull(result);
+        assertTrue(result.getSuccess());
+        LOG.debug("CreateWithId: {}", result);
+
+        // clear read only parent type fields
+        line_item__c.setInvoice_Statement__c(null);
+        line_item__c.setMerchandise__c(null);
+        // change the units sold
+        line_item__c.setUnits_Sold__c(25.0);
+
+        // update line item with Name NEW_LINE_ITEM_ID
+        result = template().requestBodyAndHeader("direct:upsertSObject" + suffix,
+            line_item__c, SalesforceEndpointConfig.SOBJECT_EXT_ID_VALUE, NEW_LINE_ITEM_ID,
+            CreateSObjectResult.class);
+        assertNull(result);
+        LOG.debug("UpdateWithId: {}", result);
+
+        // delete the SObject with Name NEW_LINE_ITEM_ID
+        assertNull(template().requestBody("direct:deleteSObjectWithId" + suffix, NEW_LINE_ITEM_ID));
+        LOG.debug("DeleteWithId successful");
+    }
+
+    @Test
+    public void testGetBlobField() throws Exception {
+        doTestGetBlobField("");
+        doTestGetBlobField("Xml");
+    }
+
+    public void doTestGetBlobField(String suffix) throws Exception {
+        // get document with Name "Test Document"
+        final HashMap<String, Object> headers = new HashMap<String, Object>();
+        headers.put(SalesforceEndpointConfig.SOBJECT_NAME, "Document");
+        headers.put(SalesforceEndpointConfig.SOBJECT_EXT_ID_NAME, "Name");
+        Document document = template().requestBodyAndHeaders("direct:getSObjectWithId" + suffix, TEST_DOCUMENT_ID,
+            headers, Document.class);
+        assertNotNull(document);
+        LOG.debug("GetWithId: {}", document);
+
+        // get Body field for this document
+        InputStream body = template().requestBody("direct:getBlobField" + suffix, document, InputStream.class);
+        assertNotNull(body);
+        LOG.debug("GetBlobField: {}", body);
+        // write body to test file
+        final FileChannel fileChannel = new FileOutputStream("target/getBlobField" + suffix + ".txt").getChannel();
+        final ReadableByteChannel src = Channels.newChannel(body);
+        fileChannel.transferFrom(src, 0, document.getBodyLength());
+        fileChannel.close();
+        src.close();
+    }
+
+    @Test
+    public void testQuery() throws Exception {
+        doTestQuery("");
+        doTestQuery("Xml");
+    }
+
+    private void doTestQuery(String suffix) throws InterruptedException {
+        QueryRecordsLine_Item__c queryRecords = template().requestBody("direct:query" + suffix, null,
+            QueryRecordsLine_Item__c.class);
+        assertNotNull(queryRecords);
+        LOG.debug("ExecuteQuery: {}", queryRecords);
+    }
+
+
+    @Test
+    public void testSearch() throws Exception {
+        doTestSearch("");
+        doTestSearch("Xml");
+    }
+
+    @SuppressWarnings("unchecked")
+    private void doTestSearch(String suffix) throws InterruptedException {
+
+        Object obj = template().requestBody("direct:search" + suffix, (Object) null);
+        List<SearchResult> searchResults = null;
+        if (obj instanceof SearchResults) {
+            SearchResults results = (SearchResults) obj;
+            searchResults = results.getResults();
+        } else {
+            searchResults = (List<SearchResult>) obj;
+        }
+        assertNotNull(searchResults);
+        LOG.debug("ExecuteSearch: {}", searchResults);
+    }
+
+    @Override
+    protected RouteBuilder doCreateRouteBuilder() throws Exception {
+
+        // create test route
+        return new RouteBuilder() {
+            public void configure() {
+
+                // testGetVersion
+                from("direct:getVersions")
+                    .to("salesforce:getVersions");
+
+                // allow overriding format per endpoint
+                from("direct:getVersionsXml")
+                    .to("salesforce:getVersions?format=xml");
+
+                // testGetResources
+                from("direct:getResources")
+                    .to("salesforce:getResources");
+
+                from("direct:getResourcesXml")
+                    .to("salesforce:getResources?format=xml");
+
+                // testGetGlobalObjects
+                from("direct:getGlobalObjects")
+                    .to("salesforce:getGlobalObjects");
+
+                from("direct:getGlobalObjectsXml")
+                    .to("salesforce:getGlobalObjects?format=xml");
+
+                // testGetBasicInfo
+                from("direct:getBasicInfo")
+                    .to("salesforce:getBasicInfo?sObjectName=Merchandise__c");
+
+                from("direct:getBasicInfoXml")
+                    .to("salesforce:getBasicInfo?format=xml&sObjectName=Merchandise__c");
+
+                // testGetDescription
+                from("direct:getDescription")
+                    .to("salesforce:getDescription?sObjectName=Merchandise__c");
+
+                from("direct:getDescriptionXml")
+                    .to("salesforce:getDescription?format=xml&sObjectName=Merchandise__c");
+
+                // testGetSObject
+                from("direct:getSObject")
+                    .to("salesforce:getSObject?sObjectName=Merchandise__c&sObjectFields=Description__c,Price__c");
+
+                from("direct:getSObjectXml")
+                    .to("salesforce:getSObject?format=xml&sObjectName=Merchandise__c&sObjectFields=Description__c,Total_Inventory__c");
+
+                // testCreateSObject
+                from("direct:CreateSObject")
+                    .to("salesforce:createSObject?sObjectName=Merchandise__c");
+
+                from("direct:CreateSObjectXml")
+                    .to("salesforce:createSObject?format=xml&sObjectName=Merchandise__c");
+
+                // testUpdateSObject
+                from("direct:UpdateSObject")
+                    .to("salesforce:updateSObject?sObjectName=Merchandise__c");
+
+                from("direct:UpdateSObjectXml")
+                    .to("salesforce:updateSObject?format=xml&sObjectName=Merchandise__c");
+
+                // testDeleteSObject
+                from("direct:deleteSObject")
+                    .to("salesforce:deleteSObject?sObjectName=Merchandise__c");
+
+                from("direct:deleteSObjectXml")
+                    .to("salesforce:deleteSObject?format=xml&sObjectName=Merchandise__c");
+
+                // testGetSObjectWithId
+                from("direct:getSObjectWithId")
+                    .to("salesforce:getSObjectWithId?sObjectName=Line_Item__c&sObjectIdName=Name");
+
+                from("direct:getSObjectWithIdXml")
+                    .to("salesforce:getSObjectWithId?format=xml&sObjectName=Line_Item__c&sObjectIdName=Name");
+
+                // testUpsertSObject
+                from("direct:upsertSObject")
+                    .to("salesforce:upsertSObject?sObjectName=Line_Item__c&sObjectIdName=Name");
+
+                from("direct:upsertSObjectXml")
+                    .to("salesforce:upsertSObject?format=xml&sObjectName=Line_Item__c&sObjectIdName=Name");
+
+                // testDeleteSObjectWithId
+                from("direct:deleteSObjectWithId")
+                    .to("salesforce:deleteSObjectWithId?sObjectName=Line_Item__c&sObjectIdName=Name");
+
+                from("direct:deleteSObjectWithIdXml")
+                    .to("salesforce:deleteSObjectWithId?format=xml&sObjectName=Line_Item__c&sObjectIdName=Name");
+
+                // testGetBlobField
+                from("direct:getBlobField")
+                    .to("salesforce:getBlobField?sObjectName=Document&sObjectBlobFieldName=Body");
+
+                from("direct:getBlobFieldXml")
+                    .to("salesforce:getBlobField?format=xml&sObjectName=Document&sObjectBlobFieldName=Body");
+
+                // testQuery
+                from("direct:query")
+                    .to("salesforce:query?sObjectQuery=SELECT name from Line_Item__c&sObjectClass=org.apache.camel.component.salesforce.dto.QueryRecordsLine_Item__c");
+
+                from("direct:queryXml")
+                    .to("salesforce:query?format=xml&sObjectQuery=SELECT name from Line_Item__c&sObjectClass=org.apache.camel.component.salesforce.dto.QueryRecordsLine_Item__c");
+
+                // testSearch
+                from("direct:search")
+                    .to("salesforce:search?sObjectSearch=FIND {Wee}");
+
+                from("direct:searchXml")
+                    .to("salesforce:search?format=xml&sObjectSearch=FIND {Wee}");
+            }
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/StreamingApiIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/StreamingApiIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/StreamingApiIntegrationTest.java
new file mode 100644
index 0000000..d72ca2b
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/StreamingApiIntegrationTest.java
@@ -0,0 +1,109 @@
+/**
+ * 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 org.apache.camel.Message;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.component.salesforce.api.dto.CreateSObjectResult;
+import org.apache.camel.component.salesforce.dto.Merchandise__c;
+import org.apache.camel.component.salesforce.internal.dto.QueryRecordsPushTopic;
+import org.joda.time.DateTime;
+import org.junit.Test;
+
+public class StreamingApiIntegrationTest extends AbstractSalesforceTestBase {
+
+    @Test
+    public void testSubscribeAndReceive() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:CamelTestTopic");
+        mock.expectedMessageCount(1);
+        // assert expected static headers
+        mock.expectedHeaderReceived("CamelSalesforceTopicName", "CamelTestTopic");
+        mock.expectedHeaderReceived("CamelSalesforceChannel", "/topic/CamelTestTopic");
+
+        Merchandise__c merchandise = new Merchandise__c();
+        merchandise.setName("TestNotification");
+        merchandise.setDescription__c("Merchandise for testing Streaming API updated on " +
+            new DateTime().toString());
+        merchandise.setPrice__c(9.99);
+        merchandise.setTotal_Inventory__c(1000.0);
+        CreateSObjectResult result = template().requestBody(
+            "direct:upsertSObject", merchandise, CreateSObjectResult.class);
+        assertTrue("Merchandise test record not created",  result == null || result.getSuccess());
+
+        try {
+            // wait for Salesforce notification
+            mock.assertIsSatisfied();
+            final Message in = mock.getExchanges().get(0).getIn();
+            merchandise = in.getMandatoryBody(Merchandise__c.class);
+            assertNotNull("Missing event body", merchandise);
+            log.info("Merchandise notification: {}", merchandise.toString());
+            assertNotNull("Missing field Id", merchandise.getId());
+            assertNotNull("Missing field Name", merchandise.getName());
+
+            // validate dynamic message headers
+            assertNotNull("Missing header CamelSalesforceClientId", in.getHeader("CamelSalesforceClientId"));
+
+        } finally {
+            // remove the test record
+            assertNull(template().requestBody("direct:deleteSObjectWithId", merchandise));
+
+            // remove the test topic
+            // find it using SOQL first
+            QueryRecordsPushTopic records = template().requestBody("direct:query", null,
+                QueryRecordsPushTopic.class);
+            assertEquals("Test topic not found", 1, records.getTotalSize());
+            assertNull(template().requestBody("direct:deleteSObject",
+                records.getRecords().get(0)));
+
+        }
+    }
+
+    @Override
+    protected RouteBuilder doCreateRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+
+                // test topic subscription
+                from("salesforce:CamelTestTopic?notifyForFields=ALL&notifyForOperations=ALL&" +
+//                    "sObjectClass=org.apache.camel.component.salesforce.dto.Merchandise__c&" +
+                    "sObjectName=Merchandise__c&" +
+                    "updateTopic=true&sObjectQuery=SELECT Id, Name FROM Merchandise__c").
+                    to("mock:CamelTestTopic");
+
+                // route for creating test record
+                from("direct:upsertSObject").
+                    to("salesforce:upsertSObject?SObjectIdName=Name");
+
+                // route for finding test topic
+                from("direct:query").
+                    to("salesforce:query?sObjectQuery=SELECT Id FROM PushTopic WHERE Name = 'CamelTestTopic'&" +
+                        "sObjectClass=org.apache.camel.component.salesforce.internal.dto.QueryRecordsPushTopic");
+
+                // route for removing test record
+                from("direct:deleteSObjectWithId").
+                    to("salesforce:deleteSObjectWithId?sObjectIdName=Name");
+
+                // route for removing topic
+                from("direct:deleteSObject").
+                    to("salesforce:deleteSObject");
+
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/Document.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/Document.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/Document.java
new file mode 100644
index 0000000..090f2b1
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/Document.java
@@ -0,0 +1,201 @@
+/*
+ * Salesforce DTO generated by camel-salesforce-maven-plugin
+ * Generated on: Tue May 14 21:15:54 PDT 2013
+ */
+package org.apache.camel.component.salesforce.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase;
+
+/**
+ * Salesforce DTO for SObject Document
+ */
+@XStreamAlias("Document")
+public class Document extends AbstractSObjectBase {
+
+    // FolderId
+    private String FolderId;
+
+    @JsonProperty("FolderId")
+    public String getFolderId() {
+        return this.FolderId;
+    }
+
+    @JsonProperty("FolderId")
+    public void setFolderId(String FolderId) {
+        this.FolderId = FolderId;
+    }
+
+    // DeveloperName
+    private String DeveloperName;
+
+    @JsonProperty("DeveloperName")
+    public String getDeveloperName() {
+        return this.DeveloperName;
+    }
+
+    @JsonProperty("DeveloperName")
+    public void setDeveloperName(String DeveloperName) {
+        this.DeveloperName = DeveloperName;
+    }
+
+    // NamespacePrefix
+    private String NamespacePrefix;
+
+    @JsonProperty("NamespacePrefix")
+    public String getNamespacePrefix() {
+        return this.NamespacePrefix;
+    }
+
+    @JsonProperty("NamespacePrefix")
+    public void setNamespacePrefix(String NamespacePrefix) {
+        this.NamespacePrefix = NamespacePrefix;
+    }
+
+    // ContentType
+    private String ContentType;
+
+    @JsonProperty("ContentType")
+    public String getContentType() {
+        return this.ContentType;
+    }
+
+    @JsonProperty("ContentType")
+    public void setContentType(String ContentType) {
+        this.ContentType = ContentType;
+    }
+
+    // Type
+    private String Type;
+
+    @JsonProperty("Type")
+    public String getType() {
+        return this.Type;
+    }
+
+    @JsonProperty("Type")
+    public void setType(String Type) {
+        this.Type = Type;
+    }
+
+    // IsPublic
+    private Boolean IsPublic;
+
+    @JsonProperty("IsPublic")
+    public Boolean getIsPublic() {
+        return this.IsPublic;
+    }
+
+    @JsonProperty("IsPublic")
+    public void setIsPublic(Boolean IsPublic) {
+        this.IsPublic = IsPublic;
+    }
+
+    // BodyLength
+    private Integer BodyLength;
+
+    @JsonProperty("BodyLength")
+    public Integer getBodyLength() {
+        return this.BodyLength;
+    }
+
+    @JsonProperty("BodyLength")
+    public void setBodyLength(Integer BodyLength) {
+        this.BodyLength = BodyLength;
+    }
+
+    // Body
+    // blob field url, use getBlobField to get the content
+    @XStreamAlias("Body")
+    private String BodyUrl;
+
+    @JsonProperty("Body")
+    public String getBodyUrl() {
+        return this.BodyUrl;
+    }
+
+    @JsonProperty("Body")
+    public void setBodyUrl(String BodyUrl) {
+        this.BodyUrl = BodyUrl;
+    }
+
+    // Url
+    private String Url;
+
+    @JsonProperty("Url")
+    public String getUrl() {
+        return this.Url;
+    }
+
+    @JsonProperty("Url")
+    public void setUrl(String Url) {
+        this.Url = Url;
+    }
+
+    // Description
+    private String Description;
+
+    @JsonProperty("Description")
+    public String getDescription() {
+        return this.Description;
+    }
+
+    @JsonProperty("Description")
+    public void setDescription(String Description) {
+        this.Description = Description;
+    }
+
+    // Keywords
+    private String Keywords;
+
+    @JsonProperty("Keywords")
+    public String getKeywords() {
+        return this.Keywords;
+    }
+
+    @JsonProperty("Keywords")
+    public void setKeywords(String Keywords) {
+        this.Keywords = Keywords;
+    }
+
+    // IsInternalUseOnly
+    private Boolean IsInternalUseOnly;
+
+    @JsonProperty("IsInternalUseOnly")
+    public Boolean getIsInternalUseOnly() {
+        return this.IsInternalUseOnly;
+    }
+
+    @JsonProperty("IsInternalUseOnly")
+    public void setIsInternalUseOnly(Boolean IsInternalUseOnly) {
+        this.IsInternalUseOnly = IsInternalUseOnly;
+    }
+
+    // AuthorId
+    private String AuthorId;
+
+    @JsonProperty("AuthorId")
+    public String getAuthorId() {
+        return this.AuthorId;
+    }
+
+    @JsonProperty("AuthorId")
+    public void setAuthorId(String AuthorId) {
+        this.AuthorId = AuthorId;
+    }
+
+    // IsBodySearchable
+    private Boolean IsBodySearchable;
+
+    @JsonProperty("IsBodySearchable")
+    public Boolean getIsBodySearchable() {
+        return this.IsBodySearchable;
+    }
+
+    @JsonProperty("IsBodySearchable")
+    public void setIsBodySearchable(Boolean IsBodySearchable) {
+        this.IsBodySearchable = IsBodySearchable;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/Line_Item__c.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/Line_Item__c.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/Line_Item__c.java
new file mode 100644
index 0000000..1bf3668
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/Line_Item__c.java
@@ -0,0 +1,74 @@
+/**
+ * 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.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase;
+
+@XStreamAlias("Line_Item__c")
+public class Line_Item__c extends AbstractSObjectBase {
+
+    private Double Unit_Price__c;
+
+    private Double Units_Sold__c;
+
+    private String Merchandise__c;
+
+    private String Invoice_Statement__c;
+
+    @JsonProperty("Unit_Price__c")
+    public Double getUnit_Price__c() {
+        return Unit_Price__c;
+    }
+
+    @JsonProperty("Unit_Price__c")
+    public void setUnit_Price__c(Double unit_Price__c) {
+        Unit_Price__c = unit_Price__c;
+    }
+
+    @JsonProperty("Units_Sold__c")
+    public Double getUnits_Sold__c() {
+        return Units_Sold__c;
+    }
+
+    @JsonProperty("Units_Sold__c")
+    public void setUnits_Sold__c(Double units_Sold__c) {
+        Units_Sold__c = units_Sold__c;
+    }
+
+    @JsonProperty("Merchandise__c")
+    public String getMerchandise__c() {
+        return Merchandise__c;
+    }
+
+    @JsonProperty("Merchandise__c")
+    public void setMerchandise__c(String merchandise__c) {
+        Merchandise__c = merchandise__c;
+    }
+
+    @JsonProperty("Invoice_Statement__c")
+    public String getInvoice_Statement__c() {
+        return Invoice_Statement__c;
+    }
+
+    @JsonProperty("Invoice_Statement__c")
+    public void setInvoice_Statement__c(String invoice_Statement__c) {
+        Invoice_Statement__c = invoice_Statement__c;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/Merchandise__c.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/Merchandise__c.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/Merchandise__c.java
new file mode 100644
index 0000000..3e3d36a
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/Merchandise__c.java
@@ -0,0 +1,61 @@
+/**
+ * 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.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase;
+
+@XStreamAlias("Merchandise__c")
+public class Merchandise__c extends AbstractSObjectBase {
+
+    private String Description__c;
+
+    private Double Price__c;
+
+    private Double Total_Inventory__c;
+
+    @JsonProperty("Description__c")
+    public String getDescription__c() {
+        return Description__c;
+    }
+
+    @JsonProperty("Description__c")
+    public void setDescription__c(String description__c) {
+        Description__c = description__c;
+    }
+
+    @JsonProperty("Price__c")
+    public Double getPrice__c() {
+        return Price__c;
+    }
+
+    @JsonProperty("Price__c")
+    public void setPrice__c(Double price__c) {
+        Price__c = price__c;
+    }
+
+    @JsonProperty("Total_Inventory__c")
+    public Double getTotal_Inventory__c() {
+        return Total_Inventory__c;
+    }
+
+    @JsonProperty("Total_Inventory__c")
+    public void setTotal_Inventory__c(Double total_Inventory__c) {
+        Total_Inventory__c = total_Inventory__c;
+    }
+}


[07/23] camel git commit: Added Salesforce component

Posted by dh...@apache.org.
Added Salesforce component


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

Branch: refs/heads/trunk
Commit: 72a1767eb44fbb03fc29691e80509f21e6e65233
Parents: b0ccd94
Author: Dhiraj Bokde <db...@fusesource.com>
Authored: Wed Jun 5 00:51:21 2013 -0700
Committer: Dhiraj Bokde <db...@fusesource.com>
Committed: Wed Jun 5 02:04:16 2013 -0700

----------------------------------------------------------------------
 .gitignore                                      |   1 +
 .../camel-salesforce-component/.gitignore       |   6 +
 .../camel-salesforce-component/README.md        |  68 ++
 .../camel-salesforce-component/pom.xml          | 121 ++++
 .../salesforce/SalesforceComponent.java         | 233 +++++++
 .../salesforce/SalesforceConsumer.java          | 215 ++++++
 .../salesforce/SalesforceEndpoint.java          |  96 +++
 .../salesforce/SalesforceEndpointConfig.java    | 276 ++++++++
 .../salesforce/SalesforceLoginConfig.java       |  99 +++
 .../salesforce/SalesforceProducer.java          | 102 +++
 .../salesforce/api/JodaTimeConverter.java       |  64 ++
 .../salesforce/api/PicklistEnumConverter.java   |  80 +++
 .../salesforce/api/SalesforceException.java     | 104 +++
 .../salesforce/api/dto/AbstractDTOBase.java     |  40 ++
 .../api/dto/AbstractQueryRecordsBase.java       |  72 ++
 .../salesforce/api/dto/AbstractSObjectBase.java | 172 +++++
 .../salesforce/api/dto/Attributes.java          |  38 ++
 .../salesforce/api/dto/ChildRelationShip.java   |  74 ++
 .../salesforce/api/dto/CreateSObjectResult.java |  57 ++
 .../salesforce/api/dto/GlobalObjects.java       |  57 ++
 .../salesforce/api/dto/PickListValue.java       |  70 ++
 .../salesforce/api/dto/RecentItem.java          |  56 ++
 .../salesforce/api/dto/RecordTypeInfo.java      |  56 ++
 .../component/salesforce/api/dto/RestError.java |  68 ++
 .../salesforce/api/dto/RestResources.java       | 100 +++
 .../component/salesforce/api/dto/SObject.java   | 237 +++++++
 .../salesforce/api/dto/SObjectBasicInfo.java    |  46 ++
 .../salesforce/api/dto/SObjectDescription.java  |  67 ++
 .../api/dto/SObjectDescriptionUrls.java         |  47 ++
 .../salesforce/api/dto/SObjectField.java        | 414 ++++++++++++
 .../salesforce/api/dto/SObjectUrls.java         |  56 ++
 .../salesforce/api/dto/SearchResult.java        |  49 ++
 .../salesforce/api/dto/SearchResults.java       |  41 ++
 .../component/salesforce/api/dto/Version.java   |  52 ++
 .../component/salesforce/api/dto/Versions.java  |  40 ++
 .../salesforce/api/dto/bulk/BatchInfo.java      | 342 ++++++++++
 .../salesforce/api/dto/bulk/BatchInfoList.java  |  82 +++
 .../salesforce/api/dto/bulk/BatchResult.java    |  82 +++
 .../salesforce/api/dto/bulk/BatchStateEnum.java |  75 +++
 .../api/dto/bulk/ConcurrencyModeEnum.java       |  66 ++
 .../salesforce/api/dto/bulk/ContentType.java    |  57 ++
 .../salesforce/api/dto/bulk/Error.java          | 105 +++
 .../salesforce/api/dto/bulk/JobInfo.java        | 673 +++++++++++++++++++
 .../salesforce/api/dto/bulk/JobStateEnum.java   |  72 ++
 .../salesforce/api/dto/bulk/ObjectFactory.java  | 200 ++++++
 .../salesforce/api/dto/bulk/OperationEnum.java  |  78 +++
 .../salesforce/api/dto/bulk/QueryResult.java    |  84 +++
 .../api/dto/bulk/QueryResultList.java           |  82 +++
 .../salesforce/api/dto/bulk/Result.java         | 147 ++++
 .../salesforce/api/dto/bulk/ResultError.java    | 140 ++++
 .../salesforce/api/dto/bulk/SObject.java        | 138 ++++
 .../salesforce/api/dto/bulk/StatusCode.java     | 395 +++++++++++
 .../salesforce/api/dto/bulk/package-info.java   |  18 +
 .../salesforce/internal/OperationName.java      |  71 ++
 .../salesforce/internal/PayloadFormat.java      |  22 +
 .../salesforce/internal/SalesforceSession.java  | 336 +++++++++
 .../internal/client/AbstractClientBase.java     | 196 ++++++
 .../internal/client/BulkApiClient.java          |  92 +++
 .../internal/client/DefaultBulkApiClient.java   | 481 +++++++++++++
 .../internal/client/DefaultRestClient.java      | 364 ++++++++++
 .../salesforce/internal/client/RestClient.java  | 177 +++++
 .../internal/client/SalesforceExchange.java     |  36 +
 .../client/SalesforceSecurityListener.java      | 162 +++++
 .../internal/client/SyncResponseCallback.java   |  57 ++
 .../salesforce/internal/dto/LoginError.java     |  47 ++
 .../salesforce/internal/dto/LoginToken.java     |  81 +++
 .../internal/dto/NotifyForFieldsEnum.java       |  53 ++
 .../internal/dto/NotifyForOperationsEnum.java   |  52 ++
 .../salesforce/internal/dto/PushTopic.java      | 100 +++
 .../internal/dto/QueryRecordsPushTopic.java     |  38 ++
 .../salesforce/internal/dto/RestErrors.java     |  41 ++
 .../processor/AbstractRestProcessor.java        | 538 +++++++++++++++
 .../processor/AbstractSalesforceProcessor.java  |  84 +++
 .../internal/processor/BulkApiProcessor.java    | 377 +++++++++++
 .../internal/processor/JsonRestProcessor.java   | 180 +++++
 .../internal/processor/SalesforceProcessor.java |  27 +
 .../internal/processor/XmlRestProcessor.java    | 240 +++++++
 .../internal/streaming/PushTopicHelper.java     | 206 ++++++
 .../internal/streaming/SubscriptionHelper.java  | 372 ++++++++++
 .../org/apache/camel/component/salesforce       |   1 +
 .../salesforce/AbstractBulkApiTestBase.java     | 105 +++
 .../salesforce/AbstractSalesforceTestBase.java  |  60 ++
 .../salesforce/BulkApiBatchIntegrationTest.java | 109 +++
 .../salesforce/BulkApiJobIntegrationTest.java   | 111 +++
 .../salesforce/BulkApiQueryIntegrationTest.java |  85 +++
 .../component/salesforce/LoginConfigHelper.java |  43 ++
 .../salesforce/RestApiIntegrationTest.java      | 408 +++++++++++
 .../salesforce/StreamingApiIntegrationTest.java | 109 +++
 .../component/salesforce/dto/Document.java      | 201 ++++++
 .../component/salesforce/dto/Line_Item__c.java  |  74 ++
 .../salesforce/dto/Merchandise__c.java          |  61 ++
 .../dto/QueryRecordsLine_Item__c.java           |  35 +
 .../internal/SessionIntegrationTest.java        |  63 ++
 .../src/test/resources/log4j.properties         |  18 +
 .../src/test/resources/test-request.csv         |   3 +
 .../src/test/resources/test-request.xml         |  15 +
 .../camel-salesforce-maven-plugin/.gitignore    |   5 +
 .../camel-salesforce-maven-plugin/README.md     |  26 +
 .../camel-salesforce-maven-plugin/pom.xml       |  78 +++
 .../apache/camel/maven/CamelSalesforceMojo.java | 569 ++++++++++++++++
 .../src/main/resources/sobject-picklist.vm      |  52 ++
 .../src/main/resources/sobject-pojo.vm          |  60 ++
 .../src/main/resources/sobject-query-records.vm |  29 +
 .../CamelSalesforceMojoIntegrationTest.java     |  85 +++
 .../src/test/resources/log4j.properties         |  19 +
 components/camel-salesforce/pom.xml             |  38 ++
 components/pom.xml                              |   1 +
 parent/pom.xml                                  |   6 +
 .../features/src/main/resources/features.xml    |  16 +
 109 files changed, 13125 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 394c174..b74e107 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,4 +9,5 @@ target
 .settings
 .checkstyle
 *.log
+test-salesforce-login.properties
 dependency-reduced-pom.xml

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/.gitignore
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/.gitignore b/components/camel-salesforce/camel-salesforce-component/.gitignore
new file mode 100644
index 0000000..acf55cc
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/.gitignore
@@ -0,0 +1,6 @@
+target
+*.ipr
+*.iml
+*.iws
+# Salesforce login properties
+*test-login.properties*

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/README.md
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/README.md b/components/camel-salesforce/camel-salesforce-component/README.md
new file mode 100644
index 0000000..9bf9845
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/README.md
@@ -0,0 +1,68 @@
+# Camel Salesforce component #
+
+This component supports producer and consumer endpoints to communicate with Salesforce using Java DTOs. 
+There is a companion maven plugin [camel-salesforce-plugin](https://github.com/dhirajsb/camel-salesforce-maven-plugin) that generates these DTOs. 
+
+The component supports the following Salesforce APIs
+
+## REST API ##
+
+Producer endpoints can use the following APIs. Most of the APIs process one record at a time, the Query API can retrieve multiple Records. 
+
+* getVersions - Gets supported Salesforce REST API versions
+* getResources - Gets available Salesforce REST Resource endpoints
+* getGlobalObjects - Gets metadata for all available SObject types
+* getBasicInfo - Gets basic metadata for a specific SObject type
+* getDescription - Gets comprehensive metadata for a specific SObject type
+* getSObject - Gets an SObject using its Salesforce Id
+* createSObject - Creates an SObject
+* updateSObject - Updates an SObject using Id
+* deleteSObject - Deletes an SObject using Id
+* getSObjectWithId - Gets an SObject using an external (user defined) id field
+* upsertSObject - Updates or inserts an SObject using an external id
+* deleteSObjectWithId - Deletes an SObject using an external id
+* query - Runs a Salesforce SOQL query
+* queryMore - Retrieves more results (in case of large number of results) using result link returned from the 'query' API
+* search - Runs a Salesforce SOSL query
+
+For example, the following producer endpoint uses the upsertSObject API, with the sObjectIdName parameter specifying 'Name' as the external id field. 
+The request message body should be an SObject DTO generated using the maven plugin. 
+The response message will either be NULL if an existing record was updated, or [CreateSObjectResult] with an id of the new record, or a list of errors while creating the new object.
+
+	...to("force:upsertSObject?sObjectIdName=Name")...
+
+## Bulk API ##
+
+Producer endpoints can use the following APIs. All Job data formats, i.e. xml, csv, zip/xml, and zip/csv are supported. 
+The request and response have to be marshalled/unmarshalled by the route. Usually the request will be some stream source like a CSV file, 
+and the response may also be saved to a file to be correlated with the request. 
+
+* createJob - Creates a Salesforce Bulk Job
+* getJob - Gets a Job using its Salesforce Id
+* closeJob - Closes a Job
+* abortJob - Aborts a Job
+* createBatch - Submits a Batch within a Bulk Job
+* getBatch - Gets a Batch using Id
+* getAllBatches - Gets all Batches for a Bulk Job Id
+* getRequest - Gets Request data (XML/CSV) for a Batch
+* getResults - Gets the results of the Batch when its complete
+* createBatchQuery - Creates a Batch from an SOQL query
+* getQueryResultIds - Gets a list of Result Ids for a Batch Query
+* getQueryResult - Gets results for a Result Id
+
+For example, the following producer endpoint uses the createBatch API to create a Job Batch. 
+The in message must contain a body that can be converted into an InputStream (usually UTF-8 CSV or XML content from a file, etc.) and header fields 'jobId' for the Job and 'contentType' for the Job content type, which can be XML, CSV, ZIP\_XML or ZIP\_CSV. The put message body will contain [BatchInfo] on success, or throw a [SalesforceException] on error.
+
+	...to("force:createBatchJob")..
+
+## Streaming API ##
+
+Consumer endpoints can use the following sytax for streaming endpoints to receive Salesforce notifications on create/update. 
+
+To create and subscribe to a topic
+
+	from("force:CamelTestTopic?notifyForFields=ALL&notifyForOperations=ALL&sObjectName=Merchandise__c&updateTopic=true&sObjectQuery=SELECT Id, Name FROM Merchandise__c")...
+
+To subscribe to an existing topic
+
+	from("force:CamelTestTopic&sObjectName=Merchandise__c")...

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/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
new file mode 100644
index 0000000..3a811f5
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/pom.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<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>camel-salesforce</artifactId>
+    <version>2.12-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>camel-salesforce-component</artifactId>
+  <packaging>bundle</packaging>
+  <name>Camel :: Salesforce component</name>
+  <description>Camel Salesforce support</description>
+
+  <properties>
+    <camel.osgi.export.pkg/>
+    <camel.osgi.export>
+      org.apache.camel.component.salesforce;version=${project.version},
+      org.apache.camel.component.salesforce.api.*;version=${project.version}
+    </camel.osgi.export>
+    <camel.osgi.private.pkg>org.apache.camel.component.salesforce.internal.*</camel.osgi.private.pkg>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-client</artifactId>
+      <version>${jetty-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-util</artifactId>
+      <version>${jetty-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-io</artifactId>
+      <version>${jetty-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.jackson</groupId>
+      <artifactId>jackson-mapper-asl</artifactId>
+      <version>${jackson-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.thoughtworks.xstream</groupId>
+      <artifactId>xstream</artifactId>
+      <version>${xstream-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.cometd.java</groupId>
+      <artifactId>cometd-java-client</artifactId>
+      <version>${cometd-java-client-version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-util</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-io</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>joda-time</groupId>
+      <artifactId>joda-time</artifactId>
+      <version>${jodatime2-bundle-version}</version>
+    </dependency>
+    <!-- logging -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <version>${slf4j-api-version}</version>
+    </dependency>
+
+    <!-- testing -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <version>${slf4j-api-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <version>${log4j-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/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
new file mode 100644
index 0000000..a48502a
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java
@@ -0,0 +1,233 @@
+/**
+ * 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 org.apache.camel.Endpoint;
+import org.apache.camel.impl.DefaultComponent;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.ServiceHelper;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.RedirectListener;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase;
+import org.apache.camel.component.salesforce.internal.OperationName;
+import org.apache.camel.component.salesforce.internal.SalesforceSession;
+import org.apache.camel.component.salesforce.internal.streaming.SubscriptionHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Represents the component that manages {@link SalesforceEndpoint}.
+ */
+public class SalesforceComponent extends DefaultComponent {
+
+    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 SalesforceLoginConfig loginConfig;
+    private SalesforceEndpointConfig config;
+    private String[] packages;
+
+    // component state
+    private HttpClient httpClient;
+    private SalesforceSession session;
+    private Map<String, Class<?>> classMap;
+
+    // Lazily created helper for consumer endpoints
+    private SubscriptionHelper subscriptionHelper;
+
+    protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+        // get Operation from remaining URI
+        OperationName operationName = null;
+        String topicName = null;
+        try {
+            LOG.debug("Creating endpoint for ", remaining);
+            operationName = OperationName.fromValue(remaining);
+        } catch (IllegalArgumentException ex) {
+            // if its not an operation name, treat is as topic name for consumer endpoints
+            topicName = remaining;
+        }
+
+        // create endpoint config
+        if (config == null) {
+            config = new SalesforceEndpointConfig();
+        }
+        if (config.getHttpClient() == null) {
+            // set the component's httpClient as default
+            config.setHttpClient(httpClient);
+        }
+
+        // create a deep copy and map parameters
+        final SalesforceEndpointConfig copy = config.copy();
+        setProperties(copy, parameters);
+
+        final SalesforceEndpoint endpoint = new SalesforceEndpoint(uri, this, copy,
+            operationName, topicName);
+
+        // map remaining parameters to endpoint (specifically, synchronous)
+        setProperties(endpoint, parameters);
+
+        return endpoint;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+
+        // validate properties
+        ObjectHelper.notNull(loginConfig, "loginConfig");
+
+        // create a Jetty HttpClient if not already set
+        if (null == httpClient) {
+            if (config != null && config.getHttpClient() != null) {
+                httpClient = config.getHttpClient();
+            } else {
+                httpClient = new HttpClient();
+                httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
+                httpClient.setMaxConnectionsPerAddress(MAX_CONNECTIONS_PER_ADDRESS);
+                httpClient.setConnectTimeout(CONNECTION_TIMEOUT);
+                httpClient.setTimeout(RESPONSE_TIMEOUT);
+            }
+        }
+
+        // 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);
+        }
+        // SalesforceSecurityListener can't be registered the same way
+        // since Jetty HttpClient's Class.forName() can't see it
+
+        // start the Jetty client to initialize thread pool, etc.
+        httpClient.start();
+
+        // support restarts
+        if (null == this.session) {
+            this.session = new SalesforceSession(httpClient, loginConfig);
+        }
+
+        // login at startup if lazyLogin is disabled
+        if (!loginConfig.isLazyLogin()) {
+            ServiceHelper.startService(session);
+        }
+
+        if (packages != null && packages.length > 0) {
+            // parse the packages to create SObject name to class map
+            classMap = parsePackages();
+        } else {
+            // use an empty map to avoid NPEs later
+            LOG.warn("Missing property packages, getSObject* operations will NOT work");
+            classMap = Collections.unmodifiableMap(new HashMap<String, Class<?>>());
+        }
+
+        if (subscriptionHelper != null) {
+            ServiceHelper.startService(subscriptionHelper);
+        }
+    }
+
+    private Map<String, Class<?>> parsePackages() {
+        Map<String, Class<?>> result = new HashMap<String, Class<?>>();
+        Set<Class<?>> classes = getCamelContext().getPackageScanClassResolver().findImplementations(AbstractSObjectBase.class, packages);
+        for (Class<?> aClass : classes) {
+            // findImplementations also returns AbstractSObjectBase for some reason!!!
+            if (AbstractSObjectBase.class != aClass) {
+                result.put(aClass.getSimpleName(), aClass);
+            }
+        }
+
+        return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        super.doStop();
+
+        try {
+            if (subscriptionHelper != null) {
+                // shutdown all streaming connections
+                // note that this is done in the component, and not in consumer
+                ServiceHelper.stopService(subscriptionHelper);
+            }
+            if (session != null && session.getAccessToken() != null) {
+                try {
+                    // logout of Salesforce
+                    ServiceHelper.stopService(session);
+                } catch (SalesforceException ignored) {
+                }
+            }
+        } finally {
+            if (httpClient != null) {
+                // shutdown http client connections
+                httpClient.stop();
+            }
+        }
+    }
+
+    public SubscriptionHelper getSubscriptionHelper() throws Exception {
+        if (subscriptionHelper == null) {
+            // lazily create subscription helper
+            subscriptionHelper = new SubscriptionHelper(this);
+
+            // also start the helper to connect to Salesforce
+            ServiceHelper.startService(subscriptionHelper);
+        }
+        return subscriptionHelper;
+    }
+
+    public SalesforceLoginConfig getLoginConfig() {
+        return loginConfig;
+    }
+
+    public void setLoginConfig(SalesforceLoginConfig loginConfig) {
+        this.loginConfig = loginConfig;
+    }
+
+    public SalesforceEndpointConfig getConfig() {
+        return config;
+    }
+
+    public void setConfig(SalesforceEndpointConfig config) {
+        this.config = config;
+    }
+
+    public String[] getPackages() {
+        return packages;
+    }
+
+    public void setPackages(String[] packages) {
+        this.packages = packages;
+    }
+
+    public SalesforceSession getSession() {
+        return session;
+    }
+
+    public Map<String, Class<?>> getClassMap() {
+        return classMap;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceConsumer.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceConsumer.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceConsumer.java
new file mode 100644
index 0000000..9fa1b91
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceConsumer.java
@@ -0,0 +1,215 @@
+/**
+ * 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 org.apache.camel.AsyncCallback;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.impl.DefaultConsumer;
+import org.apache.camel.util.ServiceHelper;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.cometd.bayeux.Message;
+import org.cometd.bayeux.client.ClientSessionChannel;
+import org.apache.camel.component.salesforce.internal.client.DefaultRestClient;
+import org.apache.camel.component.salesforce.internal.streaming.PushTopicHelper;
+import org.apache.camel.component.salesforce.internal.client.RestClient;
+import org.apache.camel.component.salesforce.internal.streaming.SubscriptionHelper;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The Salesforce consumer.
+ */
+public class SalesforceConsumer extends DefaultConsumer {
+
+    private static final ObjectMapper objectMapper = new ObjectMapper();
+    private static final String EVENT_PROPERTY = "event";
+    private static final String TYPE_PROPERTY = "type";
+    private static final String CREATED_DATE_PROPERTY = "createdDate";
+    private static final String SOBJECT_PROPERTY = "sobject";
+    private static final double MINIMUM_VERSION = 24.0;
+
+    private final SalesforceEndpoint endpoint;
+    public final SubscriptionHelper subscriptionHelper;
+
+    private final String topicName;
+    private final Class<?> sObjectClass;
+    private boolean subscribed;
+
+    public SalesforceConsumer(SalesforceEndpoint endpoint, Processor processor, SubscriptionHelper helper) {
+        super(endpoint, processor);
+        this.endpoint = endpoint;
+
+        // check minimum supported API version
+        if (Double.valueOf(endpoint.getConfiguration().getApiVersion()) < MINIMUM_VERSION) {
+            throw new IllegalArgumentException("Minimum supported API version for consumer endpoints is " + 24.0);
+        }
+
+        this.topicName = endpoint.getTopicName();
+        this.subscriptionHelper = helper;
+
+        // get sObjectClass to convert to
+        final String sObjectName = endpoint.getConfiguration().getSObjectName();
+        if (sObjectName != null) {
+            sObjectClass = endpoint.getComponent().getClassMap().get(sObjectName);
+            if (sObjectClass == null) {
+                throw new IllegalArgumentException(String.format("SObject Class not found for %s", sObjectName));
+            }
+        } else {
+            final String className = endpoint.getConfiguration().getSObjectClass();
+            if (className != null) {
+                sObjectClass = endpoint.getComponent().getCamelContext().getClassResolver().resolveClass(className);
+                if (sObjectClass == null) {
+                    throw new IllegalArgumentException(String.format("SObject Class not found %s", className));
+                }
+            } else {
+                log.warn("Property sObjectName or sObjectClass NOT set, messages will be of type java.lang.Map");
+                sObjectClass = null;
+            }
+        }
+
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+
+        final SalesforceEndpointConfig config = endpoint.getConfiguration();
+
+        // is a query configured in the endpoint?
+        if (config.getSObjectQuery() != null) {
+            // Note that we don't lookup topic if the query is not specified
+            // create REST client for PushTopic operations
+            SalesforceComponent component = endpoint.getComponent();
+            RestClient restClient = new DefaultRestClient(component.getConfig().getHttpClient(),
+                endpoint.getConfiguration().getApiVersion(), "json", component.getSession());
+            // don't forget to start the client
+            ServiceHelper.startService(restClient);
+
+            try {
+                PushTopicHelper helper = new PushTopicHelper(config, topicName, restClient);
+                helper.createOrUpdateTopic();
+            } finally {
+                // don't forget to stop the client
+                ServiceHelper.stopService(restClient);
+            }
+        }
+
+        // subscribe to topic
+        subscriptionHelper.subscribe(topicName, this);
+        subscribed = true;
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        super.doStop();
+
+        if (subscribed) {
+            subscribed = false;
+            // unsubscribe from topic
+            subscriptionHelper.unsubscribe(topicName, this);
+        }
+    }
+
+    public void processMessage(ClientSessionChannel channel, Message message) {
+        final Exchange exchange = endpoint.createExchange();
+        org.apache.camel.Message in = exchange.getIn();
+        setHeaders(in, message);
+
+        // get event data
+        // TODO do we need to add NPE checks for message/data.get***???
+        Map<String, Object> data = message.getDataAsMap();
+
+        @SuppressWarnings("unchecked") final
+        Map<String, Object> event = (Map<String, Object>) data.get(EVENT_PROPERTY);
+        final Object eventType = event.get(TYPE_PROPERTY);
+        Object createdDate = event.get(CREATED_DATE_PROPERTY);
+        if (log.isDebugEnabled()) {
+            log.debug(String.format("Received event %s on channel %s created on %s",
+                eventType, channel.getChannelId(), createdDate));
+        }
+
+        in.setHeader("CamelSalesforceEventType", eventType);
+        in.setHeader("CamelSalesforceCreatedDate", createdDate);
+
+        // get SObject
+        @SuppressWarnings("unchecked")
+        final Map<String, Object> sObject = (Map<String, Object>) data.get(SOBJECT_PROPERTY);
+        try {
+
+            final String sObjectString = objectMapper.writeValueAsString(sObject);
+            log.debug("Received SObject: {}", sObjectString);
+
+            if (sObjectClass == null) {
+                // return sobject map as exchange body
+                in.setBody(sObject);
+            } else {
+                // create the expected SObject
+                in.setBody(objectMapper.readValue(
+                    new StringReader(sObjectString), sObjectClass));
+            }
+        } catch (IOException e) {
+            final String msg = String.format("Error parsing message [%s] from Topic %s: %s",
+                message, topicName, e.getMessage());
+            handleException(msg, new RuntimeCamelException(msg, e));
+        }
+
+        try {
+            getAsyncProcessor().process(exchange, new AsyncCallback() {
+                public void done(boolean doneSync) {
+                    // noop
+                    if (log.isTraceEnabled()) {
+                        log.trace("Done processing event: {} {}", eventType.toString(),
+                            doneSync ? "synchronously" : "asynchronously");
+                    }
+                }
+            });
+        } catch (Exception e) {
+            handleException(String.format("Error processing %s: %s", exchange, e.getMessage()), e);
+        } finally {
+            Exception ex = exchange.getException();
+            if (ex != null) {
+                handleException(String.format("Unhandled exception: %s", ex.getMessage()), ex);
+            }
+        }
+    }
+
+    private void setHeaders(org.apache.camel.Message in, Message message) {
+        Map<String, Object> headers = new HashMap<String, Object>();
+        // set topic name
+        headers.put("CamelSalesforceTopicName", topicName);
+        // set message properties as headers
+        headers.put("CamelSalesforceChannel", message.getChannel());
+        headers.put("CamelSalesforceClientId", message.getClientId());
+
+        in.setHeaders(headers);
+    }
+
+    @Override
+    public void handleException(String message, Throwable t) {
+        super.handleException(message, t);
+    }
+
+    public String getTopicName() {
+        return topicName;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/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
new file mode 100644
index 0000000..24874bb
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpoint.java
@@ -0,0 +1,96 @@
+/**
+ * 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 org.apache.camel.Consumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.impl.SynchronousDelegateProducer;
+import org.apache.camel.component.salesforce.internal.OperationName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Represents a Salesforce endpoint.
+ */
+public class SalesforceEndpoint extends DefaultEndpoint {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SalesforceEndpoint.class);
+
+    private final SalesforceEndpointConfig config;
+    private final OperationName operationName;
+    private final String topicName;
+
+    public SalesforceEndpoint(String uri, SalesforceComponent salesforceComponent,
+                              SalesforceEndpointConfig config, OperationName operationName, String topicName) {
+        super(uri, salesforceComponent);
+
+        this.config = config;
+        this.operationName = operationName;
+        this.topicName = topicName;
+    }
+
+    public Producer createProducer() throws Exception {
+        // producer requires an operation, topicName must be the invalid operation name
+        if (operationName == null) {
+            throw new IllegalArgumentException(String.format("Invalid Operation %s", topicName));
+        }
+
+        SalesforceProducer producer = new SalesforceProducer(this);
+        if (isSynchronous()) {
+            return new SynchronousDelegateProducer(producer);
+        } else {
+            return producer;
+        }
+    }
+
+    public Consumer createConsumer(Processor processor) throws Exception {
+        // consumer requires a topicName, operation name must be the invalid topic name
+        if (topicName == null) {
+            throw new IllegalArgumentException(String.format("Invalid topic name %s, matches a producer operation name",
+                operationName.value()));
+        }
+
+        return new SalesforceConsumer(this, processor,
+            getComponent().getSubscriptionHelper());
+    }
+
+    @Override
+    public SalesforceComponent getComponent() {
+        return (SalesforceComponent) super.getComponent();
+    }
+
+    public boolean isSingleton() {
+        // re-use endpoint instance across multiple threads
+        // the description of this method is a little confusing
+        return true;
+    }
+
+    public SalesforceEndpointConfig getConfiguration() {
+        return config;
+    }
+
+    public OperationName getOperationName() {
+        return operationName;
+    }
+
+    public String getTopicName() {
+        return topicName;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/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
new file mode 100644
index 0000000..065f2f1
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpointConfig.java
@@ -0,0 +1,276 @@
+package org.apache.camel.component.salesforce;
+
+import org.apache.camel.RuntimeCamelException;
+import org.eclipse.jetty.client.HttpClient;
+import org.apache.camel.component.salesforce.api.dto.bulk.ContentType;
+import org.apache.camel.component.salesforce.api.dto.bulk.OperationEnum;
+import org.apache.camel.component.salesforce.internal.PayloadFormat;
+import org.apache.camel.component.salesforce.internal.dto.NotifyForFieldsEnum;
+import org.apache.camel.component.salesforce.internal.dto.NotifyForOperationsEnum;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public class SalesforceEndpointConfig implements Cloneable {
+
+    // default API version
+    static final String DEFAULT_VERSION = "27.0";
+
+    // general parameter
+    public static final String API_VERSION = "apiVersion";
+
+    // parameters for Rest API
+    public static final String FORMAT = "format";
+    public static final String SOBJECT_NAME = "sObjectName";
+    public static final String SOBJECT_ID = "sObjectId";
+    public static final String SOBJECT_FIELDS = "sObjectFields";
+    public static final String SOBJECT_EXT_ID_NAME = "sObjectIdName";
+    public static final String SOBJECT_EXT_ID_VALUE = "sObjectIdValue";
+    public static final String SOBJECT_BLOB_FIELD_NAME = "sObjectBlobFieldName";
+    public static final String SOBJECT_CLASS = "sObjectClass";
+    public static final String SOBJECT_QUERY = "sObjectQuery";
+    public static final String SOBJECT_SEARCH = "sObjectSearch";
+
+    // parameters for Bulk API
+    public static final String BULK_OPERATION = "bulkOperation";
+    public static final String CONTENT_TYPE = "contentType";
+    public static final String JOB_ID = "jobId";
+    public static final String BATCH_ID = "batchId";
+    public static final String RESULT_ID = "resultId";
+
+    // parameters for Streaming API
+    public static final String UPDATE_TOPIC = "updateTopic";
+
+    // general properties
+    private String apiVersion = DEFAULT_VERSION;
+
+    // Rest API properties
+    private PayloadFormat format = PayloadFormat.JSON;
+    private String sObjectName;
+    private String sObjectId;
+    private String sObjectFields;
+    private String sObjectIdName;
+    private String sObjectIdValue;
+    private String sObjectBlobFieldName;
+    private String sObjectClass;
+    private String sObjectQuery;
+    private String sObjectSearch;
+
+    // Bulk API properties
+    private OperationEnum bulkOperation;
+    private ContentType contentType;
+    private String jobId;
+    private String batchId;
+    private String resultId;
+
+    // Streaming API properties
+    private boolean updateTopic;
+    private NotifyForFieldsEnum notifyForFields;
+    private NotifyForOperationsEnum notifyForOperations;
+
+    // Jetty HttpClient, set using reference
+    private HttpClient httpClient;
+
+    public SalesforceEndpointConfig copy() {
+        try {
+            final SalesforceEndpointConfig copy = (SalesforceEndpointConfig) super.clone();
+            // nothing to deep copy
+            return copy;
+        } catch (CloneNotSupportedException ex) {
+            throw new RuntimeCamelException(ex);
+        }
+    }
+
+    public PayloadFormat getPayloadFormat() {
+        return format;
+    }
+
+    public void setFormat(String format) {
+        this.format = PayloadFormat.valueOf(format.toUpperCase());
+    }
+
+    public String getApiVersion() {
+        return apiVersion;
+    }
+
+    public void setApiVersion(String apiVersion) {
+        this.apiVersion = apiVersion;
+    }
+
+    public String getSObjectName() {
+        return sObjectName;
+    }
+
+    public void setSObjectName(String sObjectName) {
+        this.sObjectName = sObjectName;
+    }
+
+    public String getSObjectId() {
+        return sObjectId;
+    }
+
+    public void setSObjectId(String sObjectId) {
+        this.sObjectId = sObjectId;
+    }
+
+    public String getSObjectFields() {
+        return sObjectFields;
+    }
+
+    public void setSObjectFields(String sObjectFields) {
+        this.sObjectFields = sObjectFields;
+    }
+
+    public String getSObjectIdName() {
+        return sObjectIdName;
+    }
+
+    public void setSObjectIdName(String sObjectIdName) {
+        this.sObjectIdName = sObjectIdName;
+    }
+
+    public String getSObjectIdValue() {
+        return sObjectIdValue;
+    }
+
+    public void setSObjectIdValue(String sObjectIdValue) {
+        this.sObjectIdValue = sObjectIdValue;
+    }
+
+    public String getSObjectBlobFieldName() {
+        return sObjectBlobFieldName;
+    }
+
+    public void setSObjectBlobFieldName(String sObjectBlobFieldName) {
+        this.sObjectBlobFieldName = sObjectBlobFieldName;
+    }
+
+    public String getSObjectClass() {
+        return sObjectClass;
+    }
+
+    public void setSObjectClass(String sObjectClass) {
+        this.sObjectClass = sObjectClass;
+    }
+
+    public String getSObjectQuery() {
+        return sObjectQuery;
+    }
+
+    public void setSObjectQuery(String sObjectQuery) {
+        this.sObjectQuery = sObjectQuery;
+    }
+
+    public String getSObjectSearch() {
+        return sObjectSearch;
+    }
+
+    public void setSObjectSearch(String sObjectSearch) {
+        this.sObjectSearch = sObjectSearch;
+    }
+
+    public OperationEnum getBulkOperation() {
+        return bulkOperation;
+    }
+
+    public void setBulkOperation(OperationEnum bulkOperation) {
+        this.bulkOperation = bulkOperation;
+    }
+
+    public ContentType getContentType() {
+        return contentType;
+    }
+
+    public void setContentType(ContentType contentType) {
+        this.contentType = contentType;
+    }
+
+    public String getJobId() {
+        return jobId;
+    }
+
+    public void setJobId(String jobId) {
+        this.jobId = jobId;
+    }
+
+    public String getBatchId() {
+        return batchId;
+    }
+
+    public void setBatchId(String batchId) {
+        this.batchId = batchId;
+    }
+
+    public String getResultId() {
+        return resultId;
+    }
+
+    public void setResultId(String resultId) {
+        this.resultId = resultId;
+    }
+
+    public boolean isUpdateTopic() {
+        return updateTopic;
+    }
+
+    public void setUpdateTopic(boolean updateTopic) {
+        this.updateTopic = updateTopic;
+    }
+
+    public NotifyForFieldsEnum getNotifyForFields() {
+        return notifyForFields;
+    }
+
+    public void setNotifyForFields(NotifyForFieldsEnum notifyForFields) {
+        this.notifyForFields = notifyForFields;
+    }
+
+    public NotifyForOperationsEnum getNotifyForOperations() {
+        return notifyForOperations;
+    }
+
+    public void setNotifyForOperations(NotifyForOperationsEnum notifyForOperations) {
+        this.notifyForOperations = notifyForOperations;
+    }
+
+    public void setHttpClient(HttpClient httpClient) {
+        this.httpClient = httpClient;
+    }
+
+    public HttpClient getHttpClient() {
+        return httpClient;
+    }
+
+    public Map<String, String> toValueMap() {
+
+        final Map<String, String> valueMap = new HashMap<String, String>();
+        valueMap.put(FORMAT, format.toString().toLowerCase());
+        valueMap.put(API_VERSION, apiVersion);
+
+        valueMap.put(SOBJECT_NAME, sObjectName);
+        valueMap.put(SOBJECT_ID, sObjectId);
+        valueMap.put(SOBJECT_FIELDS, sObjectFields);
+        valueMap.put(SOBJECT_EXT_ID_NAME, sObjectIdName);
+        valueMap.put(SOBJECT_BLOB_FIELD_NAME, sObjectBlobFieldName);
+        valueMap.put(SOBJECT_EXT_ID_VALUE, sObjectIdValue);
+        valueMap.put(SOBJECT_CLASS, sObjectClass);
+        valueMap.put(SOBJECT_QUERY, sObjectQuery);
+        valueMap.put(SOBJECT_SEARCH, sObjectSearch);
+
+        // add bulk API properties
+        if (bulkOperation != null) {
+            valueMap.put(BULK_OPERATION, bulkOperation.value());
+        }
+        if (contentType != null) {
+            valueMap.put(CONTENT_TYPE, contentType.value());
+        }
+        valueMap.put(JOB_ID, jobId);
+        valueMap.put(BATCH_ID, batchId);
+        valueMap.put(RESULT_ID, resultId);
+
+        valueMap.put(UPDATE_TOPIC, String.valueOf(updateTopic));
+
+        return Collections.unmodifiableMap(valueMap);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceLoginConfig.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceLoginConfig.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceLoginConfig.java
new file mode 100644
index 0000000..a6a097f
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceLoginConfig.java
@@ -0,0 +1,99 @@
+/**
+ * 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;
+
+/**
+ * Configuration object for Salesforce login properties
+ */
+public class SalesforceLoginConfig {
+
+    public static final String DEFAULT_LOGIN_URL = "https://login.salesforce.com";
+
+    private String loginUrl;
+    private String clientId;
+    private String clientSecret;
+    private String userName;
+    private String password;
+    // allow lazy login into Salesforce
+    // note that login issues may not surface until a message needs to be processed
+    private boolean lazyLogin;
+
+    public SalesforceLoginConfig() {
+        loginUrl = DEFAULT_LOGIN_URL;
+        lazyLogin = false;
+    }
+
+    public SalesforceLoginConfig(String loginUrl,
+                                 String clientId, String clientSecret,
+                                 String userName, String password, boolean lazyLogin) {
+        this.loginUrl = loginUrl;
+        this.clientId = clientId;
+        this.clientSecret = clientSecret;
+        this.userName = userName;
+        this.password = password;
+        this.lazyLogin = lazyLogin;
+    }
+
+    public String getLoginUrl() {
+        return loginUrl;
+    }
+
+    public void setLoginUrl(String loginUrl) {
+        this.loginUrl = loginUrl;
+    }
+
+    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 String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public boolean isLazyLogin() {
+        return lazyLogin;
+    }
+
+    public void setLazyLogin(boolean lazyLogin) {
+        this.lazyLogin = lazyLogin;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceProducer.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceProducer.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceProducer.java
new file mode 100644
index 0000000..5cc4547
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceProducer.java
@@ -0,0 +1,102 @@
+/**
+ * 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 org.apache.camel.AsyncCallback;
+import org.apache.camel.Exchange;
+import org.apache.camel.impl.DefaultAsyncProducer;
+import org.apache.camel.util.ServiceHelper;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.internal.OperationName;
+import org.apache.camel.component.salesforce.internal.PayloadFormat;
+import org.apache.camel.component.salesforce.internal.processor.BulkApiProcessor;
+import org.apache.camel.component.salesforce.internal.processor.JsonRestProcessor;
+import org.apache.camel.component.salesforce.internal.processor.SalesforceProcessor;
+import org.apache.camel.component.salesforce.internal.processor.XmlRestProcessor;
+
+/**
+ * The Salesforce producer.
+ */
+public class SalesforceProducer extends DefaultAsyncProducer {
+
+    private final SalesforceProcessor processor;
+
+    public SalesforceProducer(SalesforceEndpoint endpoint) throws SalesforceException {
+        super(endpoint);
+
+        final SalesforceEndpointConfig endpointConfig = endpoint.getConfiguration();
+        final PayloadFormat payloadFormat = endpointConfig.getPayloadFormat();
+
+        // check if its a Bulk Operation
+        if (isBulkOperation(endpoint.getOperationName())) {
+            processor = new BulkApiProcessor(endpoint);
+        } else {
+            // create an appropriate processor
+            if (payloadFormat == PayloadFormat.JSON) {
+                // create a JSON exchange processor
+                processor = new JsonRestProcessor(endpoint);
+            } else {
+                processor = new XmlRestProcessor(endpoint);
+            }
+        }
+    }
+
+    private boolean isBulkOperation(OperationName operationName) {
+        switch (operationName) {
+            case CREATE_JOB:
+            case GET_JOB:
+            case CLOSE_JOB:
+            case ABORT_JOB:
+            case CREATE_BATCH:
+            case GET_BATCH:
+            case GET_ALL_BATCHES:
+            case GET_REQUEST:
+            case GET_RESULTS:
+            case CREATE_BATCH_QUERY:
+            case GET_QUERY_RESULT_IDS:
+            case GET_QUERY_RESULT:
+                return true;
+
+            default:
+                return false;
+        }
+    }
+
+    @Override
+    public boolean process(Exchange exchange, AsyncCallback callback) {
+        log.debug("Processing {}",
+            ((SalesforceEndpoint) getEndpoint()).getOperationName());
+        return processor.process(exchange, callback);
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+
+        // start Salesforce processor
+        ServiceHelper.startService(processor);
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        // stop Salesforce processor
+        ServiceHelper.stopService(processor);
+
+        super.doStop();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/JodaTimeConverter.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/JodaTimeConverter.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/JodaTimeConverter.java
new file mode 100644
index 0000000..372e7a4
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/JodaTimeConverter.java
@@ -0,0 +1,64 @@
+/**
+ * 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.api;
+
+import com.thoughtworks.xstream.converters.Converter;
+import com.thoughtworks.xstream.converters.MarshallingContext;
+import com.thoughtworks.xstream.converters.UnmarshallingContext;
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Constructor;
+
+public class JodaTimeConverter implements Converter {
+    private static final Logger LOG = LoggerFactory.getLogger(JodaTimeConverter.class);
+    private final DateTimeFormatter formatter = ISODateTimeFormat.dateTime();
+
+    @Override
+    public void marshal(Object o, HierarchicalStreamWriter writer, MarshallingContext context) {
+        DateTime dateTime = (DateTime) o;
+        writer.setValue(formatter.print(dateTime));
+    }
+
+    @Override
+    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
+        String dateTimeStr = reader.getValue();
+        Class<?> requiredType = context.getRequiredType();
+        try {
+            Constructor<?> constructor = requiredType.getConstructor(Object.class, DateTimeZone.class);
+            // normalize date time to UTC
+            return constructor.newInstance(dateTimeStr, DateTimeZone.UTC);
+        } catch (Exception e) {
+            throw new IllegalArgumentException(
+                String.format("Error reading Joda DateTime from value %s: %s",
+                    dateTimeStr, e.getMessage()),
+                e);
+        }
+    }
+
+    @Override
+    public boolean canConvert(Class aClass) {
+        return DateTime.class.isAssignableFrom(aClass);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/PicklistEnumConverter.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/PicklistEnumConverter.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/PicklistEnumConverter.java
new file mode 100644
index 0000000..06d0ca5
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/PicklistEnumConverter.java
@@ -0,0 +1,80 @@
+/**
+ * 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.api;
+
+import com.thoughtworks.xstream.converters.Converter;
+import com.thoughtworks.xstream.converters.MarshallingContext;
+import com.thoughtworks.xstream.converters.UnmarshallingContext;
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Method;
+
+public class PicklistEnumConverter implements Converter {
+    private static final Logger LOG = LoggerFactory.getLogger(PicklistEnumConverter.class);
+    private static final String FACTORY_METHOD = "fromValue";
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void marshal(Object o, HierarchicalStreamWriter writer, MarshallingContext context) {
+        Class<?> aClass = o.getClass();
+        try {
+            Method getterMethod = aClass.getMethod("value");
+            writer.setValue((String) getterMethod.invoke(o));
+        } catch (ReflectiveOperationException e) {
+            throw new IllegalArgumentException(
+                String.format("Exception writing pick list value %s of type %s: %s",
+                    o, o.getClass().getName(), e.getMessage()),
+                e);
+        }
+    }
+
+    @Override
+    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
+        String value = reader.getValue();
+        Class<?> requiredType = context.getRequiredType();
+        try {
+            Method factoryMethod = requiredType.getMethod(FACTORY_METHOD, String.class);
+            // use factory method to create object
+            return factoryMethod.invoke(null, value);
+        } catch (ReflectiveOperationException e) {
+            throw new IllegalArgumentException(
+                String.format("Exception reading pick list value %s of type %s: %s",
+                    value, context.getRequiredType().getName(), e.getMessage()),
+                e);
+        } catch (SecurityException e) {
+            throw new IllegalArgumentException(
+                String.format("Security Exception reading pick list value %s of type %s: %s",
+                    value, context.getRequiredType().getName(), e.getMessage()),
+                e);
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public boolean canConvert(Class aClass) {
+        try {
+            return Enum.class.isAssignableFrom(aClass) &&
+                aClass.getMethod(FACTORY_METHOD, String.class) != null;
+        } catch (NoSuchMethodException e) {
+            return false;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/SalesforceException.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/SalesforceException.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/SalesforceException.java
new file mode 100644
index 0000000..760eebe
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/SalesforceException.java
@@ -0,0 +1,104 @@
+/**
+ * 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.api;
+
+import org.apache.camel.CamelException;
+import org.apache.camel.component.salesforce.api.dto.RestError;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class SalesforceException extends CamelException {
+
+    private List<RestError> errors;
+    private int statusCode;
+
+    public SalesforceException(List<RestError> errors, int statusCode) {
+        this(toErrorMessage(errors, statusCode), statusCode);
+
+        this.errors = errors;
+    }
+
+    public SalesforceException(String message, int statusCode) {
+        super(message);
+
+        this.statusCode = statusCode;
+    }
+
+    public SalesforceException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public SalesforceException(Throwable cause) {
+        super(cause);
+    }
+
+    public List<RestError> getErrors() {
+        return Collections.unmodifiableList(errors);
+    }
+
+    public void setErrors(List<RestError> errors) {
+        if (this.errors != null) {
+            this.errors.clear();
+        } else {
+            this.errors = new ArrayList<RestError>();
+        }
+        this.errors.addAll(errors);
+    }
+
+    public int getStatusCode() {
+        return statusCode;
+    }
+
+    public void setStatusCode(int statusCode) {
+        this.statusCode = statusCode;
+    }
+
+    @Override
+    public String toString() {
+        if (errors != null) {
+            return toErrorMessage(errors, statusCode);
+        } else {
+            // make sure we include the custom message
+            final StringBuilder builder = new StringBuilder("{ ");
+            builder.append(getMessage());
+            builder.append(", statusCode: ");
+            builder.append(statusCode);
+            builder.append("}");
+
+            return builder.toString();
+        }
+    }
+
+    private static String toErrorMessage(List<RestError> errors, int statusCode) {
+        StringBuilder builder = new StringBuilder("{ ");
+        if (errors != null) {
+            builder.append(" errors: [");
+            for (RestError error : errors) {
+                builder.append(error.toString());
+            }
+            builder.append("], ");
+        }
+        builder.append("statusCode: ");
+        builder.append(statusCode);
+        builder.append("}");
+
+        return builder.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractDTOBase.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractDTOBase.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractDTOBase.java
new file mode 100644
index 0000000..e4723ae
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractDTOBase.java
@@ -0,0 +1,40 @@
+/**
+ * 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.api.dto;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+// disable null values in json output
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+public abstract class AbstractDTOBase {
+    private final static ObjectMapper mapper = new ObjectMapper();
+
+    @Override
+    public String toString() {
+        try {
+            StringWriter writer = new StringWriter();
+            mapper.writeValue(writer, this);
+            return writer.toString();
+        } catch (IOException e) {
+            return "Error in toString " + e.getMessage();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractQueryRecordsBase.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractQueryRecordsBase.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractQueryRecordsBase.java
new file mode 100644
index 0000000..ddfa6bf
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractQueryRecordsBase.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.salesforce.api.dto;
+
+/**
+ * Abstract base DTO for Salesforce SOQL Query records.
+ * <p>
+ * Derived classes must follow the template below:
+ * </p>
+ * <pre>
+ * {@code
+ * public class QueryResultMySObject extends AbstractQueryRecordsBase {
+ *     @XStreamImplicit
+ *     private List<MySObject> records;
+ *
+ *     public List<MySObject> getRecords() {
+ *         return records;
+ *     }
+ *
+ *     public void setRecords(List<MySObject> records) {
+ *         this.records = records;
+ *     }
+ *
+ * }
+ * }
+ * </pre>
+ */
+public abstract class AbstractQueryRecordsBase extends AbstractDTOBase {
+
+    private Boolean done;
+    private int totalSize;
+    private String nextRecordsUrl;
+
+    public Boolean getDone() {
+        return done;
+    }
+
+    public void setDone(Boolean done) {
+        this.done = done;
+    }
+
+    public int getTotalSize() {
+        return totalSize;
+    }
+
+    public void setTotalSize(int totalSize) {
+        this.totalSize = totalSize;
+    }
+
+    public String getNextRecordsUrl() {
+        return nextRecordsUrl;
+    }
+
+    public void setNextRecordsUrl(String nextRecordsUrl) {
+        this.nextRecordsUrl = nextRecordsUrl;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractSObjectBase.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractSObjectBase.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractSObjectBase.java
new file mode 100644
index 0000000..c236872
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractSObjectBase.java
@@ -0,0 +1,172 @@
+/**
+ * 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.api.dto;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.joda.time.DateTime;
+
+public class AbstractSObjectBase extends AbstractDTOBase {
+
+    private Attributes attributes;
+
+    private String Id;
+
+    private String OwnerId;
+
+    private Boolean IsDeleted;
+
+    private String Name;
+
+    private DateTime CreatedDate;
+
+    private String CreatedById;
+
+    private DateTime LastModifiedDate;
+
+    private String LastModifiedById;
+
+    private DateTime SystemModstamp;
+
+    private String LastActivityDate;
+
+    /**
+     * Utility method to clear all {@link AbstractSObjectBase} fields.
+     * <p>Used when reusing a DTO for a new record.</p>
+     */
+    public final void clearBaseFields() {
+        attributes = null;
+        Id = null;
+        OwnerId = null;
+        IsDeleted = null;
+        Name = null;
+        CreatedDate = null;
+        CreatedById = null;
+        LastModifiedDate = null;
+        LastModifiedById = null;
+        SystemModstamp = null;
+        LastActivityDate = null;
+    }
+
+    public Attributes getAttributes() {
+        return attributes;
+    }
+
+    public void setAttributes(Attributes attributes) {
+        this.attributes = attributes;
+    }
+
+    @JsonProperty("Id")
+    public String getId() {
+        return Id;
+    }
+
+    @JsonProperty("Id")
+    public void setId(String id) {
+        Id = id;
+    }
+
+    @JsonProperty("OwnerId")
+    public String getOwnerId() {
+        return OwnerId;
+    }
+
+    @JsonProperty("OwnerId")
+    public void setOwnerId(String ownerId) {
+        OwnerId = ownerId;
+    }
+
+    @JsonProperty("IsDeleted")
+    public Boolean isIsDeleted() {
+        return IsDeleted;
+    }
+
+    @JsonProperty("IsDeleted")
+    public void setIsDeleted(Boolean isDeleted) {
+        IsDeleted = isDeleted;
+    }
+
+    @JsonProperty("Name")
+    public String getName() {
+        return Name;
+    }
+
+    @JsonProperty("Name")
+    public void setName(String name) {
+        Name = name;
+    }
+
+    @JsonProperty("CreatedDate")
+    public DateTime getCreatedDate() {
+        return CreatedDate;
+    }
+
+    @JsonProperty("CreatedDate")
+    public void setCreatedDate(DateTime createdDate) {
+        CreatedDate = createdDate;
+    }
+
+    @JsonProperty("CreatedById")
+    public String getCreatedById() {
+        return CreatedById;
+    }
+
+    @JsonProperty("CreatedById")
+    public void setCreatedById(String createdById) {
+        CreatedById = createdById;
+    }
+
+    @JsonProperty("LastModifiedDate")
+    public DateTime getLastModifiedDate() {
+        return LastModifiedDate;
+    }
+
+    @JsonProperty("LastModifiedDate")
+    public void setLastModifiedDate(DateTime lastModifiedDate) {
+        LastModifiedDate = lastModifiedDate;
+    }
+
+    @JsonProperty("LastModifiedById")
+    public String getLastModifiedById() {
+        return LastModifiedById;
+    }
+
+    @JsonProperty("LastModifiedById")
+    public void setLastModifiedById(String lastModifiedById) {
+        LastModifiedById = lastModifiedById;
+    }
+
+    @JsonProperty("SystemModstamp")
+    public DateTime getSystemModstamp() {
+        return SystemModstamp;
+    }
+
+    @JsonProperty("SystemModstamp")
+    public void setSystemModstamp(DateTime systemModstamp) {
+        SystemModstamp = systemModstamp;
+    }
+
+    @JsonProperty("LastActivityDate")
+    public String getLastActivityDate() {
+        return LastActivityDate;
+    }
+
+    @JsonProperty("LastActivityDate")
+    public void setLastActivityDate(String lastActivityDate) {
+        LastActivityDate = lastActivityDate;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Attributes.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Attributes.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Attributes.java
new file mode 100644
index 0000000..439f4c3
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Attributes.java
@@ -0,0 +1,38 @@
+/**
+ * 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.api.dto;
+
+public class Attributes extends AbstractDTOBase {
+    private String type;
+    private String url;
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ChildRelationShip.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ChildRelationShip.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ChildRelationShip.java
new file mode 100644
index 0000000..4c2d58e
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/ChildRelationShip.java
@@ -0,0 +1,74 @@
+/**
+ * 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.api.dto;
+
+public class ChildRelationShip extends AbstractDTOBase {
+    private String field;
+    private Boolean deprecatedAndHidden;
+    private String relationshipName;
+    private Boolean cascadeDelete;
+    private Boolean restrictedDelete;
+    private String childSObject;
+
+    public String getField() {
+        return field;
+    }
+
+    public void setField(String field) {
+        this.field = field;
+    }
+
+    public Boolean isDeprecatedAndHidden() {
+        return deprecatedAndHidden;
+    }
+
+    public void setDeprecatedAndHidden(Boolean deprecatedAndHidden) {
+        this.deprecatedAndHidden = deprecatedAndHidden;
+    }
+
+    public String getRelationshipName() {
+        return relationshipName;
+    }
+
+    public void setRelationshipName(String relationshipName) {
+        this.relationshipName = relationshipName;
+    }
+
+    public Boolean isCascadeDelete() {
+        return cascadeDelete;
+    }
+
+    public void setCascadeDelete(Boolean cascadeDelete) {
+        this.cascadeDelete = cascadeDelete;
+    }
+
+    public Boolean isRestrictedDelete() {
+        return restrictedDelete;
+    }
+
+    public void setRestrictedDelete(Boolean restrictedDelete) {
+        this.restrictedDelete = restrictedDelete;
+    }
+
+    public String getChildSObject() {
+        return childSObject;
+    }
+
+    public void setChildSObject(String childSObject) {
+        this.childSObject = childSObject;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/CreateSObjectResult.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/CreateSObjectResult.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/CreateSObjectResult.java
new file mode 100644
index 0000000..bc9fdaa
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/CreateSObjectResult.java
@@ -0,0 +1,57 @@
+/**
+ * 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.api.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+
+import java.util.List;
+
+@XStreamAlias("Result")
+public class CreateSObjectResult extends AbstractDTOBase {
+
+    private String id;
+
+    @XStreamImplicit
+    private List<RestError> errors;
+
+    private Boolean success;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public List<RestError> getErrors() {
+        return errors;
+    }
+
+    public void setErrors(List<RestError> errors) {
+        this.errors = errors;
+    }
+
+    public Boolean getSuccess() {
+        return success;
+    }
+
+    public void setSuccess(Boolean success) {
+        this.success = success;
+    }
+}


[12/23] camel git commit: Added support in API component framework for specifying nullableOptions

Posted by dh...@apache.org.
Added support in API component framework for specifying nullableOptions


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

Branch: refs/heads/linkedin-component
Commit: 91e19c10da4fde3ab23ad87b602399740facafe6
Parents: bd7d94d
Author: Dhiraj Bokde <dh...@yahoo.com>
Authored: Thu Jul 10 14:25:38 2014 -0700
Committer: Dhiraj Bokde <dh...@yahoo.com>
Committed: Thu Jul 10 14:25:38 2014 -0700

----------------------------------------------------------------------
 .../util/component/AbstractApiProducer.java     | 23 +++--
 .../camel/util/component/ApiConsumerHelper.java |  2 +-
 .../camel/util/component/ApiMethodHelper.java   | 90 ++++++++++++++++++--
 .../camel/util/component/ApiMethodParser.java   |  4 +-
 .../util/component/ApiMethodHelperTest.java     | 21 +++--
 components/camel-box/pom.xml                    |  4 +
 .../component/box/AbstractBoxTestSupport.java   |  1 -
 ...BoxCollaborationsManagerIntegrationTest.java |  2 +-
 .../box/IBoxCommentsManagerIntegrationTest.java |  4 +-
 .../box/IBoxEventsManagerIntegrationTest.java   |  2 +-
 .../box/IBoxFilesManagerIntegrationTest.java    | 13 ++-
 .../box/IBoxFoldersManagerIntegrationTest.java  |  4 +-
 .../box/IBoxGroupsManagerIntegrationTest.java   | 10 +--
 .../box/IBoxSearchManagerIntegrationTest.java   |  2 +-
 .../IBoxSharedItemsManagerIntegrationTest.java  |  2 +-
 .../box/IBoxUsersManagerIntegrationTest.java    |  6 +-
 .../src/main/java/__name__Endpoint.java         |  2 +-
 .../src/it/all-it/pom.xml                       |  3 +
 .../maven/AbstractApiMethodGeneratorMojo.java   | 10 +--
 .../camel/maven/ApiComponentGeneratorMojo.java  | 29 +++++++
 .../java/org/apache/camel/maven/ApiProxy.java   | 10 +++
 .../camel/maven/DocumentGeneratorMojo.java      |  9 +-
 .../maven/JavadocApiMethodGeneratorMojo.java    | 15 ++--
 .../src/main/resources/api-collection.vm        |  6 +-
 .../src/main/resources/api-document.vm          | 22 ++++-
 .../src/main/resources/api-route-test.vm        |  2 +-
 .../maven/ApiComponentGeneratorMojoTest.java    |  1 +
 27 files changed, 234 insertions(+), 65 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiProducer.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiProducer.java b/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiProducer.java
index 17276aa..b4c7427 100644
--- a/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiProducer.java
+++ b/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiProducer.java
@@ -145,7 +145,7 @@ public abstract class AbstractApiProducer<E extends Enum<E> & ApiName, T>
 
             // filter candidates based on endpoint and exchange properties
             final Set<String> argNames = properties.keySet();
-            final List<ApiMethod> filteredMethods = ApiMethodHelper.filterMethods(candidates,
+            final List<ApiMethod> filteredMethods = methodHelper.filterMethods(candidates,
                     ApiMethodHelper.MatchType.SUPER_SET,
                     argNames.toArray(new String[argNames.size()]));
 
@@ -172,15 +172,24 @@ public abstract class AbstractApiProducer<E extends Enum<E> & ApiName, T>
         if (inBodyProperty != null) {
 
             Object value = exchange.getIn().getBody();
-            try {
-                value = endpoint.getCamelContext().getTypeConverter().mandatoryConvertTo(
+            if (value != null) {
+                try {
+                    value = endpoint.getCamelContext().getTypeConverter().mandatoryConvertTo(
                         endpoint.getConfiguration().getClass().getDeclaredField(inBodyProperty).getType(),
                         exchange, value);
-            } catch (Exception e) {
-                exchange.setException(new RuntimeCamelException(String.format(
-                        "Error converting value %s to property %s: %s", value, inBodyProperty, e.getMessage()), e));
+                } catch (Exception e) {
+                    exchange.setException(new RuntimeCamelException(String.format(
+                            "Error converting value %s to property %s: %s", value, inBodyProperty, e.getMessage()), e));
 
-                return false;
+                    return false;
+                }
+            } else {
+                // allow null values for inBody only if its a nullable option
+                if (!methodHelper.getNullableArguments().contains(inBodyProperty)) {
+                    exchange.setException(new NullPointerException(inBodyProperty));
+
+                    return false;
+                }
             }
 
             log.debug("Property [{}] has message body value {}", inBodyProperty, value);

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/camel-core/src/main/java/org/apache/camel/util/component/ApiConsumerHelper.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/util/component/ApiConsumerHelper.java b/camel-core/src/main/java/org/apache/camel/util/component/ApiConsumerHelper.java
index 779dea0..30a7745 100644
--- a/camel-core/src/main/java/org/apache/camel/util/component/ApiConsumerHelper.java
+++ b/camel-core/src/main/java/org/apache/camel/util/component/ApiConsumerHelper.java
@@ -55,7 +55,7 @@ public final class ApiConsumerHelper {
         propertyNamesInterceptor.interceptPropertyNames(argNames);
 
         final String[] argNamesArray = argNames.toArray(new String[argNames.size()]);
-        List<ApiMethod> filteredMethods = ApiMethodHelper.filterMethods(
+        List<ApiMethod> filteredMethods = endpoint.methodHelper.filterMethods(
                 endpoint.getCandidates(), ApiMethodHelper.MatchType.SUPER_SET, argNamesArray);
 
         if (filteredMethods.isEmpty()) {

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodHelper.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodHelper.java b/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodHelper.java
index b4401eb..7ec732b 100644
--- a/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodHelper.java
+++ b/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodHelper.java
@@ -52,19 +52,27 @@ public final class ApiMethodHelper<T extends Enum<T> & ApiMethod> {
 
     // maps aliases to actual method names
     private final HashMap<String, Set<String>> aliasesMap = new HashMap<String, Set<String>>();
+    private final List<String> nullableArguments;
 
     /**
      * Create a helper to work with a {@link ApiMethod}, using optional method aliases.
      * @param apiMethodEnum {@link ApiMethod} enumeration class
      * @param aliases Aliases mapped to actual method names
+     * @param nullableArguments names of arguments that default to null value
      */
-    public ApiMethodHelper(Class<T> apiMethodEnum, Map<String, String> aliases) {
+    public ApiMethodHelper(Class<T> apiMethodEnum, Map<String, String> aliases, List<String> nullableArguments) {
 
         // validate ApiMethod Enum
         if (apiMethodEnum == null) {
             throw new IllegalArgumentException("ApiMethod enumeration cannot be null");
         }
 
+        if (nullableArguments != null && !nullableArguments.isEmpty()) {
+            this.nullableArguments = Collections.unmodifiableList(new ArrayList<String>(nullableArguments));
+        } else {
+            this.nullableArguments = Collections.emptyList();
+        }
+
         final Map<Pattern, String> aliasPatterns = new HashMap<Pattern, String>();
         for (Map.Entry<String, String> alias : aliases.entrySet()) {
             if (alias.getKey() == null || alias.getValue() == null) {
@@ -144,6 +152,53 @@ public final class ApiMethodHelper<T extends Enum<T> & ApiMethod> {
 
         }
 
+        // validate nullableArguments
+        if (!validArguments.keySet().containsAll(this.nullableArguments)) {
+            List<String> unknowns = new ArrayList<String>(this.nullableArguments);
+            unknowns.removeAll(validArguments.keySet());
+            throw new IllegalArgumentException("Unknown nullable arguments " + unknowns.toString());
+        }
+
+        // validate aliases
+        for (Map.Entry<String, Set<String>> entry : aliasesMap.entrySet()) {
+
+            // look for aliases that match multiple methods
+            final Set<String> methodNames = entry.getValue();
+            if (methodNames.size() > 1) {
+
+                // get mapped methods
+                final List<T> aliasedMethods = new ArrayList<T>();
+                for (String methodName : methodNames) {
+                    List<T> mappedMethods = methodMap.get(methodName);
+                    aliasedMethods.addAll(mappedMethods);
+                }
+
+                // look for argument overlap
+                for (T method : aliasedMethods) {
+                    final List<String> argNames = new ArrayList<String>(method.getArgNames());
+                    argNames.removeAll(this.nullableArguments);
+
+                    final Set<T> ambiguousMethods = new HashSet<T>();
+                    for (T otherMethod : aliasedMethods) {
+                        if (method != otherMethod) {
+                            final List<String> otherArgsNames = new ArrayList<String>(otherMethod.getArgNames());
+                            otherArgsNames.removeAll(this.nullableArguments);
+
+                            if (argNames.equals(otherArgsNames)) {
+                                ambiguousMethods.add(method);
+                                ambiguousMethods.add(otherMethod);
+                            }
+                        }
+                    }
+
+                    if (!ambiguousMethods.isEmpty()) {
+                        throw new IllegalArgumentException(
+                            String.format("Ambiguous alias %s for methods %s", entry.getKey(), ambiguousMethods));
+                    }
+                }
+            }
+        }
+
         LOG.debug("Found {} unique method names in {} methods", methodMap.size(), methods.length);
     }
 
@@ -192,12 +247,23 @@ public final class ApiMethodHelper<T extends Enum<T> & ApiMethod> {
      * @return methods with arguments that satisfy the match type.<p/>
      * For SUPER_SET match, if methods with exact match are found, methods that take a subset are ignored
      */
-    public static List<ApiMethod> filterMethods(List<? extends ApiMethod> methods, MatchType matchType,
+    public List<ApiMethod> filterMethods(List<? extends ApiMethod> methods, MatchType matchType,
                                                           String... argNames) {
-        List<String> argsList = Arrays.asList(argNames);
+        // original arguments
+        final List<String> argsList = Arrays.asList(argNames);
+        // supplied arguments with missing nullable arguments
+        final List<String> withNullableArgsList;
+        if (!nullableArguments.isEmpty()) {
+            withNullableArgsList = new ArrayList<String>(argsList);
+            withNullableArgsList.addAll(nullableArguments);
+        } else {
+            withNullableArgsList = null;
+        }
+
         // list of methods that have all args in the given names
         final List<ApiMethod> result = new ArrayList<ApiMethod>();
         final List<ApiMethod> extraArgs = new ArrayList<ApiMethod>();
+        final List<ApiMethod> nullArgs = new ArrayList<ApiMethod>();
 
         for (ApiMethod method : methods) {
             final List<String> methodArgs = method.getArgNames();
@@ -225,12 +291,18 @@ public final class ApiMethodHelper<T extends Enum<T> & ApiMethod> {
                         // method takes a subset, unused args
                         extraArgs.add(method);
                     }
+                } else if (result.isEmpty() && extraArgs.isEmpty()) {
+                    // avoid looking for nullable args by checking for empty result and extraArgs
+                    if (withNullableArgsList != null && withNullableArgsList.containsAll(methodArgs)) {
+                        nullArgs.add(method);
+                    }
                 }
                 break;
             }
         }
 
-        return Collections.unmodifiableList(result.isEmpty() ? extraArgs : result);
+        // preference order is exact match, matches with extra args, matches with null args
+        return Collections.unmodifiableList(result.isEmpty() ? (extraArgs.isEmpty() ? nullArgs : extraArgs) : result);
     }
 
     /**
@@ -283,7 +355,7 @@ public final class ApiMethodHelper<T extends Enum<T> & ApiMethod> {
     }
 
     /**
-     * Get argument types and names used by all methods.
+     * Returns argument types and names used by all methods.
      * @return map with argument names as keys, and types as values
      */
     public Map<String, Class<?>> allArguments() {
@@ -291,6 +363,14 @@ public final class ApiMethodHelper<T extends Enum<T> & ApiMethod> {
     }
 
     /**
+     * Returns argument names that can be set to null if not specified.
+     * @return list of argument names
+     */
+    public List<String> getNullableArguments() {
+        return nullableArguments;
+    }
+
+    /**
      * Get the type for the given argument name.
      * @param argName argument name
      * @return argument type

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodParser.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodParser.java b/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodParser.java
index 92f5750..27c8be8 100644
--- a/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodParser.java
+++ b/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodParser.java
@@ -126,7 +126,9 @@ public abstract class ApiMethodParser<T> {
                 final Class<?> type = forName(argsMatcher.group(1));
                 argTypes.add(type);
 
-                final String typeArgs = argsMatcher.group(2) != null ? argsMatcher.group(2).replaceAll(" ", "") : null;
+                final String typeArgsGroup = argsMatcher.group(2);
+                final String typeArgs = typeArgsGroup != null
+                    ? typeArgsGroup.substring(1, typeArgsGroup.length() - 1).replaceAll(" ", "") : null;
                 arguments.add(new Argument(argsMatcher.group(3), type, typeArgs));
             }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/camel-core/src/test/java/org/apache/camel/util/component/ApiMethodHelperTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/util/component/ApiMethodHelperTest.java b/camel-core/src/test/java/org/apache/camel/util/component/ApiMethodHelperTest.java
index 4e2fee7..5f55794 100644
--- a/camel-core/src/test/java/org/apache/camel/util/component/ApiMethodHelperTest.java
+++ b/camel-core/src/test/java/org/apache/camel/util/component/ApiMethodHelperTest.java
@@ -24,11 +24,10 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 
-import org.junit.Test;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import org.junit.Test;
 
 public class ApiMethodHelperTest {
 
@@ -38,7 +37,7 @@ public class ApiMethodHelperTest {
     static {
         final HashMap<String, String> aliases = new HashMap<String, String>();
         aliases.put("say(.*)", "$1");
-        apiMethodHelper = new ApiMethodHelper<TestMethod>(TestMethod.class, aliases);
+        apiMethodHelper = new ApiMethodHelper<TestMethod>(TestMethod.class, aliases, Arrays.asList("names"));
     }
 
     @Test
@@ -64,23 +63,29 @@ public class ApiMethodHelperTest {
 
     @Test
     public void testFilterMethods() {
-        List<ApiMethod> methods = ApiMethodHelper.filterMethods(Arrays.asList(sayHis), ApiMethodHelper.MatchType.EXACT);
+        List<ApiMethod> methods = apiMethodHelper.filterMethods(Arrays.asList(sayHis), ApiMethodHelper.MatchType.EXACT);
         assertEquals("Exact match failed for sayHi()", 1, methods.size());
         assertEquals("Exact match failed for sayHi()", TestMethod.SAYHI, methods.get(0));
 
-        methods = ApiMethodHelper.filterMethods(Arrays.asList(sayHis), ApiMethodHelper.MatchType.SUBSET);
+        methods = apiMethodHelper.filterMethods(Arrays.asList(sayHis), ApiMethodHelper.MatchType.SUBSET);
         assertEquals("Subset match failed for sayHi(*)", 2, methods.size());
 
-        methods = ApiMethodHelper.filterMethods(Arrays.asList(sayHis), ApiMethodHelper.MatchType.SUBSET, "name");
+        methods = apiMethodHelper.filterMethods(Arrays.asList(sayHis), ApiMethodHelper.MatchType.SUBSET, "name");
         assertEquals("Subset match failed for sayHi(name)", 1, methods.size());
         assertEquals("Exact match failed for sayHi()", TestMethod.SAYHI_1, methods.get(0));
 
-        methods = ApiMethodHelper.filterMethods(Arrays.asList(sayHis), ApiMethodHelper.MatchType.SUPER_SET, "name");
+        methods = apiMethodHelper.filterMethods(Arrays.asList(sayHis), ApiMethodHelper.MatchType.SUPER_SET, "name");
         assertEquals("Super set match failed for sayHi(name)", 1, methods.size());
         assertEquals("Exact match failed for sayHi()", TestMethod.SAYHI_1, methods.get(0));
 
-        methods = ApiMethodHelper.filterMethods(Arrays.asList(TestMethod.values()), ApiMethodHelper.MatchType.SUPER_SET, "name");
+        methods = apiMethodHelper.filterMethods(Arrays.asList(TestMethod.values()), ApiMethodHelper.MatchType.SUPER_SET, "name");
         assertEquals("Super set match failed for sayHi(name)", 2, methods.size());
+
+        // test nullable names
+        methods = apiMethodHelper.filterMethods(
+            Arrays.asList(TestMethod.GREETALL, TestMethod.GREETALL_1, TestMethod.GREETALL_2),
+            ApiMethodHelper.MatchType.SUPER_SET);
+        assertEquals("Super set match with null args failed for greetAll(names)", 1, methods.size());
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-box/pom.xml b/components/camel-box/pom.xml
index aee2b38..307d8a6 100644
--- a/components/camel-box/pom.xml
+++ b/components/camel-box/pom.xml
@@ -315,6 +315,7 @@
                   <proxyClass>org.apache.camel.component.box.internal.LongPollingEventsManager</proxyClass>
                   <fromSignatureFile>${project.basedir}/src/signatures/long-polling-events-manager.txt</fromSignatureFile>
                   <excludeConfigNames>callback</excludeConfigNames>
+                  <nullableOptions/>
                 </api>
                 <api>
                   <apiName>search</apiName>
@@ -390,6 +391,9 @@
               <fromJavadoc>
                 <excludeClasses>BoxResourceManager|BoxItemsManager</excludeClasses>
               </fromJavadoc>
+              <nullableOptions>
+                <nullableOption>defaultRequest</nullableOption>
+              </nullableOptions>
               <aliases>
                 <alias>
                   <methodPattern>[gs]et(.+)</methodPattern>

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/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
index 130bcaf..177c4e2 100644
--- 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
@@ -48,7 +48,6 @@ public abstract class AbstractBoxTestSupport extends CamelTestSupport {
     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;
 

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCollaborationsManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCollaborationsManagerIntegrationTest.java b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCollaborationsManagerIntegrationTest.java
index eea80af..0931481 100644
--- a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCollaborationsManagerIntegrationTest.java
+++ b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCollaborationsManagerIntegrationTest.java
@@ -68,7 +68,7 @@ public class IBoxCollaborationsManagerIntegrationTest extends AbstractBoxTestSup
         // parameter type is String
         headers.put("CamelBox.collabId", collabId);
         // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
         requestBodyAndHeaders("direct://DELETECOLLABORATION", null, headers);
     }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCommentsManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCommentsManagerIntegrationTest.java b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCommentsManagerIntegrationTest.java
index 178852a..eec01ce 100644
--- a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCommentsManagerIntegrationTest.java
+++ b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCommentsManagerIntegrationTest.java
@@ -73,7 +73,7 @@ public class IBoxCommentsManagerIntegrationTest extends AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.commentId", commentId);
         // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
         requestBodyAndHeaders("direct://DELETECOMMENT", null, headers);
     }
 
@@ -85,7 +85,7 @@ public class IBoxCommentsManagerIntegrationTest extends AbstractBoxTestSupport {
             // parameter type is String
             headers.put("CamelBox.commentId", comment.getId());
             // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-            headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//            headers.put("CamelBox.defaultRequest", null);
             BoxComment result = requestBodyAndHeaders("direct://GETCOMMENT", null, headers);
 
             LOG.debug("getComment: " + result);

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxEventsManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxEventsManagerIntegrationTest.java b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxEventsManagerIntegrationTest.java
index b86ed4b..b771d67 100644
--- a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxEventsManagerIntegrationTest.java
+++ b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxEventsManagerIntegrationTest.java
@@ -42,7 +42,7 @@ public class IBoxEventsManagerIntegrationTest extends AbstractBoxTestSupport {
     @Test
     public void testGetEventOptions() throws Exception {
         // using com.box.restclientv2.requestsbase.BoxDefaultRequestObject message body for single parameter "defaultRequest"
-        BoxCollection result = requestBody("direct://GETEVENTOPTIONS", BOX_DEFAULT_REQUEST_OBJECT);
+        BoxCollection result = requestBody("direct://GETEVENTOPTIONS", null);
 
         assertNotNull("getEventOptions result", result);
         LOG.debug("getEventOptions: " + result);

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFilesManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFilesManagerIntegrationTest.java b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFilesManagerIntegrationTest.java
index 5fd8239..00ac056 100644
--- a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFilesManagerIntegrationTest.java
+++ b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFilesManagerIntegrationTest.java
@@ -114,7 +114,7 @@ public class IBoxFilesManagerIntegrationTest extends AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.fileId", testFileId);
         // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
         InputStream result = requestBodyAndHeaders("direct://DOWNLOADFILE", null, headers);
 
         assertNotNull("downloadFile result", result);
@@ -134,7 +134,7 @@ public class IBoxFilesManagerIntegrationTest extends AbstractBoxTestSupport {
         final FileTransferListener fileTransferListener = new FileTransferListener();
         headers.put("CamelBox.listener", fileTransferListener);
         // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
         requestBodyAndHeaders("direct://DOWNLOADFILE_1", null, headers);
 
@@ -164,7 +164,7 @@ public class IBoxFilesManagerIntegrationTest extends AbstractBoxTestSupport {
         final FileTransferListener fileTransferListener = new FileTransferListener();
         headers.put("CamelBox.listener", fileTransferListener);
         // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
         requestBodyAndHeaders("direct://DOWNLOADFILE_2", null, headers);
 
@@ -195,9 +195,8 @@ public class IBoxFilesManagerIntegrationTest extends AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.fileId", testFileId);
         // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
-//        BoxFile result = requestBodyAndHeaders("direct://GETFILE", null, headers);
         BoxFile result = requestBodyAndHeaders("direct://GETFILE", null, headers);
 
         assertNotNull("getFile result", result);
@@ -210,7 +209,7 @@ public class IBoxFilesManagerIntegrationTest extends AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.fileId", testFileId);
         // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
         com.box.boxjavalibv2.dao.BoxCollection result = requestBodyAndHeaders("direct://GETFILECOMMENTS", null, headers);
 
@@ -224,7 +223,7 @@ public class IBoxFilesManagerIntegrationTest extends AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.fileId", testFileId);
         // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
         java.util.List result = requestBodyAndHeaders("direct://GETFILEVERSIONS", null, headers);
 

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFoldersManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFoldersManagerIntegrationTest.java b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFoldersManagerIntegrationTest.java
index fc46361..3fb018b 100644
--- a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFoldersManagerIntegrationTest.java
+++ b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFoldersManagerIntegrationTest.java
@@ -128,7 +128,7 @@ public class IBoxFoldersManagerIntegrationTest extends AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.folderId", "0");
         // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
         final BoxFolder result = (BoxFolder) requestBodyAndHeaders("direct://GETFOLDER", null, headers);
         assertNotNull("getFolder result", result);
@@ -145,7 +145,7 @@ public class IBoxFoldersManagerIntegrationTest extends AbstractBoxTestSupport {
             // parameter type is String
             headers.put("CamelBox.folderId", testFolder.getId());
             // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-            headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//            headers.put("CamelBox.defaultRequest", null);
 
             List result = requestBodyAndHeaders("direct://GETFOLDERCOLLABORATIONS", null, headers);
             assertNotNull("getFolderCollaborations result", result);

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxGroupsManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxGroupsManagerIntegrationTest.java b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxGroupsManagerIntegrationTest.java
index 14e8ad4..7207e50 100644
--- a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxGroupsManagerIntegrationTest.java
+++ b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxGroupsManagerIntegrationTest.java
@@ -103,7 +103,7 @@ public class IBoxGroupsManagerIntegrationTest extends AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.groupId", groupId);
         // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
         requestBodyAndHeaders("direct://DELETEGROUP", null, headers);
     }
@@ -119,7 +119,7 @@ public class IBoxGroupsManagerIntegrationTest extends AbstractBoxTestSupport {
             // parameter type is String
             headers.put("CamelBox.membershipId", membership.getId());
             // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-            headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//            headers.put("CamelBox.defaultRequest", null);
             requestBodyAndHeaders("direct://DELETEMEMBERSHIP", null, headers);
         } finally {
             deleteGroup(group.getId());
@@ -134,7 +134,7 @@ public class IBoxGroupsManagerIntegrationTest extends AbstractBoxTestSupport {
             // parameter type is String
             headers.put("CamelBox.groupId", group.getId());
             // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-            headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//            headers.put("CamelBox.defaultRequest", null);
 
             BoxCollection result = requestBodyAndHeaders("direct://GETALLCOLLABORATIONS", null, headers);
 
@@ -148,7 +148,7 @@ public class IBoxGroupsManagerIntegrationTest extends AbstractBoxTestSupport {
     @Test
     public void testGetAllGroups() throws Exception {
         // using com.box.restclientv2.requestsbase.BoxDefaultRequestObject message body for single parameter "defaultRequest"
-        BoxCollection result = requestBody("direct://GETALLGROUPS", BOX_DEFAULT_REQUEST_OBJECT);
+        BoxCollection result = requestBody("direct://GETALLGROUPS", null);
 
         assertNotNull("getAllGroups result", result);
         LOG.debug("getAllGroups: " + result);
@@ -165,7 +165,7 @@ public class IBoxGroupsManagerIntegrationTest extends AbstractBoxTestSupport {
             // parameter type is String
             headers.put("CamelBox.membershipId", membership.getId());
             // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-            headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//            headers.put("CamelBox.defaultRequest", null);
 
             BoxGroupMembership result = requestBodyAndHeaders("direct://GETMEMBERSHIP", null, headers);
 

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSearchManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSearchManagerIntegrationTest.java b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSearchManagerIntegrationTest.java
index 8648787..5423076 100644
--- a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSearchManagerIntegrationTest.java
+++ b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSearchManagerIntegrationTest.java
@@ -45,7 +45,7 @@ public class IBoxSearchManagerIntegrationTest extends AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.searchQuery", "Test");
         // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
         com.box.boxjavalibv2.dao.BoxCollection result = requestBodyAndHeaders("direct://SEARCH", null, headers);
         assertNotNull("search result", result);

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSharedItemsManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSharedItemsManagerIntegrationTest.java b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSharedItemsManagerIntegrationTest.java
index a9e0443..5017953 100644
--- a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSharedItemsManagerIntegrationTest.java
+++ b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSharedItemsManagerIntegrationTest.java
@@ -35,7 +35,7 @@ public class IBoxSharedItemsManagerIntegrationTest extends AbstractBoxTestSuppor
     @Test
     public void testGetSharedItem() throws Exception {
         // using com.box.restclientv2.requestsbase.BoxDefaultRequestObject message body for single parameter "defaultRequest"
-        BoxItem result = requestBody("direct://GETSHAREDITEM", BOX_DEFAULT_REQUEST_OBJECT);
+        BoxItem result = requestBody("direct://GETSHAREDITEM", null);
 
         assertNotNull("getSharedItem result", result);
         LOG.debug("getSharedItem: " + result);

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxUsersManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxUsersManagerIntegrationTest.java b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxUsersManagerIntegrationTest.java
index a2f473c..11a77db 100644
--- a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxUsersManagerIntegrationTest.java
+++ b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxUsersManagerIntegrationTest.java
@@ -89,7 +89,7 @@ public class IBoxUsersManagerIntegrationTest extends AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.emailId", CAMEL_EMAIL_ALIAS);
         // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
         requestBodyAndHeaders("direct://DELETEEMAILALIAS", null, headers);
     }
@@ -125,7 +125,7 @@ public class IBoxUsersManagerIntegrationTest extends AbstractBoxTestSupport {
     @Test
     public void testGetCurrentUser() throws Exception {
         // using com.box.restclientv2.requestsbase.BoxDefaultRequestObject message body for single parameter "defaultRequest"
-        BoxUser result = requestBody("direct://GETCURRENTUSER", BOX_DEFAULT_REQUEST_OBJECT);
+        BoxUser result = requestBody("direct://GETCURRENTUSER", null);
 
         assertNotNull("getCurrentUser result", result);
         LOG.debug("getCurrentUser: " + result);
@@ -140,7 +140,7 @@ public class IBoxUsersManagerIntegrationTest extends AbstractBoxTestSupport {
             // parameter type is String
             headers.put("CamelBox.userId", enterpriseUser.getId());
             // parameter type is com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-            headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//            headers.put("CamelBox.defaultRequest", null);
 
             List result = requestBodyAndHeaders("direct://GETEMAILALIASES", null, headers);
 

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Endpoint.java
----------------------------------------------------------------------
diff --git a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Endpoint.java b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Endpoint.java
index e7a0340..a804e7b 100644
--- a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Endpoint.java
+++ b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Endpoint.java
@@ -75,7 +75,7 @@ public class ${name}Endpoint extends AbstractApiEndpoint<${name}ApiName, ${name}
     @Override
     protected void afterConfigureProperties() {
         // TODO create API proxy, set connection properties, etc.
-        switch ((${name}ApiName) apiName) {
+        switch (apiName) {
             case HELLO_FILE:
                 apiProxy = new ${name}FileHello();
                 break;

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/it/all-it/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-api-component-maven-plugin/src/it/all-it/pom.xml b/tooling/maven/camel-api-component-maven-plugin/src/it/all-it/pom.xml
index 369f65b..d1d6449 100644
--- a/tooling/maven/camel-api-component-maven-plugin/src/it/all-it/pom.xml
+++ b/tooling/maven/camel-api-component-maven-plugin/src/it/all-it/pom.xml
@@ -151,6 +151,9 @@
                       <name>extraString</name>
                     </extraOption>
                   </extraOptions>
+                  <nullableOptions>
+                    <nullableOption>namesList</nullableOption>
+                  </nullableOptions>
                   <fromSignatureFile>../../../src/test/resources/test-proxy-signatures.txt</fromSignatureFile>
                 </api>
                 <api>

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/AbstractApiMethodGeneratorMojo.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/AbstractApiMethodGeneratorMojo.java b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/AbstractApiMethodGeneratorMojo.java
index 6ddb5b6..387fc7c 100644
--- a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/AbstractApiMethodGeneratorMojo.java
+++ b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/AbstractApiMethodGeneratorMojo.java
@@ -309,8 +309,10 @@ public abstract class AbstractApiMethodGeneratorMojo extends AbstractApiMethodBa
             parameterizedType.append('<');
 
             // Note: its ok to split, since we don't support parsing nested type arguments
-            String[] argTypes = typeArgs.split(",");
+            final String[] argTypes = typeArgs.split(",");
             boolean ignore = false;
+            final int nTypes = argTypes.length;
+            int i = 0;
             for (String argType : argTypes) {
 
                 // try loading as is first
@@ -326,7 +328,7 @@ public abstract class AbstractApiMethodGeneratorMojo extends AbstractApiMethodBa
                         parameterizedType.append(
                             getCanonicalName(getProjectClassLoader().loadClass("java.lang." + argType)));
                     } catch (ClassNotFoundException e1) {
-                        log.warn("Ignoring type parameters < " + typeArgs + "> for argument " + argument.getName()
+                        log.warn("Ignoring type parameters <" + typeArgs + "> for argument " + argument.getName()
                                  + ", unable to load parametric type argument " + argType, e1);
                         ignore = true;
                     }
@@ -335,14 +337,12 @@ public abstract class AbstractApiMethodGeneratorMojo extends AbstractApiMethodBa
                 if (ignore) {
                     // give up
                     break;
-                } else {
+                } else if (++i < nTypes) {
                     parameterizedType.append(",");
                 }
             }
 
             if (!ignore) {
-                // replace the last ',' with '>'
-                parameterizedType.deleteCharAt(parameterizedType.length() - 1);
                 parameterizedType.append('>');
                 canonicalName = parameterizedType.toString();
             }

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiComponentGeneratorMojo.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiComponentGeneratorMojo.java b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiComponentGeneratorMojo.java
index 290d322..e099c61 100644
--- a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiComponentGeneratorMojo.java
+++ b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiComponentGeneratorMojo.java
@@ -48,6 +48,12 @@ public class ApiComponentGeneratorMojo extends AbstractApiMethodBaseMojo {
     protected FromJavadoc fromJavadoc = new FromJavadoc();
 
     /**
+     * Names of options that can be set to null value if not specified.
+     */
+    @Parameter
+    private String[] nullableOptions;
+
+    /**
      * Method alias patterns for all APIs.
      */
     @Parameter
@@ -102,6 +108,11 @@ public class ApiComponentGeneratorMojo extends AbstractApiMethodBaseMojo {
                 if (!aliases.isEmpty() && api.getAliases().isEmpty()) {
                     api.setAliases(aliases);
                 }
+
+                // set common nullable options if needed
+                if (api.getNullableOptions() == null) {
+                    api.setNullableOptions(nullableOptions);
+                }
             }
 
             // generate ApiCollection
@@ -239,4 +250,22 @@ public class ApiComponentGeneratorMojo extends AbstractApiMethodBaseMojo {
         }
         return builder.toString();
     }
+
+    public static String getNullableOptionValues(String[] nullableOptions) {
+
+        if (nullableOptions == null || nullableOptions.length == 0) {
+            return "";
+        }
+
+        final StringBuilder builder = new StringBuilder();
+        final int nOptions = nullableOptions.length;
+        int i = 0;
+        for (String option : nullableOptions) {
+            builder.append('"').append(option).append('"');
+            if (++i < nOptions) {
+                builder.append(", ");
+            }
+        }
+        return builder.toString();
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiProxy.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiProxy.java b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiProxy.java
index a8b8912..5df0a7b 100644
--- a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiProxy.java
+++ b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiProxy.java
@@ -44,6 +44,8 @@ public class ApiProxy {
 
     private ExtraOption[] extraOptions;
 
+    private String[] nullableOptions;
+
     private List<ApiMethodAlias> aliases = Collections.emptyList();
 
     public String getApiName() {
@@ -110,6 +112,14 @@ public class ApiProxy {
         this.extraOptions = extraOptions;
     }
 
+    public String[] getNullableOptions() {
+        return nullableOptions;
+    }
+
+    public void setNullableOptions(String[] nullableOptions) {
+        this.nullableOptions = nullableOptions;
+    }
+
     public List<ApiMethodAlias> getAliases() {
         return aliases;
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/DocumentGeneratorMojo.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/DocumentGeneratorMojo.java b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/DocumentGeneratorMojo.java
index cdd1e1a..ff155ca 100644
--- a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/DocumentGeneratorMojo.java
+++ b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/DocumentGeneratorMojo.java
@@ -458,18 +458,21 @@ public class DocumentGeneratorMojo extends AbstractGeneratorMojo implements Mave
     private static String getCanonicalName(ParameterizedType fieldType) {
         final Type[] typeArguments = fieldType.getActualTypeArguments();
 
-        if (typeArguments.length > 0) {
+        final int nArguments = typeArguments.length;
+        if (nArguments > 0) {
             final StringBuilder result = new StringBuilder(getCanonicalName((Class<?>) fieldType.getRawType()));
             result.append("&lt;");
+            int i = 0;
             for (Type typeArg : typeArguments) {
                 if (typeArg instanceof ParameterizedType) {
                     result.append(getCanonicalName((ParameterizedType) typeArg));
                 } else {
                     result.append(getCanonicalName((Class<?>) typeArg));
                 }
-                result.append(',');
+                if (++i < nArguments) {
+                    result.append(',');
+                }
             }
-            result.deleteCharAt(result.length() - 1);
             result.append("&gt;");
             return result.toString();
         }

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
index 7cf74d6..bf58017 100644
--- a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
+++ b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
@@ -285,19 +285,22 @@ public class JavadocApiMethodGeneratorMojo extends AbstractApiMethodGeneratorMoj
             }
 
             // make sure number of types and names match
-            if (typeList.size() != argNames.size()) {
+            final int nTypes = typeList.size();
+            if (nTypes != argNames.size()) {
                 throw new IllegalArgumentException("Unexpected Javadoc error, different number of arg types and names");
             }
 
-            final String[] names = argNames.toArray(new String[argNames.size()]);
-            StringBuilder builder = new StringBuilder("(");
+            final String[] names = argNames.toArray(new String[nTypes]);
+            final StringBuilder builder = new StringBuilder("(");
             int i = 0;
             for (String type : typeList) {
                 // split on space or non-breaking space
-                builder.append(type).append(" ").append(names[i++]).append(",");
+                builder.append(type).append(' ').append(names[i++]);
+                if (i < nTypes) {
+                    builder.append(',');
+                }
             }
-            builder.deleteCharAt(builder.length() - 1);
-            builder.append(")");
+            builder.append(')');
             return builder.toString();
         }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-collection.vm
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-collection.vm b/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-collection.vm
index 1b73e7f..6d5b850 100644
--- a/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-collection.vm
+++ b/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-collection.vm
@@ -21,7 +21,9 @@
  */
 package $packageName;
 
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 #set( $componentConfig = "${componentName}Configuration" )
@@ -42,6 +44,7 @@ public final class $collectionName extends ApiCollection<${apiNameEnum}, ${compo
 
     private ${collectionName}() {
         final Map<String, String> aliases = new HashMap<String, String>();
+        List<String> nullableArgs;
 #foreach( $api in $apis )
 
         aliases.clear();
@@ -50,7 +53,8 @@ public final class $collectionName extends ApiCollection<${apiNameEnum}, ${compo
 #end
 #set( $apiMethod = ${helper.getApiMethod($api.ProxyClass)} )
 #set( $apiName = "${apiNameEnum}.${helper.getEnumConstant($api.ApiName)}" )
-        apis.put($apiName, new ApiMethodHelper<$apiMethod>(${apiMethod}.class, aliases));
+        nullableArgs = Arrays.asList(${helper.getNullableOptionValues($api.NullableOptions)});
+        apis.put($apiName, new ApiMethodHelper<$apiMethod>(${apiMethod}.class, aliases, nullableArgs));
         apiMethods.put(${apiMethod}.class, ${apiName});
 #end
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-document.vm
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-document.vm b/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-document.vm
index 9e14962..5f65a00 100644
--- a/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-document.vm
+++ b/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-document.vm
@@ -69,7 +69,7 @@
     <hr/>
     <p>
         The ${componentName} Component can be configured with the options below.
-        These options can be provided using the component's bean property <code>configuration</code> of type <code>$componentConfiguration.Name</code>.
+        These options can be provided using the component's bean property <code>configuration</code> of type <code>$componentConfig.Name</code>.
     </p>
     <table>
         <tr>
@@ -98,6 +98,7 @@
 #end
     <p>
         Endpoint options that are not mandatory are denoted by [].
+        When there are no mandatory options for an endpoint, one of the set of [] options MUST be provided.
         Producer endpoints can also use a special option <b><code>inBody</code></b> that in turn should contain
         the name of the endpoint option whose value will be contained in the Camel Exchange In message.
     </p>
@@ -129,6 +130,14 @@
     </table>
     <h3>URI Options</h3>
     <hr/>
+#set ( $nullableArguments = $apiHelpers.get("").NullableArguments )
+#if( !$nullableArguments.isEmpty )
+    <p>
+        If a value is not provided for one of the option(s) ${nullableArguments.toString()}
+        either in the endpoint URI or in a message header, it will be assumed to be <code>null</code>.
+        Note that the <code>null</code> value(s) will only be used if other options do not satisfy matching endpoints.
+    </p>
+#end
     <table>
         <tr>
             <th>Name</th>
@@ -159,7 +168,8 @@
             <th>Result Body Type</th>
         </tr>
 #set( $endpointConfig = $apiConfigs.get($apiName) )
-#set( $endpoints = $helper.getEndpoints($apiMethod.Value, $apiHelpers.get($apiName), $endpointConfig) )
+#set( $anApiHelper = $apiHelpers.get($apiName) )
+#set( $endpoints = $helper.getEndpoints($apiMethod.Value, $anApiHelper, $endpointConfig) )
 #foreach( $endpoint in $endpoints )
         <tr>
             <td>$endpoint.Endpoint</td>
@@ -171,6 +181,14 @@
     </table>
     <h4>URI Options for <em>$apiName</em></h4>
     <hr/>
+#set ( $nullableArguments = $anApiHelper.NullableArguments )
+#if( !$nullableArguments.Empty )
+    <p>
+        If a value is not provided for one of the option(s) ${nullableArguments.toString()}
+        either in the endpoint URI or in a message header, it will be assumed to be <code>null</code>.
+        Note that the <code>null</code> value(s) will only be used if other options do not satisfy matching endpoints.
+    </p>
+#end
     <table>
         <tr>
             <th>Name</th>

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-route-test.vm
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-route-test.vm b/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-route-test.vm
index 5c91def..90e54f4 100644
--- a/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-route-test.vm
+++ b/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-route-test.vm
@@ -34,7 +34,7 @@ import ${packageName}.${componentName}ApiCollection;
 import ${packageName}.${enumName};
 
 /**
- * Test class for $proxyType.Name APIs.
+ * Test class for {@link ${proxyType.Name}} APIs.
  * TODO Move the file to src/test/java, populate parameter values, and remove @Ignore annotations.
  * The class source won't be generated again if the generator MOJO finds it under src/test/java.
  */

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/ApiComponentGeneratorMojoTest.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/ApiComponentGeneratorMojoTest.java b/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/ApiComponentGeneratorMojoTest.java
index cfb460d..52cf975 100644
--- a/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/ApiComponentGeneratorMojoTest.java
+++ b/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/ApiComponentGeneratorMojoTest.java
@@ -52,6 +52,7 @@ public class ApiComponentGeneratorMojoTest extends AbstractGeneratorMojoTest {
         // exclude name2, and int times
         mojo.apis[0].setExcludeConfigNames("name2");
         mojo.apis[0].setExcludeConfigTypes("int");
+        mojo.apis[0].setNullableOptions(new String[] {"namesList"});
 
         List<ApiMethodAlias> aliases = new ArrayList<ApiMethodAlias>();
         aliases.add(new ApiMethodAlias("get(.+)", "$1"));


[06/23] camel git commit: Added Salesforce component

Posted by dh...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/GlobalObjects.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/GlobalObjects.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/GlobalObjects.java
new file mode 100644
index 0000000..302e54e
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/GlobalObjects.java
@@ -0,0 +1,57 @@
+/**
+ * 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.api.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+
+import java.util.List;
+
+@XStreamAlias("DescribeGlobal")
+public class GlobalObjects extends AbstractDTOBase {
+
+    private String encoding;
+    private Integer maxBatchSize;
+
+    @XStreamImplicit
+    private List<SObject> sobjects;
+
+    public String getEncoding() {
+        return encoding;
+    }
+
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    public Integer getMaxBatchSize() {
+        return maxBatchSize;
+    }
+
+    public void setMaxBatchSize(Integer maxBatchSize) {
+        this.maxBatchSize = maxBatchSize;
+    }
+
+    public List<SObject> getSobjects() {
+        return sobjects;
+    }
+
+    public void setSobjects(List<SObject> sobjects) {
+        this.sobjects = sobjects;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/PickListValue.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/PickListValue.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/PickListValue.java
new file mode 100644
index 0000000..7816848
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/PickListValue.java
@@ -0,0 +1,70 @@
+/**
+ * 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.api.dto;
+
+/**
+ * Salesforce DTO for picklist value.
+ */
+public class PickListValue {
+
+    private String value;
+    private String label;
+    private Boolean active;
+    private Boolean defaultValue;
+    private String validFor;
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    public Boolean getActive() {
+        return active;
+    }
+
+    public void setActive(Boolean active) {
+        this.active = active;
+    }
+
+    public Boolean getDefaultValue() {
+        return defaultValue;
+    }
+
+    public void setDefaultValue(Boolean defaultValue) {
+        this.defaultValue = defaultValue;
+    }
+
+    public String getValidFor() {
+        return validFor;
+    }
+
+    public void setValidFor(String validFor) {
+        this.validFor = validFor;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RecentItem.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RecentItem.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RecentItem.java
new file mode 100644
index 0000000..503c363
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RecentItem.java
@@ -0,0 +1,56 @@
+/**
+ * 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.api.dto;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+public class RecentItem extends AbstractDTOBase {
+
+    private Attributes attributes;
+
+    private String Id;
+
+    private String Name;
+
+    public Attributes getAttributes() {
+        return attributes;
+    }
+
+    public void setAttributes(Attributes attributes) {
+        this.attributes = attributes;
+    }
+
+    @JsonProperty("Id")
+    public String getId() {
+        return Id;
+    }
+
+    @JsonProperty("Id")
+    public void setId(String id) {
+        Id = id;
+    }
+
+    @JsonProperty("Name")
+    public String getName() {
+        return Name;
+    }
+
+    @JsonProperty("Name")
+    public void setName(String name) {
+        Name = name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RecordTypeInfo.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RecordTypeInfo.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RecordTypeInfo.java
new file mode 100644
index 0000000..7b8d997
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RecordTypeInfo.java
@@ -0,0 +1,56 @@
+/**
+ * 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.api.dto;
+
+public class RecordTypeInfo extends AbstractDTOBase {
+    private String name;
+    private Boolean available;
+    private String recordTypeId;
+    private Boolean defaultRecordTypeMapping;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Boolean isAvailable() {
+        return available;
+    }
+
+    public void setAvailable(Boolean available) {
+        this.available = available;
+    }
+
+    public String getRecordTypeId() {
+        return recordTypeId;
+    }
+
+    public void setRecordTypeId(String recordTypeId) {
+        this.recordTypeId = recordTypeId;
+    }
+
+    public Boolean isDefaultRecordTypeMapping() {
+        return defaultRecordTypeMapping;
+    }
+
+    public void setDefaultRecordTypeMapping(Boolean defaultRecordTypeMapping) {
+        this.defaultRecordTypeMapping = defaultRecordTypeMapping;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestError.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestError.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestError.java
new file mode 100644
index 0000000..e155f05
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestError.java
@@ -0,0 +1,68 @@
+/**
+ * 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.api.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+
+import java.util.List;
+
+public class RestError extends AbstractDTOBase {
+    private String errorCode;
+    private String message;
+    @XStreamImplicit
+    private List<String> fields;
+
+    // default ctor for unmarshalling
+    public RestError() {
+        super();
+    }
+
+    public RestError(String errorCode, String message, List<String> fields) {
+        this(errorCode, message);
+        this.fields = fields;
+    }
+
+    public RestError(String errorCode, String message) {
+        this.errorCode = errorCode;
+        this.message = message;
+    }
+
+    public String getErrorCode() {
+        return errorCode;
+    }
+
+    public void setErrorCode(String errorCode) {
+        this.errorCode = errorCode;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public List<String> getFields() {
+        return fields;
+    }
+
+    public void setFields(List<String> fields) {
+        this.fields = fields;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestResources.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestResources.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestResources.java
new file mode 100644
index 0000000..9e7c644
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/RestResources.java
@@ -0,0 +1,100 @@
+/**
+ * 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.api.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+
+/**
+ * DTO for Salesforce Resources.
+ */
+@XStreamAlias("urls")
+public class RestResources extends AbstractDTOBase {
+
+    private String sobjects;
+    private String identity;
+    private String connect;
+    private String search;
+    private String query;
+    private String chatter;
+    private String recent;
+    private String tooling;
+
+    public String getSobjects() {
+        return sobjects;
+    }
+
+    public void setSobjects(String sobjects) {
+        this.sobjects = sobjects;
+    }
+
+    public String getIdentity() {
+        return identity;
+    }
+
+    public void setIdentity(String identity) {
+        this.identity = identity;
+    }
+
+    public String getConnect() {
+        return connect;
+    }
+
+    public void setConnect(String connect) {
+        this.connect = connect;
+    }
+
+    public String getSearch() {
+        return search;
+    }
+
+    public void setSearch(String search) {
+        this.search = search;
+    }
+
+    public String getQuery() {
+        return query;
+    }
+
+    public void setQuery(String query) {
+        this.query = query;
+    }
+
+    public String getChatter() {
+        return chatter;
+    }
+
+    public void setChatter(String chatter) {
+        this.chatter = chatter;
+    }
+
+    public String getRecent() {
+        return recent;
+    }
+
+    public void setRecent(String recent) {
+        this.recent = recent;
+    }
+
+    public String getTooling() {
+        return tooling;
+    }
+
+    public void setTooling(String tooling) {
+        this.tooling = tooling;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObject.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObject.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObject.java
new file mode 100644
index 0000000..0ad6962
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObject.java
@@ -0,0 +1,237 @@
+/**
+ * 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.api.dto;
+
+public class SObject extends AbstractDTOBase {
+    private String name;
+    private String label;
+    private Boolean updateable;
+    private String keyPrefix;
+    private Boolean custom;
+    private SObjectUrls urls;
+    private Boolean searchable;
+    private String labelPlural;
+    private Boolean layoutable;
+    private Boolean activateable;
+    private Boolean createable;
+    private Boolean deprecatedAndHidden;
+    private Boolean deletable;
+    private Boolean customSetting;
+    private Boolean feedEnabled;
+    private String listviewable;
+    private String lookupLayoutable;
+    private Boolean mergeable;
+    private Boolean queryable;
+    private Boolean replicateable;
+    private Boolean retrieveable;
+    private String searchLayoutable;
+    private Boolean undeletable;
+    private Boolean triggerable;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    public Boolean isUpdateable() {
+        return updateable;
+    }
+
+    public void setUpdateable(Boolean updateable) {
+        this.updateable = updateable;
+    }
+
+    public String getKeyPrefix() {
+        return keyPrefix;
+    }
+
+    public void setKeyPrefix(String keyPrefix) {
+        this.keyPrefix = keyPrefix;
+    }
+
+    public Boolean isCustom() {
+        return custom;
+    }
+
+    public void setCustom(Boolean custom) {
+        this.custom = custom;
+    }
+
+    public SObjectUrls getUrls() {
+        return urls;
+    }
+
+    public void setUrls(SObjectUrls urls) {
+        this.urls = urls;
+    }
+
+    public Boolean isSearchable() {
+        return searchable;
+    }
+
+    public void setSearchable(Boolean searchable) {
+        this.searchable = searchable;
+    }
+
+    public String getLabelPlural() {
+        return labelPlural;
+    }
+
+    public void setLabelPlural(String labelPlural) {
+        this.labelPlural = labelPlural;
+    }
+
+    public Boolean isLayoutable() {
+        return layoutable;
+    }
+
+    public void setLayoutable(Boolean layoutable) {
+        this.layoutable = layoutable;
+    }
+
+    public Boolean isActivateable() {
+        return activateable;
+    }
+
+    public void setActivateable(Boolean activateable) {
+        this.activateable = activateable;
+    }
+
+    public Boolean isCreateable() {
+        return createable;
+    }
+
+    public void setCreateable(Boolean createable) {
+        this.createable = createable;
+    }
+
+    public Boolean isDeprecatedAndHidden() {
+        return deprecatedAndHidden;
+    }
+
+    public void setDeprecatedAndHidden(Boolean deprecatedAndHidden) {
+        this.deprecatedAndHidden = deprecatedAndHidden;
+    }
+
+    public Boolean isDeletable() {
+        return deletable;
+    }
+
+    public void setDeletable(Boolean deletable) {
+        this.deletable = deletable;
+    }
+
+    public Boolean isCustomSetting() {
+        return customSetting;
+    }
+
+    public void setCustomSetting(Boolean customSetting) {
+        this.customSetting = customSetting;
+    }
+
+    public Boolean isFeedEnabled() {
+        return feedEnabled;
+    }
+
+    public void setFeedEnabled(Boolean feedEnabled) {
+        this.feedEnabled = feedEnabled;
+    }
+
+    public String getListviewable() {
+        return listviewable;
+    }
+
+    public void setListviewable(String listviewable) {
+        this.listviewable = listviewable;
+    }
+
+    public String getLookupLayoutable() {
+        return lookupLayoutable;
+    }
+
+    public void setLookupLayoutable(String lookupLayoutable) {
+        this.lookupLayoutable = lookupLayoutable;
+    }
+
+    public Boolean isMergeable() {
+        return mergeable;
+    }
+
+    public void setMergeable(Boolean mergeable) {
+        this.mergeable = mergeable;
+    }
+
+    public Boolean isQueryable() {
+        return queryable;
+    }
+
+    public void setQueryable(Boolean queryable) {
+        this.queryable = queryable;
+    }
+
+    public Boolean isReplicateable() {
+        return replicateable;
+    }
+
+    public void setReplicateable(Boolean replicateable) {
+        this.replicateable = replicateable;
+    }
+
+    public Boolean isRetrieveable() {
+        return retrieveable;
+    }
+
+    public void setRetrieveable(Boolean retrieveable) {
+        this.retrieveable = retrieveable;
+    }
+
+    public String getSearchLayoutable() {
+        return searchLayoutable;
+    }
+
+    public void setSearchLayoutable(String searchLayoutable) {
+        this.searchLayoutable = searchLayoutable;
+    }
+
+    public Boolean isUndeletable() {
+        return undeletable;
+    }
+
+    public void setUndeletable(Boolean undeletable) {
+        this.undeletable = undeletable;
+    }
+
+    public Boolean isTriggerable() {
+        return triggerable;
+    }
+
+    public void setTriggerable(Boolean triggerable) {
+        this.triggerable = triggerable;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectBasicInfo.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectBasicInfo.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectBasicInfo.java
new file mode 100644
index 0000000..b31708c
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectBasicInfo.java
@@ -0,0 +1,46 @@
+/**
+ * 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.api.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+
+import java.util.List;
+
+public class SObjectBasicInfo extends AbstractDTOBase {
+
+    private SObject objectDescribe;
+
+    @XStreamImplicit
+    private List<RecentItem> recentItems;
+
+    public SObject getObjectDescribe() {
+        return objectDescribe;
+    }
+
+    public void setObjectDescribe(SObject objectDescribe) {
+        this.objectDescribe = objectDescribe;
+    }
+
+    public List<RecentItem> getRecentItems() {
+        return recentItems;
+    }
+
+    public void setRecentItems(List<RecentItem> recentItems) {
+        this.recentItems = recentItems;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectDescription.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectDescription.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectDescription.java
new file mode 100644
index 0000000..5177f4a
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectDescription.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.salesforce.api.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+
+import java.util.List;
+
+public class SObjectDescription extends SObject {
+
+    @XStreamImplicit
+    private List<SObjectField> fields;
+
+    private SObjectDescriptionUrls urls;
+
+    @XStreamImplicit
+    private List<ChildRelationShip> childRelationships;
+
+    @XStreamImplicit
+    private List<RecordTypeInfo> recordTypeInfos;
+
+    public List<SObjectField> getFields() {
+        return fields;
+    }
+
+    public void setFields(List<SObjectField> fields) {
+        this.fields = fields;
+    }
+
+    public SObjectDescriptionUrls getUrls() {
+        return urls;
+    }
+
+    public void setUrls(SObjectDescriptionUrls urls) {
+        this.urls = urls;
+    }
+
+    public List<ChildRelationShip> getChildRelationships() {
+        return childRelationships;
+    }
+
+    public void setChildRelationships(List<ChildRelationShip> childRelationships) {
+        this.childRelationships = childRelationships;
+    }
+
+    public List<RecordTypeInfo> getRecordTypeInfos() {
+        return recordTypeInfos;
+    }
+
+    public void setRecordTypeInfos(List<RecordTypeInfo> recordTypeInfos) {
+        this.recordTypeInfos = recordTypeInfos;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectDescriptionUrls.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectDescriptionUrls.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectDescriptionUrls.java
new file mode 100644
index 0000000..3fe7503
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectDescriptionUrls.java
@@ -0,0 +1,47 @@
+/**
+ * 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.api.dto;
+
+public class SObjectDescriptionUrls extends SObjectUrls {
+    private String uiEditTemplate;
+    private String uiDetailTemplate;
+    private String uiNewRecord;
+
+    public String getUiEditTemplate() {
+        return uiEditTemplate;
+    }
+
+    public void setUiEditTemplate(String uiEditTemplate) {
+        this.uiEditTemplate = uiEditTemplate;
+    }
+
+    public String getUiDetailTemplate() {
+        return uiDetailTemplate;
+    }
+
+    public void setUiDetailTemplate(String uiDetailTemplate) {
+        this.uiDetailTemplate = uiDetailTemplate;
+    }
+
+    public String getUiNewRecord() {
+        return uiNewRecord;
+    }
+
+    public void setUiNewRecord(String uiNewRecord) {
+        this.uiNewRecord = uiNewRecord;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectField.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectField.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectField.java
new file mode 100644
index 0000000..379365d
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectField.java
@@ -0,0 +1,414 @@
+/**
+ * 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.api.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+
+import java.util.List;
+
+public class SObjectField extends AbstractDTOBase {
+
+    private Integer length;
+    private String name;
+    private String type;
+    private String defaultValue;
+    private String label;
+    private Boolean updateable;
+    private Boolean calculated;
+    private Boolean caseSensitive;
+    private String controllerName;
+    private Boolean unique;
+    private Boolean nillable;
+    private Integer precision;
+    private Integer scale;
+    private Integer byteLength;
+    private Boolean nameField;
+    private Boolean sortable;
+    private Boolean filterable;
+    private Boolean writeRequiresMasterRead;
+    private Boolean externalId;
+    private Boolean idLookup;
+    private String inlineHelpText;
+    private Boolean createable;
+    private String soapType;
+    private Boolean autoNumber;
+    private Boolean restrictedPicklist;
+    private Boolean namePointing;
+    private Boolean custom;
+    private Boolean defaultedOnCreate;
+    private Boolean deprecatedAndHidden;
+    private Boolean htmlFormatted;
+    private String defaultValueFormula;
+    private String calculatedFormula;
+    @XStreamImplicit
+    private List<PickListValue> picklistValues;
+    private Boolean dependentPicklist;
+    @XStreamImplicit
+    private List<String> referenceTo;
+    private String relationshipName;
+    private String relationshipOrder;
+    private Boolean cascadeDelete;
+    private Boolean restrictedDelete;
+    private String digits;
+    private Boolean groupable;
+    private Boolean permissionable;
+    private Boolean displayLocationInDecimal;
+
+    public Integer getLength() {
+        return length;
+    }
+
+    public void setLength(Integer length) {
+        this.length = length;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getDefaultValue() {
+        return defaultValue;
+    }
+
+    public void setDefaultValue(String defaultValue) {
+        this.defaultValue = defaultValue;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    public Boolean isUpdateable() {
+        return updateable;
+    }
+
+    public void setUpdateable(Boolean updateable) {
+        this.updateable = updateable;
+    }
+
+    public Boolean isCalculated() {
+        return calculated;
+    }
+
+    public void setCalculated(Boolean calculated) {
+        this.calculated = calculated;
+    }
+
+    public Boolean isCaseSensitive() {
+        return caseSensitive;
+    }
+
+    public void setCaseSensitive(Boolean caseSensitive) {
+        this.caseSensitive = caseSensitive;
+    }
+
+    public String getControllerName() {
+        return controllerName;
+    }
+
+    public void setControllerName(String controllerName) {
+        this.controllerName = controllerName;
+    }
+
+    public Boolean isUnique() {
+        return unique;
+    }
+
+    public void setUnique(Boolean unique) {
+        this.unique = unique;
+    }
+
+    public Boolean isNillable() {
+        return nillable;
+    }
+
+    public void setNillable(Boolean nillable) {
+        this.nillable = nillable;
+    }
+
+    public Integer getPrecision() {
+        return precision;
+    }
+
+    public void setPrecision(Integer precision) {
+        this.precision = precision;
+    }
+
+    public Integer getScale() {
+        return scale;
+    }
+
+    public void setScale(Integer scale) {
+        this.scale = scale;
+    }
+
+    public Integer getByteLength() {
+        return byteLength;
+    }
+
+    public void setByteLength(Integer byteLength) {
+        this.byteLength = byteLength;
+    }
+
+    public Boolean isNameField() {
+        return nameField;
+    }
+
+    public void setNameField(Boolean nameField) {
+        this.nameField = nameField;
+    }
+
+    public Boolean isSortable() {
+        return sortable;
+    }
+
+    public void setSortable(Boolean sortable) {
+        this.sortable = sortable;
+    }
+
+    public Boolean isFilterable() {
+        return filterable;
+    }
+
+    public void setFilterable(Boolean filterable) {
+        this.filterable = filterable;
+    }
+
+    public Boolean isWriteRequiresMasterRead() {
+        return writeRequiresMasterRead;
+    }
+
+    public void setWriteRequiresMasterRead(Boolean writeRequiresMasterRead) {
+        this.writeRequiresMasterRead = writeRequiresMasterRead;
+    }
+
+    public Boolean isExternalId() {
+        return externalId;
+    }
+
+    public void setExternalId(Boolean externalId) {
+        this.externalId = externalId;
+    }
+
+    public Boolean isIdLookup() {
+        return idLookup;
+    }
+
+    public void setIdLookup(Boolean idLookup) {
+        this.idLookup = idLookup;
+    }
+
+    public String getInlineHelpText() {
+        return inlineHelpText;
+    }
+
+    public void setInlineHelpText(String inlineHelpText) {
+        this.inlineHelpText = inlineHelpText;
+    }
+
+    public Boolean isCreateable() {
+        return createable;
+    }
+
+    public void setCreateable(Boolean createable) {
+        this.createable = createable;
+    }
+
+    public String getSoapType() {
+        return soapType;
+    }
+
+    public void setSoapType(String soapType) {
+        this.soapType = soapType;
+    }
+
+    public Boolean isAutoNumber() {
+        return autoNumber;
+    }
+
+    public void setAutoNumber(Boolean autoNumber) {
+        this.autoNumber = autoNumber;
+    }
+
+    public Boolean isRestrictedPicklist() {
+        return restrictedPicklist;
+    }
+
+    public void setRestrictedPicklist(Boolean restrictedPicklist) {
+        this.restrictedPicklist = restrictedPicklist;
+    }
+
+    public Boolean isNamePointing() {
+        return namePointing;
+    }
+
+    public void setNamePointing(Boolean namePointing) {
+        this.namePointing = namePointing;
+    }
+
+    public Boolean isCustom() {
+        return custom;
+    }
+
+    public void setCustom(Boolean custom) {
+        this.custom = custom;
+    }
+
+    public Boolean isDefaultedOnCreate() {
+        return defaultedOnCreate;
+    }
+
+    public void setDefaultedOnCreate(Boolean defaultedOnCreate) {
+        this.defaultedOnCreate = defaultedOnCreate;
+    }
+
+    public Boolean isDeprecatedAndHidden() {
+        return deprecatedAndHidden;
+    }
+
+    public void setDeprecatedAndHidden(Boolean deprecatedAndHidden) {
+        this.deprecatedAndHidden = deprecatedAndHidden;
+    }
+
+    public Boolean isHtmlFormatted() {
+        return htmlFormatted;
+    }
+
+    public void setHtmlFormatted(Boolean htmlFormatted) {
+        this.htmlFormatted = htmlFormatted;
+    }
+
+    public String getDefaultValueFormula() {
+        return defaultValueFormula;
+    }
+
+    public void setDefaultValueFormula(String defaultValueFormula) {
+        this.defaultValueFormula = defaultValueFormula;
+    }
+
+    public String getCalculatedFormula() {
+        return calculatedFormula;
+    }
+
+    public void setCalculatedFormula(String calculatedFormula) {
+        this.calculatedFormula = calculatedFormula;
+    }
+
+    public List<PickListValue> getPicklistValues() {
+        return picklistValues;
+    }
+
+    public void setPicklistValues(List<PickListValue> picklistValues) {
+        this.picklistValues = picklistValues;
+    }
+
+    public Boolean isDependentPicklist() {
+        return dependentPicklist;
+    }
+
+    public void setDependentPicklist(Boolean dependentPicklist) {
+        this.dependentPicklist = dependentPicklist;
+    }
+
+    public List<String> getReferenceTo() {
+        return referenceTo;
+    }
+
+    public void setReferenceTo(List<String> referenceTo) {
+        this.referenceTo = referenceTo;
+    }
+
+    public String getRelationshipName() {
+        return relationshipName;
+    }
+
+    public void setRelationshipName(String relationshipName) {
+        this.relationshipName = relationshipName;
+    }
+
+    public String getRelationshipOrder() {
+        return relationshipOrder;
+    }
+
+    public void setRelationshipOrder(String relationshipOrder) {
+        this.relationshipOrder = relationshipOrder;
+    }
+
+    public Boolean isCascadeDelete() {
+        return cascadeDelete;
+    }
+
+    public void setCascadeDelete(Boolean cascadeDelete) {
+        this.cascadeDelete = cascadeDelete;
+    }
+
+    public Boolean isRestrictedDelete() {
+        return restrictedDelete;
+    }
+
+    public void setRestrictedDelete(Boolean restrictedDelete) {
+        this.restrictedDelete = restrictedDelete;
+    }
+
+    public String getDigits() {
+        return digits;
+    }
+
+    public void setDigits(String digits) {
+        this.digits = digits;
+    }
+
+    public Boolean isGroupable() {
+        return groupable;
+    }
+
+    public void setGroupable(Boolean groupable) {
+        this.groupable = groupable;
+    }
+
+    public Boolean isPermissionable() {
+        return permissionable;
+    }
+
+    public void setPermissionable(Boolean permissionable) {
+        this.permissionable = permissionable;
+    }
+
+    public Boolean isDisplayLocationInDecimal() {
+        return displayLocationInDecimal;
+    }
+
+    public void setDisplayLocationInDecimal(Boolean displayLocationInDecimal) {
+        this.displayLocationInDecimal = displayLocationInDecimal;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectUrls.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectUrls.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectUrls.java
new file mode 100644
index 0000000..14b2f06
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SObjectUrls.java
@@ -0,0 +1,56 @@
+/**
+ * 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.api.dto;
+
+public class SObjectUrls extends AbstractDTOBase {
+    private String sobject;
+    private String describe;
+    private String rowTemplate;
+    private String passwordUtilities;
+
+    public String getSobject() {
+        return sobject;
+    }
+
+    public void setSobject(String sobject) {
+        this.sobject = sobject;
+    }
+
+    public String getDescribe() {
+        return describe;
+    }
+
+    public void setDescribe(String describe) {
+        this.describe = describe;
+    }
+
+    public String getRowTemplate() {
+        return rowTemplate;
+    }
+
+    public void setRowTemplate(String rowTemplate) {
+        this.rowTemplate = rowTemplate;
+    }
+
+    public String getPasswordUtilities() {
+        return passwordUtilities;
+    }
+
+    public void setPasswordUtilities(String passwordUtilities) {
+        this.passwordUtilities = passwordUtilities;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SearchResult.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SearchResult.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SearchResult.java
new file mode 100644
index 0000000..d6fb673
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SearchResult.java
@@ -0,0 +1,49 @@
+/**
+ * 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.api.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * DTO for Salesforce SOSL Search result record.
+ */
+@XStreamAlias("SearchResult")
+public final class SearchResult extends AbstractDTOBase {
+
+    private Attributes attributes;
+    private String Id;
+
+    public Attributes getAttributes() {
+        return attributes;
+    }
+
+    public void setAttributes(Attributes attributes) {
+        this.attributes = attributes;
+    }
+
+    @JsonProperty("Id")
+    public String getId() {
+        return Id;
+    }
+
+    @JsonProperty("Id")
+    public void setId(String id) {
+        Id = id;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SearchResults.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SearchResults.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SearchResults.java
new file mode 100644
index 0000000..18fb680
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SearchResults.java
@@ -0,0 +1,41 @@
+/**
+ * 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.api.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+
+import java.util.List;
+
+/**
+ * DTO for Salesforce SOSL Search results.
+ */
+@XStreamAlias("SearchResults")
+public final class SearchResults extends AbstractDTOBase {
+
+    @XStreamImplicit(itemFieldName = "SearchResult")
+    private List<SearchResult> results;
+
+    public List<SearchResult> getResults() {
+        return results;
+    }
+
+    public void setResults(List<SearchResult> results) {
+        this.results = results;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Version.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Version.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Version.java
new file mode 100644
index 0000000..08e4031
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Version.java
@@ -0,0 +1,52 @@
+/**
+ * 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.api.dto;
+
+/**
+ * DTO for Salesforce version API
+ */
+public class Version extends AbstractDTOBase {
+
+    private String label;
+    private String url;
+    private String version;
+
+    public String getLabel() {
+        return label;
+    }
+
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Versions.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Versions.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Versions.java
new file mode 100644
index 0000000..1349eb8
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Versions.java
@@ -0,0 +1,40 @@
+/**
+ * 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.api.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+
+import java.util.List;
+
+/**
+ * DTO for Salesforce versions
+ */
+@XStreamAlias("Versions")
+public class Versions extends AbstractDTOBase {
+
+    @XStreamImplicit(itemFieldName = "Version")
+    private List<Version> versions;
+
+    public List<Version> getVersions() {
+        return versions;
+    }
+
+    public void setVersions(List<Version> versions) {
+        this.versions = versions;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/BatchInfo.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/BatchInfo.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/BatchInfo.java
new file mode 100644
index 0000000..2a78b22
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/BatchInfo.java
@@ -0,0 +1,342 @@
+/**
+ * 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.api.dto.bulk;
+
+import javax.xml.bind.annotation.*;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+
+/**
+ * <p>Java class for BatchInfo complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="BatchInfo">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="id" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         &lt;element name="jobId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         &lt;element name="state" type="{http://www.force.com/2009/06/asyncapi/dataload}BatchStateEnum"/>
+ *         &lt;element name="stateMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         &lt;element name="createdDate" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+ *         &lt;element name="systemModstamp" type="{http://www.w3.org/2001/XMLSchema}dateTime" minOccurs="0"/>
+ *         &lt;element name="numberRecordsProcessed" type="{http://www.w3.org/2001/XMLSchema}int"/>
+ *         &lt;element name="numberRecordsFailed" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
+ *         &lt;element name="totalProcessingTime" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
+ *         &lt;element name="apiActiveProcessingTime" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
+ *         &lt;element name="apexProcessingTime" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "BatchInfo", propOrder = {
+    "id",
+    "jobId",
+    "state",
+    "stateMessage",
+    "createdDate",
+    "systemModstamp",
+    "numberRecordsProcessed",
+    "numberRecordsFailed",
+    "totalProcessingTime",
+    "apiActiveProcessingTime",
+    "apexProcessingTime"
+})
+public class BatchInfo {
+
+    @XmlElement(required = true)
+    protected String id;
+    @XmlElement(required = true)
+    protected String jobId;
+    @XmlElement(required = true)
+    protected BatchStateEnum state;
+    protected String stateMessage;
+    @XmlElement(required = true)
+    @XmlSchemaType(name = "dateTime")
+    protected XMLGregorianCalendar createdDate;
+    @XmlSchemaType(name = "dateTime")
+    protected XMLGregorianCalendar systemModstamp;
+    protected int numberRecordsProcessed;
+    protected Integer numberRecordsFailed;
+    protected Long totalProcessingTime;
+    protected Long apiActiveProcessingTime;
+    protected Long apexProcessingTime;
+
+    /**
+     * Gets the value of the id property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Sets the value of the id property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setId(String value) {
+        this.id = value;
+    }
+
+    /**
+     * Gets the value of the jobId property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getJobId() {
+        return jobId;
+    }
+
+    /**
+     * Sets the value of the jobId property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setJobId(String value) {
+        this.jobId = value;
+    }
+
+    /**
+     * Gets the value of the state property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link BatchStateEnum }
+     *
+     */
+    public BatchStateEnum getState() {
+        return state;
+    }
+
+    /**
+     * Sets the value of the state property.
+     *
+     * @param value
+     *     allowed object is
+     *     {@link BatchStateEnum }
+     *
+     */
+    public void setState(BatchStateEnum value) {
+        this.state = value;
+    }
+
+    /**
+     * Gets the value of the stateMessage property.
+     *
+     * @return
+     *     possible object is
+     *     {@link String }
+     *
+     */
+    public String getStateMessage() {
+        return stateMessage;
+    }
+
+    /**
+     * Sets the value of the stateMessage property.
+     *
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *
+     */
+    public void setStateMessage(String value) {
+        this.stateMessage = value;
+    }
+
+    /**
+     * Gets the value of the createdDate property.
+     *
+     * @return
+     *     possible object is
+     *     {@link javax.xml.datatype.XMLGregorianCalendar }
+     *
+     */
+    public XMLGregorianCalendar getCreatedDate() {
+        return createdDate;
+    }
+
+    /**
+     * Sets the value of the createdDate property.
+     *
+     * @param value
+     *     allowed object is
+     *     {@link javax.xml.datatype.XMLGregorianCalendar }
+     *
+     */
+    public void setCreatedDate(XMLGregorianCalendar value) {
+        this.createdDate = value;
+    }
+
+    /**
+     * Gets the value of the systemModstamp property.
+     *
+     * @return
+     *     possible object is
+     *     {@link javax.xml.datatype.XMLGregorianCalendar }
+     *
+     */
+    public XMLGregorianCalendar getSystemModstamp() {
+        return systemModstamp;
+    }
+
+    /**
+     * Sets the value of the systemModstamp property.
+     *
+     * @param value
+     *     allowed object is
+     *     {@link javax.xml.datatype.XMLGregorianCalendar }
+     *     
+     */
+    public void setSystemModstamp(XMLGregorianCalendar value) {
+        this.systemModstamp = value;
+    }
+
+    /**
+     * Gets the value of the numberRecordsProcessed property.
+     * 
+     */
+    public int getNumberRecordsProcessed() {
+        return numberRecordsProcessed;
+    }
+
+    /**
+     * Sets the value of the numberRecordsProcessed property.
+     * 
+     */
+    public void setNumberRecordsProcessed(int value) {
+        this.numberRecordsProcessed = value;
+    }
+
+    /**
+     * Gets the value of the numberRecordsFailed property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public Integer getNumberRecordsFailed() {
+        return numberRecordsFailed;
+    }
+
+    /**
+     * Sets the value of the numberRecordsFailed property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setNumberRecordsFailed(Integer value) {
+        this.numberRecordsFailed = value;
+    }
+
+    /**
+     * Gets the value of the totalProcessingTime property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Long }
+     *     
+     */
+    public Long getTotalProcessingTime() {
+        return totalProcessingTime;
+    }
+
+    /**
+     * Sets the value of the totalProcessingTime property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Long }
+     *     
+     */
+    public void setTotalProcessingTime(Long value) {
+        this.totalProcessingTime = value;
+    }
+
+    /**
+     * Gets the value of the apiActiveProcessingTime property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Long }
+     *     
+     */
+    public Long getApiActiveProcessingTime() {
+        return apiActiveProcessingTime;
+    }
+
+    /**
+     * Sets the value of the apiActiveProcessingTime property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Long }
+     *     
+     */
+    public void setApiActiveProcessingTime(Long value) {
+        this.apiActiveProcessingTime = value;
+    }
+
+    /**
+     * Gets the value of the apexProcessingTime property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Long }
+     *     
+     */
+    public Long getApexProcessingTime() {
+        return apexProcessingTime;
+    }
+
+    /**
+     * Sets the value of the apexProcessingTime property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Long }
+     *     
+     */
+    public void setApexProcessingTime(Long value) {
+        this.apexProcessingTime = value;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/BatchInfoList.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/BatchInfoList.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/BatchInfoList.java
new file mode 100644
index 0000000..de73632
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/BatchInfoList.java
@@ -0,0 +1,82 @@
+/**
+ * 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.api.dto.bulk;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlType;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * <p>Java class for BatchInfoList complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="BatchInfoList">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="batchInfo" type="{http://www.force.com/2009/06/asyncapi/dataload}BatchInfo" maxOccurs="unbounded" minOccurs="0"/>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "BatchInfoList", propOrder = {
+    "batchInfo"
+})
+public class BatchInfoList {
+
+    protected List<BatchInfo> batchInfo;
+
+    /**
+     * Gets the value of the batchInfo property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the batchInfo property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getBatchInfo().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link BatchInfo }
+     * 
+     * 
+     */
+    public List<BatchInfo> getBatchInfo() {
+        if (batchInfo == null) {
+            batchInfo = new ArrayList<BatchInfo>();
+        }
+        return this.batchInfo;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/BatchResult.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/BatchResult.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/BatchResult.java
new file mode 100644
index 0000000..f7a7f72
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/BatchResult.java
@@ -0,0 +1,82 @@
+/**
+ * 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.api.dto.bulk;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlType;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * <p>Java class for BatchResult complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="BatchResult">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="result" type="{http://www.force.com/2009/06/asyncapi/dataload}Result" maxOccurs="unbounded" minOccurs="0"/>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "BatchResult", propOrder = {
+    "result"
+})
+public class BatchResult {
+
+    protected List<Result> result;
+
+    /**
+     * Gets the value of the result property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the result property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getResult().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Result }
+     * 
+     * 
+     */
+    public List<Result> getResult() {
+        if (result == null) {
+            result = new ArrayList<Result>();
+        }
+        return this.result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/BatchStateEnum.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/BatchStateEnum.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/BatchStateEnum.java
new file mode 100644
index 0000000..1914ec0
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/BatchStateEnum.java
@@ -0,0 +1,75 @@
+/**
+ * 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.api.dto.bulk;
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlEnumValue;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for BatchStateEnum.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p>
+ * <pre>
+ * &lt;simpleType name="BatchStateEnum">
+ *   &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     &lt;enumeration value="Queued"/>
+ *     &lt;enumeration value="InProgress"/>
+ *     &lt;enumeration value="Completed"/>
+ *     &lt;enumeration value="Failed"/>
+ *     &lt;enumeration value="NotProcessed"/>
+ *   &lt;/restriction>
+ * &lt;/simpleType>
+ * </pre>
+ * 
+ */
+@XmlType(name = "BatchStateEnum")
+@XmlEnum
+public enum BatchStateEnum {
+
+    @XmlEnumValue("Queued")
+    QUEUED("Queued"),
+    @XmlEnumValue("InProgress")
+    IN_PROGRESS("InProgress"),
+    @XmlEnumValue("Completed")
+    COMPLETED("Completed"),
+    @XmlEnumValue("Failed")
+    FAILED("Failed"),
+    @XmlEnumValue("NotProcessed")
+    NOT_PROCESSED("NotProcessed");
+    private final String value;
+
+    BatchStateEnum(String v) {
+        value = v;
+    }
+
+    public String value() {
+        return value;
+    }
+
+    public static BatchStateEnum fromValue(String v) {
+        for (BatchStateEnum c: BatchStateEnum.values()) {
+            if (c.value.equals(v)) {
+                return c;
+            }
+        }
+        throw new IllegalArgumentException(v);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/ConcurrencyModeEnum.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/ConcurrencyModeEnum.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/ConcurrencyModeEnum.java
new file mode 100644
index 0000000..879bb37
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/ConcurrencyModeEnum.java
@@ -0,0 +1,66 @@
+/**
+ * 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.api.dto.bulk;
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlEnumValue;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for ConcurrencyModeEnum.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p>
+ * <pre>
+ * &lt;simpleType name="ConcurrencyModeEnum">
+ *   &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     &lt;enumeration value="Parallel"/>
+ *     &lt;enumeration value="Serial"/>
+ *   &lt;/restriction>
+ * &lt;/simpleType>
+ * </pre>
+ * 
+ */
+@XmlType(name = "ConcurrencyModeEnum")
+@XmlEnum
+public enum ConcurrencyModeEnum {
+
+    @XmlEnumValue("Parallel")
+    PARALLEL("Parallel"),
+    @XmlEnumValue("Serial")
+    SERIAL("Serial");
+    private final String value;
+
+    ConcurrencyModeEnum(String v) {
+        value = v;
+    }
+
+    public String value() {
+        return value;
+    }
+
+    public static ConcurrencyModeEnum fromValue(String v) {
+        for (ConcurrencyModeEnum c: ConcurrencyModeEnum.values()) {
+            if (c.value.equals(v)) {
+                return c;
+            }
+        }
+        throw new IllegalArgumentException(v);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/ContentType.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/ContentType.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/ContentType.java
new file mode 100644
index 0000000..1a3c75e
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/ContentType.java
@@ -0,0 +1,57 @@
+/**
+ * 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.api.dto.bulk;
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for ContentType.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p>
+ * <pre>
+ * &lt;simpleType name="ContentType">
+ *   &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     &lt;enumeration value="XML"/>
+ *     &lt;enumeration value="CSV"/>
+ *     &lt;enumeration value="ZIP_XML"/>
+ *     &lt;enumeration value="ZIP_CSV"/>
+ *   &lt;/restriction>
+ * &lt;/simpleType>
+ * </pre>
+ * 
+ */
+@XmlType(name = "ContentType")
+@XmlEnum
+public enum ContentType {
+
+    XML,
+    CSV,
+    ZIP_XML,
+    ZIP_CSV;
+
+    public String value() {
+        return name();
+    }
+
+    public static ContentType fromValue(String v) {
+        return valueOf(v);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/Error.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/Error.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/Error.java
new file mode 100644
index 0000000..4a06fbb
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/Error.java
@@ -0,0 +1,105 @@
+/**
+ * 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.api.dto.bulk;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for Error complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="Error">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="exceptionCode" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         &lt;element name="exceptionMessage" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "Error", propOrder = {
+    "exceptionCode",
+    "exceptionMessage"
+})
+public class Error {
+
+    @XmlElement(required = true)
+    protected String exceptionCode;
+    @XmlElement(required = true)
+    protected String exceptionMessage;
+
+    /**
+     * Gets the value of the exceptionCode property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getExceptionCode() {
+        return exceptionCode;
+    }
+
+    /**
+     * Sets the value of the exceptionCode property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setExceptionCode(String value) {
+        this.exceptionCode = value;
+    }
+
+    /**
+     * Gets the value of the exceptionMessage property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getExceptionMessage() {
+        return exceptionMessage;
+    }
+
+    /**
+     * Sets the value of the exceptionMessage property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setExceptionMessage(String value) {
+        this.exceptionMessage = value;
+    }
+
+}


[05/23] camel git commit: Added Salesforce component

Posted by dh...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/JobInfo.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/JobInfo.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/JobInfo.java
new file mode 100644
index 0000000..568138c
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/JobInfo.java
@@ -0,0 +1,673 @@
+/**
+ * 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.api.dto.bulk;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+
+/**
+ * <p>Java class for JobInfo complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="JobInfo">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="id" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         &lt;element name="operation" type="{http://www.force.com/2009/06/asyncapi/dataload}OperationEnum" minOccurs="0"/>
+ *         &lt;element name="object" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         &lt;element name="createdById" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         &lt;element name="createdDate" type="{http://www.w3.org/2001/XMLSchema}dateTime" minOccurs="0"/>
+ *         &lt;element name="systemModstamp" type="{http://www.w3.org/2001/XMLSchema}dateTime" minOccurs="0"/>
+ *         &lt;element name="state" type="{http://www.force.com/2009/06/asyncapi/dataload}JobStateEnum" minOccurs="0"/>
+ *         &lt;element name="externalIdFieldName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         &lt;element name="concurrencyMode" type="{http://www.force.com/2009/06/asyncapi/dataload}ConcurrencyModeEnum" minOccurs="0"/>
+ *         &lt;element name="contentType" type="{http://www.force.com/2009/06/asyncapi/dataload}ContentType" minOccurs="0"/>
+ *         &lt;element name="numberBatchesQueued" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
+ *         &lt;element name="numberBatchesInProgress" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
+ *         &lt;element name="numberBatchesCompleted" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
+ *         &lt;element name="numberBatchesFailed" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
+ *         &lt;element name="numberBatchesTotal" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
+ *         &lt;element name="numberRecordsProcessed" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
+ *         &lt;element name="numberRetries" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
+ *         &lt;element name="apiVersion" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         &lt;element name="assignmentRuleId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         &lt;element name="numberRecordsFailed" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
+ *         &lt;element name="totalProcessingTime" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
+ *         &lt;element name="apiActiveProcessingTime" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
+ *         &lt;element name="apexProcessingTime" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "JobInfo", propOrder = {
+    "id",
+    "operation",
+    "object",
+    "createdById",
+    "createdDate",
+    "systemModstamp",
+    "state",
+    "externalIdFieldName",
+    "concurrencyMode",
+    "contentType",
+    "numberBatchesQueued",
+    "numberBatchesInProgress",
+    "numberBatchesCompleted",
+    "numberBatchesFailed",
+    "numberBatchesTotal",
+    "numberRecordsProcessed",
+    "numberRetries",
+    "apiVersion",
+    "assignmentRuleId",
+    "numberRecordsFailed",
+    "totalProcessingTime",
+    "apiActiveProcessingTime",
+    "apexProcessingTime"
+})
+public class JobInfo {
+
+    protected String id;
+    protected OperationEnum operation;
+    protected String object;
+    protected String createdById;
+    @XmlSchemaType(name = "dateTime")
+    protected XMLGregorianCalendar createdDate;
+    @XmlSchemaType(name = "dateTime")
+    protected XMLGregorianCalendar systemModstamp;
+    protected JobStateEnum state;
+    protected String externalIdFieldName;
+    protected ConcurrencyModeEnum concurrencyMode;
+    protected ContentType contentType;
+    protected Integer numberBatchesQueued;
+    protected Integer numberBatchesInProgress;
+    protected Integer numberBatchesCompleted;
+    protected Integer numberBatchesFailed;
+    protected Integer numberBatchesTotal;
+    protected Integer numberRecordsProcessed;
+    protected Integer numberRetries;
+    protected String apiVersion;
+    protected String assignmentRuleId;
+    protected Integer numberRecordsFailed;
+    protected Long totalProcessingTime;
+    protected Long apiActiveProcessingTime;
+    protected Long apexProcessingTime;
+
+    /**
+     * Gets the value of the id property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Sets the value of the id property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setId(String value) {
+        this.id = value;
+    }
+
+    /**
+     * Gets the value of the operation property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link OperationEnum }
+     *
+     */
+    public OperationEnum getOperation() {
+        return operation;
+    }
+
+    /**
+     * Sets the value of the operation property.
+     *
+     * @param value
+     *     allowed object is
+     *     {@link OperationEnum }
+     *
+     */
+    public void setOperation(OperationEnum value) {
+        this.operation = value;
+    }
+
+    /**
+     * Gets the value of the object property.
+     *
+     * @return
+     *     possible object is
+     *     {@link String }
+     *
+     */
+    public String getObject() {
+        return object;
+    }
+
+    /**
+     * Sets the value of the object property.
+     *
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *
+     */
+    public void setObject(String value) {
+        this.object = value;
+    }
+
+    /**
+     * Gets the value of the createdById property.
+     *
+     * @return
+     *     possible object is
+     *     {@link String }
+     *
+     */
+    public String getCreatedById() {
+        return createdById;
+    }
+
+    /**
+     * Sets the value of the createdById property.
+     *
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *
+     */
+    public void setCreatedById(String value) {
+        this.createdById = value;
+    }
+
+    /**
+     * Gets the value of the createdDate property.
+     *
+     * @return
+     *     possible object is
+     *     {@link javax.xml.datatype.XMLGregorianCalendar }
+     *
+     */
+    public XMLGregorianCalendar getCreatedDate() {
+        return createdDate;
+    }
+
+    /**
+     * Sets the value of the createdDate property.
+     *
+     * @param value
+     *     allowed object is
+     *     {@link javax.xml.datatype.XMLGregorianCalendar }
+     *
+     */
+    public void setCreatedDate(XMLGregorianCalendar value) {
+        this.createdDate = value;
+    }
+
+    /**
+     * Gets the value of the systemModstamp property.
+     *
+     * @return
+     *     possible object is
+     *     {@link javax.xml.datatype.XMLGregorianCalendar }
+     *
+     */
+    public XMLGregorianCalendar getSystemModstamp() {
+        return systemModstamp;
+    }
+
+    /**
+     * Sets the value of the systemModstamp property.
+     *
+     * @param value
+     *     allowed object is
+     *     {@link javax.xml.datatype.XMLGregorianCalendar }
+     *
+     */
+    public void setSystemModstamp(XMLGregorianCalendar value) {
+        this.systemModstamp = value;
+    }
+
+    /**
+     * Gets the value of the state property.
+     *
+     * @return
+     *     possible object is
+     *     {@link JobStateEnum }
+     *
+     */
+    public JobStateEnum getState() {
+        return state;
+    }
+
+    /**
+     * Sets the value of the state property.
+     *
+     * @param value
+     *     allowed object is
+     *     {@link JobStateEnum }
+     *
+     */
+    public void setState(JobStateEnum value) {
+        this.state = value;
+    }
+
+    /**
+     * Gets the value of the externalIdFieldName property.
+     *
+     * @return
+     *     possible object is
+     *     {@link String }
+     *
+     */
+    public String getExternalIdFieldName() {
+        return externalIdFieldName;
+    }
+
+    /**
+     * Sets the value of the externalIdFieldName property.
+     *
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *
+     */
+    public void setExternalIdFieldName(String value) {
+        this.externalIdFieldName = value;
+    }
+
+    /**
+     * Gets the value of the concurrencyMode property.
+     *
+     * @return
+     *     possible object is
+     *     {@link ConcurrencyModeEnum }
+     *
+     */
+    public ConcurrencyModeEnum getConcurrencyMode() {
+        return concurrencyMode;
+    }
+
+    /**
+     * Sets the value of the concurrencyMode property.
+     *
+     * @param value
+     *     allowed object is
+     *     {@link ConcurrencyModeEnum }
+     *
+     */
+    public void setConcurrencyMode(ConcurrencyModeEnum value) {
+        this.concurrencyMode = value;
+    }
+
+    /**
+     * Gets the value of the contentType property.
+     *
+     * @return
+     *     possible object is
+     *     {@link ContentType }
+     *
+     */
+    public ContentType getContentType() {
+        return contentType;
+    }
+
+    /**
+     * Sets the value of the contentType property.
+     *
+     * @param value
+     *     allowed object is
+     *     {@link ContentType }
+     *     
+     */
+    public void setContentType(ContentType value) {
+        this.contentType = value;
+    }
+
+    /**
+     * Gets the value of the numberBatchesQueued property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public Integer getNumberBatchesQueued() {
+        return numberBatchesQueued;
+    }
+
+    /**
+     * Sets the value of the numberBatchesQueued property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setNumberBatchesQueued(Integer value) {
+        this.numberBatchesQueued = value;
+    }
+
+    /**
+     * Gets the value of the numberBatchesInProgress property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public Integer getNumberBatchesInProgress() {
+        return numberBatchesInProgress;
+    }
+
+    /**
+     * Sets the value of the numberBatchesInProgress property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setNumberBatchesInProgress(Integer value) {
+        this.numberBatchesInProgress = value;
+    }
+
+    /**
+     * Gets the value of the numberBatchesCompleted property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public Integer getNumberBatchesCompleted() {
+        return numberBatchesCompleted;
+    }
+
+    /**
+     * Sets the value of the numberBatchesCompleted property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setNumberBatchesCompleted(Integer value) {
+        this.numberBatchesCompleted = value;
+    }
+
+    /**
+     * Gets the value of the numberBatchesFailed property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public Integer getNumberBatchesFailed() {
+        return numberBatchesFailed;
+    }
+
+    /**
+     * Sets the value of the numberBatchesFailed property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setNumberBatchesFailed(Integer value) {
+        this.numberBatchesFailed = value;
+    }
+
+    /**
+     * Gets the value of the numberBatchesTotal property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public Integer getNumberBatchesTotal() {
+        return numberBatchesTotal;
+    }
+
+    /**
+     * Sets the value of the numberBatchesTotal property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setNumberBatchesTotal(Integer value) {
+        this.numberBatchesTotal = value;
+    }
+
+    /**
+     * Gets the value of the numberRecordsProcessed property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public Integer getNumberRecordsProcessed() {
+        return numberRecordsProcessed;
+    }
+
+    /**
+     * Sets the value of the numberRecordsProcessed property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setNumberRecordsProcessed(Integer value) {
+        this.numberRecordsProcessed = value;
+    }
+
+    /**
+     * Gets the value of the numberRetries property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public Integer getNumberRetries() {
+        return numberRetries;
+    }
+
+    /**
+     * Sets the value of the numberRetries property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setNumberRetries(Integer value) {
+        this.numberRetries = value;
+    }
+
+    /**
+     * Gets the value of the apiVersion property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getApiVersion() {
+        return apiVersion;
+    }
+
+    /**
+     * Sets the value of the apiVersion property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setApiVersion(String value) {
+        this.apiVersion = value;
+    }
+
+    /**
+     * Gets the value of the assignmentRuleId property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getAssignmentRuleId() {
+        return assignmentRuleId;
+    }
+
+    /**
+     * Sets the value of the assignmentRuleId property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setAssignmentRuleId(String value) {
+        this.assignmentRuleId = value;
+    }
+
+    /**
+     * Gets the value of the numberRecordsFailed property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public Integer getNumberRecordsFailed() {
+        return numberRecordsFailed;
+    }
+
+    /**
+     * Sets the value of the numberRecordsFailed property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setNumberRecordsFailed(Integer value) {
+        this.numberRecordsFailed = value;
+    }
+
+    /**
+     * Gets the value of the totalProcessingTime property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Long }
+     *     
+     */
+    public Long getTotalProcessingTime() {
+        return totalProcessingTime;
+    }
+
+    /**
+     * Sets the value of the totalProcessingTime property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Long }
+     *     
+     */
+    public void setTotalProcessingTime(Long value) {
+        this.totalProcessingTime = value;
+    }
+
+    /**
+     * Gets the value of the apiActiveProcessingTime property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Long }
+     *     
+     */
+    public Long getApiActiveProcessingTime() {
+        return apiActiveProcessingTime;
+    }
+
+    /**
+     * Sets the value of the apiActiveProcessingTime property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Long }
+     *     
+     */
+    public void setApiActiveProcessingTime(Long value) {
+        this.apiActiveProcessingTime = value;
+    }
+
+    /**
+     * Gets the value of the apexProcessingTime property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Long }
+     *     
+     */
+    public Long getApexProcessingTime() {
+        return apexProcessingTime;
+    }
+
+    /**
+     * Sets the value of the apexProcessingTime property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Long }
+     *     
+     */
+    public void setApexProcessingTime(Long value) {
+        this.apexProcessingTime = value;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/JobStateEnum.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/JobStateEnum.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/JobStateEnum.java
new file mode 100644
index 0000000..474768c
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/JobStateEnum.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.salesforce.api.dto.bulk;
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlEnumValue;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for JobStateEnum.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p>
+ * <pre>
+ * &lt;simpleType name="JobStateEnum">
+ *   &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     &lt;enumeration value="Open"/>
+ *     &lt;enumeration value="Closed"/>
+ *     &lt;enumeration value="Aborted"/>
+ *     &lt;enumeration value="Failed"/>
+ *   &lt;/restriction>
+ * &lt;/simpleType>
+ * </pre>
+ * 
+ */
+@XmlType(name = "JobStateEnum")
+@XmlEnum
+public enum JobStateEnum {
+
+    @XmlEnumValue("Open")
+    OPEN("Open"),
+    @XmlEnumValue("Closed")
+    CLOSED("Closed"),
+    @XmlEnumValue("Aborted")
+    ABORTED("Aborted"),
+    @XmlEnumValue("Failed")
+    FAILED("Failed");
+    private final String value;
+
+    JobStateEnum(String v) {
+        value = v;
+    }
+
+    public String value() {
+        return value;
+    }
+
+    public static JobStateEnum fromValue(String v) {
+        for (JobStateEnum c: JobStateEnum.values()) {
+            if (c.value.equals(v)) {
+                return c;
+            }
+        }
+        throw new IllegalArgumentException(v);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/ObjectFactory.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/ObjectFactory.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/ObjectFactory.java
new file mode 100644
index 0000000..dc476ac
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/ObjectFactory.java
@@ -0,0 +1,200 @@
+/**
+ * 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.api.dto.bulk;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.annotation.XmlElementDecl;
+import javax.xml.bind.annotation.XmlRegistry;
+import javax.xml.namespace.QName;
+
+
+/**
+ * This object contains factory methods for each 
+ * Java content interface and Java element interface 
+ * in the org.apache.camel.component.salesforce.api.dto.bulk package.
+ * <p>An ObjectFactory allows you to programatically 
+ * construct new instances of the Java representation 
+ * for XML content. The Java representation of XML 
+ * content can consist of schema derived interfaces 
+ * and classes representing the binding of schema 
+ * type definitions, element declarations and model 
+ * groups.  Factory methods for each of these are 
+ * provided in this class.
+ * 
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+    private final static QName _JobInfo_QNAME = new QName("http://www.force.com/2009/06/asyncapi/dataload", "jobInfo");
+    private final static QName _BatchInfo_QNAME = new QName("http://www.force.com/2009/06/asyncapi/dataload", "batchInfo");
+    private final static QName _Error_QNAME = new QName("http://www.force.com/2009/06/asyncapi/dataload", "error");
+    private final static QName _Results_QNAME = new QName("http://www.force.com/2009/06/asyncapi/dataload", "results");
+    private final static QName _ResultList_QNAME = new QName("http://www.force.com/2009/06/asyncapi/dataload", "result-list");
+    private final static QName _BatchInfoList_QNAME = new QName("http://www.force.com/2009/06/asyncapi/dataload", "batchInfoList");
+    private final static QName _QueryResult_QNAME = new QName("http://www.force.com/2009/06/asyncapi/dataload", "queryResult");
+
+    /**
+     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.apache.camel.component.salesforce.api.dto.bulk
+     * 
+     */
+    public ObjectFactory() {
+    }
+
+    /**
+     * Create an instance of {@link SObject }
+     *
+     */
+    public SObject createSObject() {
+        return new SObject();
+    }
+
+    /**
+     * Create an instance of {@link ResultError }
+     *
+     */
+    public ResultError createResultError() {
+        return new ResultError();
+    }
+
+    /**
+     * Create an instance of {@link BatchInfo }
+     *
+     */
+    public BatchInfo createBatchInfo() {
+        return new BatchInfo();
+    }
+
+    /**
+     * Create an instance of {@link BatchResult }
+     *
+     */
+    public BatchResult createBatchResult() {
+        return new BatchResult();
+    }
+
+    /**
+     * Create an instance of {@link QueryResultList }
+     *
+     */
+    public QueryResultList createQueryResultList() {
+        return new QueryResultList();
+    }
+
+    /**
+     * Create an instance of {@link Error }
+     *
+     */
+    public Error createError() {
+        return new Error();
+    }
+
+    /**
+     * Create an instance of {@link BatchInfoList }
+     *
+     */
+    public BatchInfoList createBatchInfoList() {
+        return new BatchInfoList();
+    }
+
+    /**
+     * Create an instance of {@link Result }
+     *
+     */
+    public Result createResult() {
+        return new Result();
+    }
+
+    /**
+     * Create an instance of {@link JobInfo }
+     *
+     */
+    public JobInfo createJobInfo() {
+        return new JobInfo();
+    }
+
+    /**
+     * Create an instance of {@link QueryResult }
+     *
+     */
+    public QueryResult createQueryResult() {
+        return new QueryResult();
+    }
+
+    /**
+     * Create an instance of {@link javax.xml.bind.JAXBElement }{@code <}{@link JobInfo }{@code >}}
+     *
+     */
+    @XmlElementDecl(namespace = "http://www.force.com/2009/06/asyncapi/dataload", name = "jobInfo")
+    public JAXBElement<JobInfo> createJobInfo(JobInfo value) {
+        return new JAXBElement<JobInfo>(_JobInfo_QNAME, JobInfo.class, null, value);
+    }
+
+    /**
+     * Create an instance of {@link javax.xml.bind.JAXBElement }{@code <}{@link BatchInfo }{@code >}}
+     *
+     */
+    @XmlElementDecl(namespace = "http://www.force.com/2009/06/asyncapi/dataload", name = "batchInfo")
+    public JAXBElement<BatchInfo> createBatchInfo(BatchInfo value) {
+        return new JAXBElement<BatchInfo>(_BatchInfo_QNAME, BatchInfo.class, null, value);
+    }
+
+    /**
+     * Create an instance of {@link javax.xml.bind.JAXBElement }{@code <}{@link Error }{@code >}}
+     *
+     */
+    @XmlElementDecl(namespace = "http://www.force.com/2009/06/asyncapi/dataload", name = "error")
+    public JAXBElement<Error> createError(Error value) {
+        return new JAXBElement<Error>(_Error_QNAME, Error.class, null, value);
+    }
+
+    /**
+     * Create an instance of {@link javax.xml.bind.JAXBElement }{@code <}{@link BatchResult }{@code >}}
+     *
+     */
+    @XmlElementDecl(namespace = "http://www.force.com/2009/06/asyncapi/dataload", name = "results")
+    public JAXBElement<BatchResult> createResults(BatchResult value) {
+        return new JAXBElement<BatchResult>(_Results_QNAME, BatchResult.class, null, value);
+    }
+
+    /**
+     * Create an instance of {@link javax.xml.bind.JAXBElement }{@code <}{@link QueryResultList }{@code >}}
+     *
+     */
+    @XmlElementDecl(namespace = "http://www.force.com/2009/06/asyncapi/dataload", name = "result-list")
+    public JAXBElement<QueryResultList> createResultList(QueryResultList value) {
+        return new JAXBElement<QueryResultList>(_ResultList_QNAME, QueryResultList.class, null, value);
+    }
+
+    /**
+     * Create an instance of {@link javax.xml.bind.JAXBElement }{@code <}{@link BatchInfoList }{@code >}}
+     *
+     */
+    @XmlElementDecl(namespace = "http://www.force.com/2009/06/asyncapi/dataload", name = "batchInfoList")
+    public JAXBElement<BatchInfoList> createBatchInfoList(BatchInfoList value) {
+        return new JAXBElement<BatchInfoList>(_BatchInfoList_QNAME, BatchInfoList.class, null, value);
+    }
+
+    /**
+     * Create an instance of {@link javax.xml.bind.JAXBElement }{@code <}{@link QueryResult }{@code >}}
+     * 
+     */
+    @XmlElementDecl(namespace = "http://www.force.com/2009/06/asyncapi/dataload", name = "queryResult")
+    public JAXBElement<QueryResult> createQueryResult(QueryResult value) {
+        return new JAXBElement<QueryResult>(_QueryResult_QNAME, QueryResult.class, null, value);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/OperationEnum.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/OperationEnum.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/OperationEnum.java
new file mode 100644
index 0000000..3f25e66
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/OperationEnum.java
@@ -0,0 +1,78 @@
+/**
+ * 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.api.dto.bulk;
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlEnumValue;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for OperationEnum.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p>
+ * <pre>
+ * &lt;simpleType name="OperationEnum">
+ *   &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     &lt;enumeration value="insert"/>
+ *     &lt;enumeration value="upsert"/>
+ *     &lt;enumeration value="update"/>
+ *     &lt;enumeration value="delete"/>
+ *     &lt;enumeration value="hardDelete"/>
+ *     &lt;enumeration value="query"/>
+ *   &lt;/restriction>
+ * &lt;/simpleType>
+ * </pre>
+ * 
+ */
+@XmlType(name = "OperationEnum")
+@XmlEnum
+public enum OperationEnum {
+
+    @XmlEnumValue("insert")
+    INSERT("insert"),
+    @XmlEnumValue("upsert")
+    UPSERT("upsert"),
+    @XmlEnumValue("update")
+    UPDATE("update"),
+    @XmlEnumValue("delete")
+    DELETE("delete"),
+    @XmlEnumValue("hardDelete")
+    HARD_DELETE("hardDelete"),
+    @XmlEnumValue("query")
+    QUERY("query");
+    private final String value;
+
+    OperationEnum(String v) {
+        value = v;
+    }
+
+    public String value() {
+        return value;
+    }
+
+    public static OperationEnum fromValue(String v) {
+        for (OperationEnum c: OperationEnum.values()) {
+            if (c.value.equals(v)) {
+                return c;
+            }
+        }
+        throw new IllegalArgumentException(v);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/QueryResult.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/QueryResult.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/QueryResult.java
new file mode 100644
index 0000000..702d993
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/QueryResult.java
@@ -0,0 +1,84 @@
+/**
+ * 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.api.dto.bulk;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * <p>Java class for QueryResult complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="QueryResult">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="records" type="{http://www.force.com/2009/06/asyncapi/dataload}sObject" maxOccurs="unbounded" minOccurs="0"/>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "QueryResult", propOrder = {
+    "records"
+})
+public class QueryResult {
+
+    @XmlElement(nillable = true)
+    protected List<SObject> records;
+
+    /**
+     * Gets the value of the records property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the records property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getRecords().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link SObject }
+     * 
+     * 
+     */
+    public List<SObject> getRecords() {
+        if (records == null) {
+            records = new ArrayList<SObject>();
+        }
+        return this.records;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/QueryResultList.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/QueryResultList.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/QueryResultList.java
new file mode 100644
index 0000000..6dbda5a
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/QueryResultList.java
@@ -0,0 +1,82 @@
+/**
+ * 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.api.dto.bulk;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlType;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * <p>Java class for QueryResultList complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="QueryResultList">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="result" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "QueryResultList", propOrder = {
+    "result"
+})
+public class QueryResultList {
+
+    protected List<String> result;
+
+    /**
+     * Gets the value of the result property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the result property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getResult().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link String }
+     * 
+     * 
+     */
+    public List<String> getResult() {
+        if (result == null) {
+            result = new ArrayList<String>();
+        }
+        return this.result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/Result.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/Result.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/Result.java
new file mode 100644
index 0000000..c36d9aa
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/Result.java
@@ -0,0 +1,147 @@
+/**
+ * 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.api.dto.bulk;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlType;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * <p>Java class for Result complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="Result">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="errors" type="{http://www.force.com/2009/06/asyncapi/dataload}ResultError" maxOccurs="unbounded" minOccurs="0"/>
+ *         &lt;element name="id" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         &lt;element name="success" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ *         &lt;element name="created" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "Result", propOrder = {
+    "errors",
+    "id",
+    "success",
+    "created"
+})
+public class Result {
+
+    protected List<ResultError> errors;
+    protected String id;
+    protected boolean success;
+    protected boolean created;
+
+    /**
+     * Gets the value of the errors property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the errors property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getErrors().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link ResultError }
+     * 
+     * 
+     */
+    public List<ResultError> getErrors() {
+        if (errors == null) {
+            errors = new ArrayList<ResultError>();
+        }
+        return this.errors;
+    }
+
+    /**
+     * Gets the value of the id property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Sets the value of the id property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setId(String value) {
+        this.id = value;
+    }
+
+    /**
+     * Gets the value of the success property.
+     * 
+     */
+    public boolean isSuccess() {
+        return success;
+    }
+
+    /**
+     * Sets the value of the success property.
+     * 
+     */
+    public void setSuccess(boolean value) {
+        this.success = value;
+    }
+
+    /**
+     * Gets the value of the created property.
+     * 
+     */
+    public boolean isCreated() {
+        return created;
+    }
+
+    /**
+     * Sets the value of the created property.
+     * 
+     */
+    public void setCreated(boolean value) {
+        this.created = value;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/ResultError.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/ResultError.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/ResultError.java
new file mode 100644
index 0000000..fabccab
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/ResultError.java
@@ -0,0 +1,140 @@
+/**
+ * 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.api.dto.bulk;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * <p>Java class for ResultError complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="ResultError">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="fields" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ *         &lt;element name="message" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         &lt;element name="statusCode" type="{http://www.force.com/2009/06/asyncapi/dataload}StatusCode"/>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "ResultError", propOrder = {
+    "fields",
+    "message",
+    "statusCode"
+})
+public class ResultError {
+
+    @XmlElement(nillable = true)
+    protected List<String> fields;
+    @XmlElement(required = true)
+    protected String message;
+    @XmlElement(required = true)
+    protected StatusCode statusCode;
+
+    /**
+     * Gets the value of the fields property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the fields property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getFields().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link String }
+     * 
+     * 
+     */
+    public List<String> getFields() {
+        if (fields == null) {
+            fields = new ArrayList<String>();
+        }
+        return this.fields;
+    }
+
+    /**
+     * Gets the value of the message property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getMessage() {
+        return message;
+    }
+
+    /**
+     * Sets the value of the message property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setMessage(String value) {
+        this.message = value;
+    }
+
+    /**
+     * Gets the value of the statusCode property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link StatusCode }
+     *
+     */
+    public StatusCode getStatusCode() {
+        return statusCode;
+    }
+
+    /**
+     * Sets the value of the statusCode property.
+     *
+     * @param value
+     *     allowed object is
+     *     {@link StatusCode }
+     *     
+     */
+    public void setStatusCode(StatusCode value) {
+        this.statusCode = value;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/SObject.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/SObject.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/SObject.java
new file mode 100644
index 0000000..aa9c2c5
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/SObject.java
@@ -0,0 +1,138 @@
+/**
+ * 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.api.dto.bulk;
+
+import javax.xml.bind.annotation.*;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * <p>Java class for sObject complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="sObject">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="type" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         &lt;element name="Id" type="{http://www.force.com/2009/06/asyncapi/dataload}ID"/>
+ *         &lt;any processContents='lax' namespace='http://www.force.com/2009/06/asyncapi/dataload' maxOccurs="unbounded" minOccurs="0"/>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "sObject", propOrder = {
+    "type",
+    "id",
+    "any"
+})
+public class SObject {
+
+    @XmlElement(required = true)
+    protected String type;
+    @XmlElement(name = "Id", required = true, nillable = true)
+    protected String id;
+    @XmlAnyElement(lax = true)
+    protected List<Object> any;
+
+    /**
+     * Gets the value of the type property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * Sets the value of the type property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setType(String value) {
+        this.type = value;
+    }
+
+    /**
+     * Gets the value of the id property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Sets the value of the id property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setId(String value) {
+        this.id = value;
+    }
+
+    /**
+     * Gets the value of the any property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the any property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getAny().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Object }
+     * {@link org.w3c.dom.Element }
+     * 
+     * 
+     */
+    public List<Object> getAny() {
+        if (any == null) {
+            any = new ArrayList<Object>();
+        }
+        return this.any;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/StatusCode.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/StatusCode.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/StatusCode.java
new file mode 100644
index 0000000..d4e3493
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/StatusCode.java
@@ -0,0 +1,395 @@
+/**
+ * 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.api.dto.bulk;
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for StatusCode.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p>
+ * <pre>
+ * &lt;simpleType name="StatusCode">
+ *   &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     &lt;enumeration value="ALL_OR_NONE_OPERATION_ROLLED_BACK"/>
+ *     &lt;enumeration value="ALREADY_IN_PROCESS"/>
+ *     &lt;enumeration value="ASSIGNEE_TYPE_REQUIRED"/>
+ *     &lt;enumeration value="BAD_CUSTOM_ENTITY_PARENT_DOMAIN"/>
+ *     &lt;enumeration value="BCC_NOT_ALLOWED_IF_BCC_COMPLIANCE_ENABLED"/>
+ *     &lt;enumeration value="CANNOT_CASCADE_PRODUCT_ACTIVE"/>
+ *     &lt;enumeration value="CANNOT_CHANGE_FIELD_TYPE_OF_APEX_REFERENCED_FIELD"/>
+ *     &lt;enumeration value="CANNOT_CREATE_ANOTHER_MANAGED_PACKAGE"/>
+ *     &lt;enumeration value="CANNOT_DEACTIVATE_DIVISION"/>
+ *     &lt;enumeration value="CANNOT_DELETE_LAST_DATED_CONVERSION_RATE"/>
+ *     &lt;enumeration value="CANNOT_DELETE_MANAGED_OBJECT"/>
+ *     &lt;enumeration value="CANNOT_DISABLE_LAST_ADMIN"/>
+ *     &lt;enumeration value="CANNOT_ENABLE_IP_RESTRICT_REQUESTS"/>
+ *     &lt;enumeration value="CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY"/>
+ *     &lt;enumeration value="CANNOT_MODIFY_MANAGED_OBJECT"/>
+ *     &lt;enumeration value="CANNOT_RENAME_APEX_REFERENCED_FIELD"/>
+ *     &lt;enumeration value="CANNOT_RENAME_APEX_REFERENCED_OBJECT"/>
+ *     &lt;enumeration value="CANNOT_REPARENT_RECORD"/>
+ *     &lt;enumeration value="CANNOT_UPDATE_CONVERTED_LEAD"/>
+ *     &lt;enumeration value="CANT_DISABLE_CORP_CURRENCY"/>
+ *     &lt;enumeration value="CANT_UNSET_CORP_CURRENCY"/>
+ *     &lt;enumeration value="CHILD_SHARE_FAILS_PARENT"/>
+ *     &lt;enumeration value="CIRCULAR_DEPENDENCY"/>
+ *     &lt;enumeration value="COMMUNITY_NOT_ACCESSIBLE"/>
+ *     &lt;enumeration value="CUSTOM_CLOB_FIELD_LIMIT_EXCEEDED"/>
+ *     &lt;enumeration value="CUSTOM_ENTITY_OR_FIELD_LIMIT"/>
+ *     &lt;enumeration value="CUSTOM_FIELD_INDEX_LIMIT_EXCEEDED"/>
+ *     &lt;enumeration value="CUSTOM_INDEX_EXISTS"/>
+ *     &lt;enumeration value="CUSTOM_LINK_LIMIT_EXCEEDED"/>
+ *     &lt;enumeration value="CUSTOM_TAB_LIMIT_EXCEEDED"/>
+ *     &lt;enumeration value="DELETE_FAILED"/>
+ *     &lt;enumeration value="DELETE_OPERATION_TOO_LARGE"/>
+ *     &lt;enumeration value="DELETE_REQUIRED_ON_CASCADE"/>
+ *     &lt;enumeration value="DEPENDENCY_EXISTS"/>
+ *     &lt;enumeration value="DUPLICATE_CASE_SOLUTION"/>
+ *     &lt;enumeration value="DUPLICATE_COMM_NICKNAME"/>
+ *     &lt;enumeration value="DUPLICATE_CUSTOM_ENTITY_DEFINITION"/>
+ *     &lt;enumeration value="DUPLICATE_CUSTOM_TAB_MOTIF"/>
+ *     &lt;enumeration value="DUPLICATE_DEVELOPER_NAME"/>
+ *     &lt;enumeration value="DUPLICATE_EXTERNAL_ID"/>
+ *     &lt;enumeration value="DUPLICATE_MASTER_LABEL"/>
+ *     &lt;enumeration value="DUPLICATE_SENDER_DISPLAY_NAME"/>
+ *     &lt;enumeration value="DUPLICATE_USERNAME"/>
+ *     &lt;enumeration value="DUPLICATE_VALUE"/>
+ *     &lt;enumeration value="EMAIL_NOT_PROCESSED_DUE_TO_PRIOR_ERROR"/>
+ *     &lt;enumeration value="EMPTY_SCONTROL_FILE_NAME"/>
+ *     &lt;enumeration value="ENTITY_FAILED_IFLASTMODIFIED_ON_UPDATE"/>
+ *     &lt;enumeration value="ENTITY_IS_ARCHIVED"/>
+ *     &lt;enumeration value="ENTITY_IS_DELETED"/>
+ *     &lt;enumeration value="ENTITY_IS_LOCKED"/>
+ *     &lt;enumeration value="ERROR_IN_MAILER"/>
+ *     &lt;enumeration value="EXTERNAL_OBJECT_AUTHENTICATION_EXCEPTION"/>
+ *     &lt;enumeration value="EXTERNAL_OBJECT_CONNECTION_EXCEPTION"/>
+ *     &lt;enumeration value="EXTERNAL_OBJECT_EXCEPTION"/>
+ *     &lt;enumeration value="EXTERNAL_OBJECT_UNSUPPORTED_EXCEPTION"/>
+ *     &lt;enumeration value="FAILED_ACTIVATION"/>
+ *     &lt;enumeration value="FIELD_CUSTOM_VALIDATION_EXCEPTION"/>
+ *     &lt;enumeration value="FIELD_FILTER_VALIDATION_EXCEPTION"/>
+ *     &lt;enumeration value="FIELD_INTEGRITY_EXCEPTION"/>
+ *     &lt;enumeration value="FILTERED_LOOKUP_LIMIT_EXCEEDED"/>
+ *     &lt;enumeration value="HTML_FILE_UPLOAD_NOT_ALLOWED"/>
+ *     &lt;enumeration value="IMAGE_TOO_LARGE"/>
+ *     &lt;enumeration value="INACTIVE_OWNER_OR_USER"/>
+ *     &lt;enumeration value="INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY"/>
+ *     &lt;enumeration value="INSUFFICIENT_ACCESS_OR_READONLY"/>
+ *     &lt;enumeration value="INVALID_ACCESS_LEVEL"/>
+ *     &lt;enumeration value="INVALID_ARGUMENT_TYPE"/>
+ *     &lt;enumeration value="INVALID_ASSIGNEE_TYPE"/>
+ *     &lt;enumeration value="INVALID_ASSIGNMENT_RULE"/>
+ *     &lt;enumeration value="INVALID_BATCH_OPERATION"/>
+ *     &lt;enumeration value="INVALID_CONTENT_TYPE"/>
+ *     &lt;enumeration value="INVALID_CREDIT_CARD_INFO"/>
+ *     &lt;enumeration value="INVALID_CROSS_REFERENCE_KEY"/>
+ *     &lt;enumeration value="INVALID_CROSS_REFERENCE_TYPE_FOR_FIELD"/>
+ *     &lt;enumeration value="INVALID_CURRENCY_CONV_RATE"/>
+ *     &lt;enumeration value="INVALID_CURRENCY_CORP_RATE"/>
+ *     &lt;enumeration value="INVALID_CURRENCY_ISO"/>
+ *     &lt;enumeration value="INVALID_DATA_CATEGORY_GROUP_REFERENCE"/>
+ *     &lt;enumeration value="INVALID_DATA_URI"/>
+ *     &lt;enumeration value="INVALID_EMAIL_ADDRESS"/>
+ *     &lt;enumeration value="INVALID_EMPTY_KEY_OWNER"/>
+ *     &lt;enumeration value="INVALID_FIELD"/>
+ *     &lt;enumeration value="INVALID_FIELD_FOR_INSERT_UPDATE"/>
+ *     &lt;enumeration value="INVALID_FIELD_WHEN_USING_TEMPLATE"/>
+ *     &lt;enumeration value="INVALID_FILTER_ACTION"/>
+ *     &lt;enumeration value="INVALID_GOOGLE_DOCS_URL"/>
+ *     &lt;enumeration value="INVALID_ID_FIELD"/>
+ *     &lt;enumeration value="INVALID_INET_ADDRESS"/>
+ *     &lt;enumeration value="INVALID_LINEITEM_CLONE_STATE"/>
+ *     &lt;enumeration value="INVALID_MASTER_OR_TRANSLATED_SOLUTION"/>
+ *     &lt;enumeration value="INVALID_MESSAGE_ID_REFERENCE"/>
+ *     &lt;enumeration value="INVALID_OPERATION"/>
+ *     &lt;enumeration value="INVALID_OPERATOR"/>
+ *     &lt;enumeration value="INVALID_OR_NULL_FOR_RESTRICTED_PICKLIST"/>
+ *     &lt;enumeration value="INVALID_PACKAGE_VERSION"/>
+ *     &lt;enumeration value="INVALID_PARTNER_NETWORK_STATUS"/>
+ *     &lt;enumeration value="INVALID_PERSON_ACCOUNT_OPERATION"/>
+ *     &lt;enumeration value="INVALID_QUERY_LOCATOR"/>
+ *     &lt;enumeration value="INVALID_READ_ONLY_USER_DML"/>
+ *     &lt;enumeration value="INVALID_SAVE_AS_ACTIVITY_FLAG"/>
+ *     &lt;enumeration value="INVALID_SESSION_ID"/>
+ *     &lt;enumeration value="INVALID_SETUP_OWNER"/>
+ *     &lt;enumeration value="INVALID_STATUS"/>
+ *     &lt;enumeration value="INVALID_TYPE"/>
+ *     &lt;enumeration value="INVALID_TYPE_FOR_OPERATION"/>
+ *     &lt;enumeration value="INVALID_TYPE_ON_FIELD_IN_RECORD"/>
+ *     &lt;enumeration value="IP_RANGE_LIMIT_EXCEEDED"/>
+ *     &lt;enumeration value="LICENSE_LIMIT_EXCEEDED"/>
+ *     &lt;enumeration value="LIGHT_PORTAL_USER_EXCEPTION"/>
+ *     &lt;enumeration value="LIMIT_EXCEEDED"/>
+ *     &lt;enumeration value="MALFORMED_ID"/>
+ *     &lt;enumeration value="MANAGER_NOT_DEFINED"/>
+ *     &lt;enumeration value="MASSMAIL_RETRY_LIMIT_EXCEEDED"/>
+ *     &lt;enumeration value="MASS_MAIL_LIMIT_EXCEEDED"/>
+ *     &lt;enumeration value="MAXIMUM_CCEMAILS_EXCEEDED"/>
+ *     &lt;enumeration value="MAXIMUM_DASHBOARD_COMPONENTS_EXCEEDED"/>
+ *     &lt;enumeration value="MAXIMUM_HIERARCHY_LEVELS_REACHED"/>
+ *     &lt;enumeration value="MAXIMUM_SIZE_OF_ATTACHMENT"/>
+ *     &lt;enumeration value="MAXIMUM_SIZE_OF_DOCUMENT"/>
+ *     &lt;enumeration value="MAX_ACTIONS_PER_RULE_EXCEEDED"/>
+ *     &lt;enumeration value="MAX_ACTIVE_RULES_EXCEEDED"/>
+ *     &lt;enumeration value="MAX_APPROVAL_STEPS_EXCEEDED"/>
+ *     &lt;enumeration value="MAX_FORMULAS_PER_RULE_EXCEEDED"/>
+ *     &lt;enumeration value="MAX_RULES_EXCEEDED"/>
+ *     &lt;enumeration value="MAX_RULE_ENTRIES_EXCEEDED"/>
+ *     &lt;enumeration value="MAX_TASK_DESCRIPTION_EXCEEEDED"/>
+ *     &lt;enumeration value="MAX_TM_RULES_EXCEEDED"/>
+ *     &lt;enumeration value="MAX_TM_RULE_ITEMS_EXCEEDED"/>
+ *     &lt;enumeration value="MERGE_FAILED"/>
+ *     &lt;enumeration value="MISSING_ARGUMENT"/>
+ *     &lt;enumeration value="MIXED_DML_OPERATION"/>
+ *     &lt;enumeration value="NONUNIQUE_SHIPPING_ADDRESS"/>
+ *     &lt;enumeration value="NO_APPLICABLE_PROCESS"/>
+ *     &lt;enumeration value="NO_ATTACHMENT_PERMISSION"/>
+ *     &lt;enumeration value="NO_INACTIVE_DIVISION_MEMBERS"/>
+ *     &lt;enumeration value="NO_MASS_MAIL_PERMISSION"/>
+ *     &lt;enumeration value="NUMBER_OUTSIDE_VALID_RANGE"/>
+ *     &lt;enumeration value="NUM_HISTORY_FIELDS_BY_SOBJECT_EXCEEDED"/>
+ *     &lt;enumeration value="OPTED_OUT_OF_MASS_MAIL"/>
+ *     &lt;enumeration value="OP_WITH_INVALID_USER_TYPE_EXCEPTION"/>
+ *     &lt;enumeration value="PACKAGE_LICENSE_REQUIRED"/>
+ *     &lt;enumeration value="PORTAL_NO_ACCESS"/>
+ *     &lt;enumeration value="PORTAL_USER_ALREADY_EXISTS_FOR_CONTACT"/>
+ *     &lt;enumeration value="PRIVATE_CONTACT_ON_ASSET"/>
+ *     &lt;enumeration value="QUERY_TIMEOUT"/>
+ *     &lt;enumeration value="RECORD_IN_USE_BY_WORKFLOW"/>
+ *     &lt;enumeration value="REQUEST_RUNNING_TOO_LONG"/>
+ *     &lt;enumeration value="REQUIRED_FEATURE_MISSING"/>
+ *     &lt;enumeration value="REQUIRED_FIELD_MISSING"/>
+ *     &lt;enumeration value="SELF_REFERENCE_FROM_TRIGGER"/>
+ *     &lt;enumeration value="SHARE_NEEDED_FOR_CHILD_OWNER"/>
+ *     &lt;enumeration value="SINGLE_EMAIL_LIMIT_EXCEEDED"/>
+ *     &lt;enumeration value="STANDARD_PRICE_NOT_DEFINED"/>
+ *     &lt;enumeration value="STORAGE_LIMIT_EXCEEDED"/>
+ *     &lt;enumeration value="STRING_TOO_LONG"/>
+ *     &lt;enumeration value="TABSET_LIMIT_EXCEEDED"/>
+ *     &lt;enumeration value="TEMPLATE_NOT_ACTIVE"/>
+ *     &lt;enumeration value="TERRITORY_REALIGN_IN_PROGRESS"/>
+ *     &lt;enumeration value="TEXT_DATA_OUTSIDE_SUPPORTED_CHARSET"/>
+ *     &lt;enumeration value="TOO_MANY_APEX_REQUESTS"/>
+ *     &lt;enumeration value="TOO_MANY_ENUM_VALUE"/>
+ *     &lt;enumeration value="TRANSFER_REQUIRES_READ"/>
+ *     &lt;enumeration value="UNABLE_TO_LOCK_ROW"/>
+ *     &lt;enumeration value="UNAVAILABLE_RECORDTYPE_EXCEPTION"/>
+ *     &lt;enumeration value="UNDELETE_FAILED"/>
+ *     &lt;enumeration value="UNKNOWN_EXCEPTION"/>
+ *     &lt;enumeration value="UNSPECIFIED_EMAIL_ADDRESS"/>
+ *     &lt;enumeration value="UNSUPPORTED_APEX_TRIGGER_OPERATON"/>
+ *     &lt;enumeration value="UNVERIFIED_SENDER_ADDRESS"/>
+ *     &lt;enumeration value="USER_OWNS_PORTAL_ACCOUNT_EXCEPTION"/>
+ *     &lt;enumeration value="USER_WITH_APEX_SHARES_EXCEPTION"/>
+ *     &lt;enumeration value="WEBLINK_SIZE_LIMIT_EXCEEDED"/>
+ *     &lt;enumeration value="WRONG_CONTROLLER_TYPE"/>
+ *   &lt;/restriction>
+ * &lt;/simpleType>
+ * </pre>
+ * 
+ */
+@XmlType(name = "StatusCode")
+@XmlEnum
+public enum StatusCode {
+
+    ALL_OR_NONE_OPERATION_ROLLED_BACK,
+    ALREADY_IN_PROCESS,
+    ASSIGNEE_TYPE_REQUIRED,
+    BAD_CUSTOM_ENTITY_PARENT_DOMAIN,
+    BCC_NOT_ALLOWED_IF_BCC_COMPLIANCE_ENABLED,
+    CANNOT_CASCADE_PRODUCT_ACTIVE,
+    CANNOT_CHANGE_FIELD_TYPE_OF_APEX_REFERENCED_FIELD,
+    CANNOT_CREATE_ANOTHER_MANAGED_PACKAGE,
+    CANNOT_DEACTIVATE_DIVISION,
+    CANNOT_DELETE_LAST_DATED_CONVERSION_RATE,
+    CANNOT_DELETE_MANAGED_OBJECT,
+    CANNOT_DISABLE_LAST_ADMIN,
+    CANNOT_ENABLE_IP_RESTRICT_REQUESTS,
+    CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY,
+    CANNOT_MODIFY_MANAGED_OBJECT,
+    CANNOT_RENAME_APEX_REFERENCED_FIELD,
+    CANNOT_RENAME_APEX_REFERENCED_OBJECT,
+    CANNOT_REPARENT_RECORD,
+    CANNOT_UPDATE_CONVERTED_LEAD,
+    CANT_DISABLE_CORP_CURRENCY,
+    CANT_UNSET_CORP_CURRENCY,
+    CHILD_SHARE_FAILS_PARENT,
+    CIRCULAR_DEPENDENCY,
+    COMMUNITY_NOT_ACCESSIBLE,
+    CUSTOM_CLOB_FIELD_LIMIT_EXCEEDED,
+    CUSTOM_ENTITY_OR_FIELD_LIMIT,
+    CUSTOM_FIELD_INDEX_LIMIT_EXCEEDED,
+    CUSTOM_INDEX_EXISTS,
+    CUSTOM_LINK_LIMIT_EXCEEDED,
+    CUSTOM_TAB_LIMIT_EXCEEDED,
+    DELETE_FAILED,
+    DELETE_OPERATION_TOO_LARGE,
+    DELETE_REQUIRED_ON_CASCADE,
+    DEPENDENCY_EXISTS,
+    DUPLICATE_CASE_SOLUTION,
+    DUPLICATE_COMM_NICKNAME,
+    DUPLICATE_CUSTOM_ENTITY_DEFINITION,
+    DUPLICATE_CUSTOM_TAB_MOTIF,
+    DUPLICATE_DEVELOPER_NAME,
+    DUPLICATE_EXTERNAL_ID,
+    DUPLICATE_MASTER_LABEL,
+    DUPLICATE_SENDER_DISPLAY_NAME,
+    DUPLICATE_USERNAME,
+    DUPLICATE_VALUE,
+    EMAIL_NOT_PROCESSED_DUE_TO_PRIOR_ERROR,
+    EMPTY_SCONTROL_FILE_NAME,
+    ENTITY_FAILED_IFLASTMODIFIED_ON_UPDATE,
+    ENTITY_IS_ARCHIVED,
+    ENTITY_IS_DELETED,
+    ENTITY_IS_LOCKED,
+    ERROR_IN_MAILER,
+    EXTERNAL_OBJECT_AUTHENTICATION_EXCEPTION,
+    EXTERNAL_OBJECT_CONNECTION_EXCEPTION,
+    EXTERNAL_OBJECT_EXCEPTION,
+    EXTERNAL_OBJECT_UNSUPPORTED_EXCEPTION,
+    FAILED_ACTIVATION,
+    FIELD_CUSTOM_VALIDATION_EXCEPTION,
+    FIELD_FILTER_VALIDATION_EXCEPTION,
+    FIELD_INTEGRITY_EXCEPTION,
+    FILTERED_LOOKUP_LIMIT_EXCEEDED,
+    HTML_FILE_UPLOAD_NOT_ALLOWED,
+    IMAGE_TOO_LARGE,
+    INACTIVE_OWNER_OR_USER,
+    INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY,
+    INSUFFICIENT_ACCESS_OR_READONLY,
+    INVALID_ACCESS_LEVEL,
+    INVALID_ARGUMENT_TYPE,
+    INVALID_ASSIGNEE_TYPE,
+    INVALID_ASSIGNMENT_RULE,
+    INVALID_BATCH_OPERATION,
+    INVALID_CONTENT_TYPE,
+    INVALID_CREDIT_CARD_INFO,
+    INVALID_CROSS_REFERENCE_KEY,
+    INVALID_CROSS_REFERENCE_TYPE_FOR_FIELD,
+    INVALID_CURRENCY_CONV_RATE,
+    INVALID_CURRENCY_CORP_RATE,
+    INVALID_CURRENCY_ISO,
+    INVALID_DATA_CATEGORY_GROUP_REFERENCE,
+    INVALID_DATA_URI,
+    INVALID_EMAIL_ADDRESS,
+    INVALID_EMPTY_KEY_OWNER,
+    INVALID_FIELD,
+    INVALID_FIELD_FOR_INSERT_UPDATE,
+    INVALID_FIELD_WHEN_USING_TEMPLATE,
+    INVALID_FILTER_ACTION,
+    INVALID_GOOGLE_DOCS_URL,
+    INVALID_ID_FIELD,
+    INVALID_INET_ADDRESS,
+    INVALID_LINEITEM_CLONE_STATE,
+    INVALID_MASTER_OR_TRANSLATED_SOLUTION,
+    INVALID_MESSAGE_ID_REFERENCE,
+    INVALID_OPERATION,
+    INVALID_OPERATOR,
+    INVALID_OR_NULL_FOR_RESTRICTED_PICKLIST,
+    INVALID_PACKAGE_VERSION,
+    INVALID_PARTNER_NETWORK_STATUS,
+    INVALID_PERSON_ACCOUNT_OPERATION,
+    INVALID_QUERY_LOCATOR,
+    INVALID_READ_ONLY_USER_DML,
+    INVALID_SAVE_AS_ACTIVITY_FLAG,
+    INVALID_SESSION_ID,
+    INVALID_SETUP_OWNER,
+    INVALID_STATUS,
+    INVALID_TYPE,
+    INVALID_TYPE_FOR_OPERATION,
+    INVALID_TYPE_ON_FIELD_IN_RECORD,
+    IP_RANGE_LIMIT_EXCEEDED,
+    LICENSE_LIMIT_EXCEEDED,
+    LIGHT_PORTAL_USER_EXCEPTION,
+    LIMIT_EXCEEDED,
+    MALFORMED_ID,
+    MANAGER_NOT_DEFINED,
+    MASSMAIL_RETRY_LIMIT_EXCEEDED,
+    MASS_MAIL_LIMIT_EXCEEDED,
+    MAXIMUM_CCEMAILS_EXCEEDED,
+    MAXIMUM_DASHBOARD_COMPONENTS_EXCEEDED,
+    MAXIMUM_HIERARCHY_LEVELS_REACHED,
+    MAXIMUM_SIZE_OF_ATTACHMENT,
+    MAXIMUM_SIZE_OF_DOCUMENT,
+    MAX_ACTIONS_PER_RULE_EXCEEDED,
+    MAX_ACTIVE_RULES_EXCEEDED,
+    MAX_APPROVAL_STEPS_EXCEEDED,
+    MAX_FORMULAS_PER_RULE_EXCEEDED,
+    MAX_RULES_EXCEEDED,
+    MAX_RULE_ENTRIES_EXCEEDED,
+    MAX_TASK_DESCRIPTION_EXCEEEDED,
+    MAX_TM_RULES_EXCEEDED,
+    MAX_TM_RULE_ITEMS_EXCEEDED,
+    MERGE_FAILED,
+    MISSING_ARGUMENT,
+    MIXED_DML_OPERATION,
+    NONUNIQUE_SHIPPING_ADDRESS,
+    NO_APPLICABLE_PROCESS,
+    NO_ATTACHMENT_PERMISSION,
+    NO_INACTIVE_DIVISION_MEMBERS,
+    NO_MASS_MAIL_PERMISSION,
+    NUMBER_OUTSIDE_VALID_RANGE,
+    NUM_HISTORY_FIELDS_BY_SOBJECT_EXCEEDED,
+    OPTED_OUT_OF_MASS_MAIL,
+    OP_WITH_INVALID_USER_TYPE_EXCEPTION,
+    PACKAGE_LICENSE_REQUIRED,
+    PORTAL_NO_ACCESS,
+    PORTAL_USER_ALREADY_EXISTS_FOR_CONTACT,
+    PRIVATE_CONTACT_ON_ASSET,
+    QUERY_TIMEOUT,
+    RECORD_IN_USE_BY_WORKFLOW,
+    REQUEST_RUNNING_TOO_LONG,
+    REQUIRED_FEATURE_MISSING,
+    REQUIRED_FIELD_MISSING,
+    SELF_REFERENCE_FROM_TRIGGER,
+    SHARE_NEEDED_FOR_CHILD_OWNER,
+    SINGLE_EMAIL_LIMIT_EXCEEDED,
+    STANDARD_PRICE_NOT_DEFINED,
+    STORAGE_LIMIT_EXCEEDED,
+    STRING_TOO_LONG,
+    TABSET_LIMIT_EXCEEDED,
+    TEMPLATE_NOT_ACTIVE,
+    TERRITORY_REALIGN_IN_PROGRESS,
+    TEXT_DATA_OUTSIDE_SUPPORTED_CHARSET,
+    TOO_MANY_APEX_REQUESTS,
+    TOO_MANY_ENUM_VALUE,
+    TRANSFER_REQUIRES_READ,
+    UNABLE_TO_LOCK_ROW,
+    UNAVAILABLE_RECORDTYPE_EXCEPTION,
+    UNDELETE_FAILED,
+    UNKNOWN_EXCEPTION,
+    UNSPECIFIED_EMAIL_ADDRESS,
+    UNSUPPORTED_APEX_TRIGGER_OPERATON,
+    UNVERIFIED_SENDER_ADDRESS,
+    USER_OWNS_PORTAL_ACCOUNT_EXCEPTION,
+    USER_WITH_APEX_SHARES_EXCEPTION,
+    WEBLINK_SIZE_LIMIT_EXCEEDED,
+    WRONG_CONTROLLER_TYPE;
+
+    public String value() {
+        return name();
+    }
+
+    public static StatusCode fromValue(String v) {
+        return valueOf(v);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/package-info.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/package-info.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/package-info.java
new file mode 100644
index 0000000..ae2b9ee
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/bulk/package-info.java
@@ -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.
+ */
+@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.force.com/2009/06/asyncapi/dataload", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
+package org.apache.camel.component.salesforce.api.dto.bulk;

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
new file mode 100644
index 0000000..50141f1
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
@@ -0,0 +1,71 @@
+/**
+ * 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.internal;
+
+public enum OperationName {
+
+    // rest API
+    GET_VERSIONS("getVersions"),
+    GET_RESOURCES("getResources"),
+    GET_GLOBAL_OBJECTS("getGlobalObjects"),
+    GET_BASIC_INFO("getBasicInfo"),
+    GET_DESCRIPTION("getDescription"),
+    GET_SOBJECT("getSObject"),
+    CREATE_SOBJECT("createSObject"),
+    UPDATE_SOBJECT("updateSObject"),
+    DELETE_SOBJECT("deleteSObject"),
+    GET_SOBJECT_WITH_ID("getSObjectWithId"),
+    UPSERT_SOBJECT("upsertSObject"),
+    DELETE_SOBJECT_WITH_ID("deleteSObjectWithId"),
+    GET_BLOB_FIELD("getBlobField"),
+    QUERY("query"),
+    QUERY_MORE("queryMore"),
+    SEARCH("search"),
+
+    // bulk API
+    CREATE_JOB("createJob"),
+    GET_JOB("getJob"),
+    CLOSE_JOB("closeJob"),
+    ABORT_JOB("abortJob"),
+    CREATE_BATCH("createBatch"),
+    GET_BATCH("getBatch"),
+    GET_ALL_BATCHES("getAllBatches"),
+    GET_REQUEST("getRequest"),
+    GET_RESULTS("getResults"),
+    CREATE_BATCH_QUERY("createBatchQuery"),
+    GET_QUERY_RESULT_IDS("getQueryResultIds"),
+    GET_QUERY_RESULT("getQueryResult");
+
+    private final String value;
+
+    private OperationName(String value) {
+        this.value = value;
+    }
+
+    public String value() {
+        return value;
+    }
+
+    public static OperationName fromValue(String value) {
+        for (OperationName operationName : OperationName.values()) {
+            if (operationName.value.equals(value)) {
+                return operationName;
+            }
+        }
+        throw new IllegalArgumentException(value);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/PayloadFormat.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/PayloadFormat.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/PayloadFormat.java
new file mode 100644
index 0000000..8555910
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/PayloadFormat.java
@@ -0,0 +1,22 @@
+/**
+ * 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.internal;
+
+public enum PayloadFormat {
+    JSON,
+    XML
+}


[04/23] camel git commit: Added Salesforce component

Posted by dh...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/SalesforceSession.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/SalesforceSession.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/SalesforceSession.java
new file mode 100644
index 0000000..a16a2a3
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/SalesforceSession.java
@@ -0,0 +1,336 @@
+/**
+ * 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.internal;
+
+import org.apache.camel.Service;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.eclipse.jetty.client.ContentExchange;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.http.HttpMethods;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.io.Buffer;
+import org.eclipse.jetty.io.ByteArrayBuffer;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.UrlEncoded;
+import org.apache.camel.component.salesforce.SalesforceLoginConfig;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.RestError;
+import org.apache.camel.component.salesforce.internal.dto.LoginError;
+import org.apache.camel.component.salesforce.internal.dto.LoginToken;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+public class SalesforceSession implements Service {
+
+    private static final String OAUTH2_REVOKE_PATH = "/services/oauth2/revoke?token=";
+    private static final String OAUTH2_TOKEN_PATH = "/services/oauth2/token";
+
+    private static final Logger LOG = LoggerFactory.getLogger(SalesforceSession.class);
+    private static final String FORM_CONTENT_TYPE = "application/x-www-form-urlencoded;charset=utf-8";
+
+    private final HttpClient httpClient;
+
+    private final SalesforceLoginConfig config;
+
+    private final ObjectMapper objectMapper;
+    private final Set<SalesforceSessionListener> listeners;
+
+    private String accessToken;
+    private String instanceUrl;
+
+    public SalesforceSession(HttpClient httpClient, SalesforceLoginConfig config) {
+        // validate parameters
+        assertNotNull("Null httpClient", httpClient);
+        assertNotNull("Null SalesforceLoginConfig", config);
+        assertNotNull("Null loginUrl", config.getLoginUrl());
+        assertNotNull("Null clientId", config.getClientId());
+        assertNotNull("Null clientSecret", config.getClientSecret());
+        assertNotNull("Null userName", config.getUserName());
+        assertNotNull("Null password", config.getPassword());
+
+        this.httpClient = httpClient;
+        this.config = config;
+
+        // strip trailing '/'
+        String loginUrl = config.getLoginUrl();
+        config.setLoginUrl(loginUrl.endsWith("/") ? loginUrl.substring(0, loginUrl.length() - 1) : loginUrl);
+
+        this.objectMapper = new ObjectMapper();
+        this.listeners = new CopyOnWriteArraySet<SalesforceSessionListener>();
+    }
+
+    private void assertNotNull(String s, Object o) {
+        if (o == null) {
+            throw new IllegalArgumentException(s);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public synchronized String login(String oldToken) throws SalesforceException {
+
+        // check if we need a new session
+        // this way there's always a single valid session
+        if ((accessToken == null) || accessToken.equals(oldToken)) {
+
+            // try revoking the old access token before creating a new one
+            accessToken = oldToken;
+            if (accessToken != null) {
+                try {
+                    logout();
+                } catch (SalesforceException e) {
+                    LOG.warn("Error revoking old access token: " + e.getMessage(), e);
+                }
+                accessToken = null;
+            }
+
+            // login to Salesforce and get session id
+            final StatusExceptionExchange loginPost = new StatusExceptionExchange(true);
+            loginPost.setURL(config.getLoginUrl() + OAUTH2_TOKEN_PATH);
+            loginPost.setMethod(HttpMethods.POST);
+            loginPost.setRequestContentType(FORM_CONTENT_TYPE);
+
+            final UrlEncoded nvps = new UrlEncoded();
+            nvps.put("grant_type", "password");
+            nvps.put("client_id", config.getClientId());
+            nvps.put("client_secret", config.getClientSecret());
+            nvps.put("username", config.getUserName());
+            nvps.put("password", config.getPassword());
+            nvps.put("format", "json");
+
+            try {
+
+                // set form content
+                loginPost.setRequestContent(new ByteArrayBuffer(
+                    nvps.encode(StringUtil.__UTF8, true).getBytes(StringUtil.__UTF8)));
+                httpClient.send(loginPost);
+
+                // wait for the login to finish
+                final int exchangeState = loginPost.waitForDone();
+
+                switch (exchangeState) {
+                    case HttpExchange.STATUS_COMPLETED:
+                        final byte[] responseContent = loginPost.getResponseContentBytes();
+                        final int responseStatus = loginPost.getResponseStatus();
+                        switch (responseStatus) {
+
+                            case HttpStatus.OK_200:
+                                // parse the response to get token
+                                LoginToken token = objectMapper.readValue(responseContent,
+                                    LoginToken.class);
+
+                                // don't log token or instance URL for security reasons
+                                LOG.info("Login successful");
+                                accessToken = token.getAccessToken();
+                                instanceUrl = token.getInstanceUrl();
+
+                                // notify all listeners
+                                for (SalesforceSessionListener listener : listeners) {
+                                    try {
+                                        listener.onLogin(accessToken, instanceUrl);
+                                    } catch (Throwable t) {
+                                        LOG.warn("Unexpected error from listener {}: {}", listener, t.getMessage());
+                                    }
+                                }
+
+                                break;
+
+                            case HttpStatus.BAD_REQUEST_400:
+                                // parse the response to get error
+                                final LoginError error = objectMapper.readValue(responseContent,
+                                    LoginError.class);
+                                final String msg = String.format("Login error code:[%s] description:[%s]",
+                                    error.getError(), error.getErrorDescription());
+                                final List<RestError> errors = new ArrayList<RestError>();
+                                errors.add(new RestError(msg, error.getErrorDescription()));
+                                throw new SalesforceException(errors, HttpStatus.BAD_REQUEST_400);
+
+                            default:
+                                throw new SalesforceException(
+                                    String.format("Login error status:[%s] reason:[%s]",
+                                        responseStatus, loginPost.getReason()),
+                                    responseStatus);
+                        }
+                        break;
+
+                    case HttpExchange.STATUS_EXCEPTED:
+                        final Throwable ex = loginPost.getException();
+                        throw new SalesforceException(
+                            String.format("Unexpected login exception: %s", ex.getMessage()),
+                            ex);
+
+                    case HttpExchange.STATUS_CANCELLED:
+                        throw new SalesforceException("Login request CANCELLED!", null);
+
+                    case HttpExchange.STATUS_EXPIRED:
+                        throw new SalesforceException("Login request TIMEOUT!", null);
+
+                }
+
+            } catch (IOException e) {
+                String msg = "Login error: unexpected exception " + e.getMessage();
+                throw new SalesforceException(msg, e);
+            } catch (InterruptedException e) {
+                String msg = "Login error: unexpected exception " + e.getMessage();
+                throw new SalesforceException(msg, e);
+            }
+        }
+
+        return accessToken;
+    }
+
+    public void logout() throws SalesforceException {
+        if (accessToken == null) {
+            return;
+        }
+
+        StatusExceptionExchange logoutGet = new StatusExceptionExchange(true);
+        logoutGet.setURL(config.getLoginUrl() + OAUTH2_REVOKE_PATH + accessToken);
+        logoutGet.setMethod(HttpMethods.GET);
+
+        try {
+            httpClient.send(logoutGet);
+            final int done = logoutGet.waitForDone();
+            switch (done) {
+
+                case HttpExchange.STATUS_COMPLETED:
+                    final int statusCode = logoutGet.getResponseStatus();
+                    final String reason = logoutGet.getReason();
+
+                    if (statusCode == HttpStatus.OK_200) {
+                        LOG.info("Logout successful");
+                    } else {
+                        throw new SalesforceException(
+                            String.format("Logout error, code: [%s] reason: [%s]",
+                                statusCode, reason),
+                            statusCode);
+                    }
+                    break;
+
+                case HttpExchange.STATUS_EXCEPTED:
+                    final Throwable ex = logoutGet.getException();
+                    throw new SalesforceException("Unexpected logout exception: " + ex.getMessage(), ex);
+
+                case HttpExchange.STATUS_CANCELLED:
+                    throw new SalesforceException("Logout request CANCELLED!", null);
+
+                case HttpExchange.STATUS_EXPIRED:
+                    throw new SalesforceException("Logout request TIMEOUT!", null);
+
+            }
+
+        } catch (SalesforceException e) {
+            throw e;
+        } catch (Exception e) {
+            String msg = "Logout error: " + e.getMessage();
+            throw new SalesforceException(msg, e);
+        } finally {
+            // reset session
+            accessToken = null;
+            instanceUrl = null;
+            // notify all session listeners of the new access token and instance url
+            for (SalesforceSessionListener listener : listeners) {
+                try {
+                    listener.onLogout();
+                } catch (Throwable t) {
+                    LOG.warn("Unexpected error from listener {}: {}", listener, t.getMessage());
+                }
+            }
+        }
+    }
+
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    public String getInstanceUrl() {
+        return instanceUrl;
+    }
+
+    public boolean addListener(SalesforceSessionListener listener) {
+        return listeners.add(listener);
+    }
+
+    public boolean removeListener(SalesforceSessionListener listener) {
+        return listeners.remove(listener);
+    }
+
+    @Override
+    public void start() throws Exception {
+        // auto-login at start if needed
+        login(accessToken);
+    }
+
+    @Override
+    public void stop() throws Exception {
+        // logout
+        logout();
+    }
+
+    /**
+     * Records status line, and exception from exchange.
+     *
+     * @author dbokde
+     */
+    private static class StatusExceptionExchange extends ContentExchange {
+
+        private String reason;
+        private Throwable exception;
+
+        public StatusExceptionExchange(boolean cacheFields) {
+            super(cacheFields);
+        }
+
+        @Override
+        protected synchronized void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException {
+            // remember reason
+            this.reason = reason.toString(StringUtil.__ISO_8859_1);
+            super.onResponseStatus(version, status, reason);
+        }
+
+        @Override
+        protected void onConnectionFailed(Throwable x) {
+            this.exception = x;
+            super.onConnectionFailed(x);
+        }
+
+        @Override
+        protected void onException(Throwable x) {
+            this.exception = x;
+            super.onException(x);
+        }
+
+        public String getReason() {
+            return reason;
+        }
+
+        public Throwable getException() {
+            return exception;
+        }
+
+    }
+
+    public static interface SalesforceSessionListener {
+        void onLogin(String accessToken, String instanceUrl);
+        void onLogout();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
new file mode 100644
index 0000000..6fe7028
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
@@ -0,0 +1,196 @@
+/**
+ * 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.internal.client;
+
+import org.apache.camel.Service;
+import org.eclipse.jetty.client.ContentExchange;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpEventListenerWrapper;
+import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.http.HttpSchemes;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.io.Buffer;
+import org.eclipse.jetty.util.StringUtil;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.internal.SalesforceSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public abstract class AbstractClientBase implements SalesforceSession.SalesforceSessionListener, Service {
+
+    protected final Logger LOG = LoggerFactory.getLogger(getClass());
+
+    protected static final String APPLICATION_JSON_UTF8 = "application/json;charset=utf-8";
+    protected static final String APPLICATION_XML_UTF8 = "application/xml;charset=utf-8";
+
+    protected final HttpClient httpClient;
+    protected final SalesforceSession session;
+    protected final String version;
+
+    protected String accessToken;
+    protected String instanceUrl;
+
+    public AbstractClientBase(String version,
+                              SalesforceSession session, HttpClient httpClient) throws SalesforceException {
+
+        this.version = version;
+        this.session = session;
+        this.httpClient = httpClient;
+    }
+
+    public void start() throws Exception {
+        // local cache
+        accessToken = session.getAccessToken();
+        if (accessToken == null) {
+            // lazy login here!
+            accessToken = session.login(accessToken);
+        }
+        instanceUrl = session.getInstanceUrl();
+
+        // also register this client as a session listener
+        session.addListener(this);
+    }
+
+    @Override
+    public void stop() throws Exception {
+        // deregister listener
+        session.removeListener(this);
+    }
+
+    @Override
+    public void onLogin(String accessToken, String instanceUrl) {
+        if (!accessToken.equals(this.accessToken)) {
+            this.accessToken = accessToken;
+            this.instanceUrl = instanceUrl;
+        }
+    }
+
+    @Override
+    public void onLogout() {
+        // ignore, if this client makes another request with stale token,
+        // SalesforceSecurityListener will auto login!
+    }
+
+    protected SalesforceExchange getContentExchange(String method, String url) {
+        SalesforceExchange get = new SalesforceExchange();
+        get.setMethod(method);
+        get.setURL(url);
+        get.setClient(this);
+        return get;
+    }
+
+    protected interface ClientResponseCallback {
+        void onResponse(InputStream response, SalesforceException ex);
+    }
+
+    protected void doHttpRequest(final ContentExchange request, final ClientResponseCallback callback) {
+
+        // use SalesforceSecurityListener for security login retries
+        try {
+            final boolean isHttps = HttpSchemes.HTTPS.equals(String.valueOf(request.getScheme()));
+            request.setEventListener(new SalesforceSecurityListener(
+                httpClient.getDestination(request.getAddress(), isHttps),
+                request, session, accessToken));
+        } catch (IOException e) {
+            // propagate exception
+            callback.onResponse(null, new SalesforceException(
+                String.format("Error registering security listener: %s", e.getMessage()),
+                e));
+        }
+
+        // use HttpEventListener for lifecycle events
+        request.setEventListener(new HttpEventListenerWrapper(request.getEventListener(), true) {
+
+            public String reason;
+
+            @Override
+            public void onConnectionFailed(Throwable ex) {
+                super.onConnectionFailed(ex);
+                callback.onResponse(null,
+                    new SalesforceException("Connection error: " + ex.getMessage(), ex));
+            }
+
+            @Override
+            public void onException(Throwable ex) {
+                super.onException(ex);
+                callback.onResponse(null,
+                    new SalesforceException("Unexpected exception: " + ex.getMessage(), ex));
+            }
+
+            @Override
+            public void onExpire() {
+                super.onExpire();
+                callback.onResponse(null,
+                    new SalesforceException("Request expired", null));
+            }
+
+            @Override
+            public void onResponseComplete() throws IOException {
+                super.onResponseComplete();
+
+                final int responseStatus = request.getResponseStatus();
+                if (responseStatus < HttpStatus.OK_200 || responseStatus >= HttpStatus.MULTIPLE_CHOICES_300) {
+                    final String msg = String.format("Error {%s:%s} executing {%s:%s}",
+                        responseStatus, reason, request.getMethod(), request.getRequestURI());
+                    final SalesforceException exception = new SalesforceException(msg, createRestException(request));
+                    exception.setStatusCode(responseStatus);
+                    callback.onResponse(null, exception);
+                } else {
+                    // TODO not memory efficient for large response messages,
+                    // doesn't seem to be possible in Jetty 7 to directly stream to response parsers
+                    final byte[] bytes = request.getResponseContentBytes();
+                    callback.onResponse(bytes != null ? new ByteArrayInputStream(bytes) : null, null);
+                }
+
+            }
+
+            @Override
+            public void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException {
+                super.onResponseStatus(version, status, reason);
+                // remember status reason
+                this.reason = reason.toString(StringUtil.__ISO_8859_1);
+            }
+        });
+
+        // execute the request
+        try {
+            httpClient.send(request);
+        } catch (IOException e) {
+            String msg = "Unexpected Error: " + e.getMessage();
+            // send error through callback
+            callback.onResponse(null, new SalesforceException(msg, e));
+        }
+
+    }
+
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
+    }
+
+    public void setInstanceUrl(String instanceUrl) {
+        this.instanceUrl = instanceUrl;
+    }
+
+    protected abstract void setAccessToken(HttpExchange httpExchange);
+
+    protected abstract SalesforceException createRestException(ContentExchange httpExchange);
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/BulkApiClient.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/BulkApiClient.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/BulkApiClient.java
new file mode 100644
index 0000000..b00e3fd
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/BulkApiClient.java
@@ -0,0 +1,92 @@
+/**
+ * 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.internal.client;
+
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.bulk.*;
+
+import java.io.InputStream;
+import java.util.List;
+
+/**
+ * Client interface for Salesforce Bulk API
+ */
+public interface BulkApiClient {
+
+    public static interface JobInfoResponseCallback {
+        void onResponse(JobInfo jobInfo, SalesforceException ex);
+    }
+
+    public static interface BatchInfoResponseCallback {
+        void onResponse(BatchInfo batchInfo, SalesforceException ex);
+    }
+
+    public static interface BatchInfoListResponseCallback {
+        void onResponse(List<BatchInfo> batchInfoList, SalesforceException ex);
+    }
+
+    public static interface StreamResponseCallback {
+        void onResponse(InputStream inputStream, SalesforceException ex);
+    }
+
+    public static interface QueryResultIdsCallback {
+        void onResponse(List<String> ids, SalesforceException ex);
+    }
+
+    /**
+     * Creates a Bulk Job
+     *
+     * @param jobInfo {@link JobInfo} with required fields
+     * @param callback {@link JobInfoResponseCallback} to be invoked on response or error
+     */
+    void createJob(JobInfo jobInfo,
+                   JobInfoResponseCallback callback);
+
+    void getJob(String jobId,
+                JobInfoResponseCallback callback);
+
+    void closeJob(String jobId,
+                  JobInfoResponseCallback callback);
+
+    void abortJob(String jobId,
+                  JobInfoResponseCallback callback);
+
+    void createBatch(InputStream batchStream, String jobId, ContentType contentTypeEnum,
+                     BatchInfoResponseCallback callback);
+
+    void getBatch(String jobId, String batchId,
+                  BatchInfoResponseCallback callback);
+
+    void getAllBatches(String jobId,
+                       BatchInfoListResponseCallback callback);
+
+    void getRequest(String jobId, String batchId,
+                    StreamResponseCallback callback);
+
+    void getResults(String jobId, String batchId,
+                    StreamResponseCallback callback);
+
+    void createBatchQuery(String jobId, String soqlQuery, ContentType jobContentType,
+                          BatchInfoResponseCallback callback);
+
+    void getQueryResultIds(String jobId, String batchId,
+                           QueryResultIdsCallback callback);
+
+    void getQueryResult(String jobId, String batchId, String resultId,
+                        StreamResponseCallback callback);
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultBulkApiClient.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultBulkApiClient.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultBulkApiClient.java
new file mode 100644
index 0000000..b4899e5
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultBulkApiClient.java
@@ -0,0 +1,481 @@
+/**
+ * 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.internal.client;
+
+import org.eclipse.jetty.client.ContentExchange;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.http.HttpHeaders;
+import org.eclipse.jetty.http.HttpMethods;
+import org.eclipse.jetty.io.ByteArrayBuffer;
+import org.eclipse.jetty.util.StringUtil;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.RestError;
+import org.apache.camel.component.salesforce.api.dto.bulk.*;
+import org.apache.camel.component.salesforce.api.dto.bulk.Error;
+import org.apache.camel.component.salesforce.internal.SalesforceSession;
+
+import javax.xml.bind.*;
+import javax.xml.transform.stream.StreamSource;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collections;
+
+public class DefaultBulkApiClient extends AbstractClientBase implements BulkApiClient {
+
+    private static final String TOKEN_HEADER = "X-SFDC-Session";
+
+    private JAXBContext context;
+    private static final ContentType DEFAULT_ACCEPT_TYPE = ContentType.XML;
+    private ObjectFactory objectFactory;
+
+    public DefaultBulkApiClient(String version,
+                                SalesforceSession session, HttpClient httpClient) throws SalesforceException {
+        super(version, session, httpClient);
+
+        try {
+            context = JAXBContext.newInstance(JobInfo.class.getPackage().getName(), getClass().getClassLoader());
+        } catch (JAXBException e) {
+            String msg = "Error loading Bulk API DTOs: " + e.getMessage();
+            throw new IllegalArgumentException(msg, e);
+        }
+
+        this.objectFactory = new ObjectFactory();
+    }
+
+    @Override
+    public void createJob(JobInfo request, final JobInfoResponseCallback callback) {
+
+        // clear system fields if set
+        sanitizeJobRequest(request);
+
+        final ContentExchange post = getContentExchange(HttpMethods.POST, jobUrl(null));
+        try {
+            marshalRequest(objectFactory.createJobInfo(request), post, APPLICATION_XML_UTF8);
+        } catch (SalesforceException e) {
+            callback.onResponse(null, e);
+            return;
+        }
+
+        // make the call and parse the result in callback
+        doHttpRequest(post, new ClientResponseCallback() {
+            @Override
+            public void onResponse(InputStream response, SalesforceException ex) {
+                JobInfo value = null;
+                if (response != null) {
+                    try {
+                        value = unmarshalResponse(response, post, JobInfo.class);
+                    } catch (SalesforceException e) {
+                        ex = e;
+                    }
+                }
+                callback.onResponse(value, ex);
+            }
+        });
+
+    }
+
+    // reset read only fields
+    private void sanitizeJobRequest(JobInfo request) {
+        request.setApexProcessingTime(null);
+        request.setApiActiveProcessingTime(null);
+        request.setApiVersion(null);
+        request.setCreatedById(null);
+        request.setCreatedDate(null);
+        request.setId(null);
+        request.setNumberBatchesCompleted(null);
+        request.setNumberBatchesFailed(null);
+        request.setNumberBatchesInProgress(null);
+        request.setNumberBatchesQueued(null);
+        request.setNumberBatchesTotal(null);
+        request.setNumberRecordsFailed(null);
+        request.setNumberRecordsProcessed(null);
+        request.setNumberRetries(null);
+        request.setState(null);
+        request.setSystemModstamp(null);
+        request.setSystemModstamp(null);
+    }
+
+    @Override
+    public void getJob(String jobId, final JobInfoResponseCallback callback) {
+
+        final ContentExchange get = getContentExchange(HttpMethods.GET, jobUrl(jobId));
+
+        // make the call and parse the result
+        doHttpRequest(get, new ClientResponseCallback() {
+            @Override
+            public void onResponse(InputStream response, SalesforceException ex) {
+                JobInfo value = null;
+                try {
+                    value = unmarshalResponse(response, get, JobInfo.class);
+                } catch (SalesforceException e) {
+                    ex = e;
+                }
+                callback.onResponse(value, ex);
+            }
+        });
+
+    }
+
+    @Override
+    public void closeJob(String jobId, final JobInfoResponseCallback callback) {
+        final JobInfo request = new JobInfo();
+        request.setState(JobStateEnum.CLOSED);
+
+        final ContentExchange post = getContentExchange(HttpMethods.POST, jobUrl(jobId));
+        try {
+            marshalRequest(objectFactory.createJobInfo(request), post, APPLICATION_XML_UTF8);
+        } catch (SalesforceException e) {
+            callback.onResponse(null, e);
+            return;
+        }
+
+        // make the call and parse the result
+        doHttpRequest(post, new ClientResponseCallback() {
+            @Override
+            public void onResponse(InputStream response, SalesforceException ex) {
+                JobInfo value = null;
+                try {
+                    value = unmarshalResponse(response, post, JobInfo.class);
+                } catch (SalesforceException e) {
+                    ex = e;
+                }
+                callback.onResponse(value, ex);
+            }
+        });
+
+    }
+
+    @Override
+    public void abortJob(String jobId, final JobInfoResponseCallback callback) {
+        final JobInfo request = new JobInfo();
+        request.setState(JobStateEnum.ABORTED);
+
+        final ContentExchange post = getContentExchange(HttpMethods.POST, jobUrl(jobId));
+        try {
+            marshalRequest(objectFactory.createJobInfo(request), post, APPLICATION_XML_UTF8);
+        } catch (SalesforceException e) {
+            callback.onResponse(null, e);
+            return;
+        }
+
+        // make the call and parse the result
+        doHttpRequest(post, new ClientResponseCallback() {
+            @Override
+            public void onResponse(InputStream response, SalesforceException ex) {
+                JobInfo value = null;
+                try {
+                    value = unmarshalResponse(response, post, JobInfo.class);
+                } catch (SalesforceException e) {
+                    ex = e;
+                }
+                callback.onResponse(value, ex);
+            }
+        });
+
+    }
+
+    @Override
+    public void createBatch(InputStream batchStream, String jobId, ContentType contentTypeEnum,
+                            final BatchInfoResponseCallback callback) {
+
+        final ContentExchange post = getContentExchange(HttpMethods.POST, batchUrl(jobId, null));
+        post.setRequestContentSource(batchStream);
+        post.setRequestContentType(getContentType(contentTypeEnum) + ";charset=" + StringUtil.__UTF8);
+
+        // make the call and parse the result
+        doHttpRequest(post, new ClientResponseCallback() {
+            @Override
+            public void onResponse(InputStream response, SalesforceException ex) {
+                BatchInfo value = null;
+                try {
+                    value = unmarshalResponse(response, post, BatchInfo.class);
+                } catch (SalesforceException e) {
+                    ex = e;
+                }
+                callback.onResponse(value, ex);
+            }
+        });
+
+    }
+
+    @Override
+    public void getBatch(String jobId, String batchId,
+                         final BatchInfoResponseCallback callback) {
+
+        final ContentExchange get = getContentExchange(HttpMethods.GET, batchUrl(jobId, batchId));
+
+        // make the call and parse the result
+        doHttpRequest(get, new ClientResponseCallback() {
+            @Override
+            public void onResponse(InputStream response, SalesforceException ex) {
+                BatchInfo value = null;
+                try {
+                    value = unmarshalResponse(response, get, BatchInfo.class);
+                } catch (SalesforceException e) {
+                    ex = e;
+                }
+                callback.onResponse(value, ex);
+            }
+        });
+
+    }
+
+    @Override
+    public void getAllBatches(String jobId,
+                              final BatchInfoListResponseCallback callback) {
+
+        final ContentExchange get = getContentExchange(HttpMethods.GET, batchUrl(jobId, null));
+
+        // make the call and parse the result
+        doHttpRequest(get, new ClientResponseCallback() {
+            @Override
+            public void onResponse(InputStream response, SalesforceException ex) {
+                BatchInfoList value = null;
+                try {
+                    value = unmarshalResponse(response, get, BatchInfoList.class);
+                } catch (SalesforceException e) {
+                    ex = e;
+                }
+                callback.onResponse(value != null ? value.getBatchInfo() : null, ex);
+            }
+        });
+
+    }
+
+    @Override
+    public void getRequest(String jobId, String batchId,
+                           final StreamResponseCallback callback) {
+
+        final ContentExchange get = getContentExchange(HttpMethods.GET, batchUrl(jobId, batchId));
+
+        // make the call and parse the result
+        doHttpRequest(get, new ClientResponseCallback() {
+            @Override
+            public void onResponse(InputStream response, SalesforceException ex) {
+                callback.onResponse(response, ex);
+            }
+        });
+
+    }
+
+    @Override
+    public void getResults(String jobId, String batchId,
+                           final StreamResponseCallback callback) {
+        final ContentExchange get = getContentExchange(HttpMethods.GET, batchResultUrl(jobId, batchId, null));
+
+        // make the call and return the result
+        doHttpRequest(get, new ClientResponseCallback() {
+            @Override
+            public void onResponse(InputStream response, SalesforceException ex) {
+                callback.onResponse(response, ex);
+            }
+        });
+    }
+
+    @Override
+    public void createBatchQuery(String jobId, String soqlQuery, ContentType jobContentType,
+                                 final BatchInfoResponseCallback callback) {
+
+        final ContentExchange post = getContentExchange(HttpMethods.POST, batchUrl(jobId, null));
+        byte[] queryBytes = soqlQuery.getBytes(StringUtil.__UTF8_CHARSET);
+        post.setRequestContent(new ByteArrayBuffer(queryBytes));
+        post.setRequestContentType(getContentType(jobContentType) + ";charset=" + StringUtil.__UTF8);
+
+        // make the call and parse the result
+        doHttpRequest(post, new ClientResponseCallback() {
+            @Override
+            public void onResponse(InputStream response, SalesforceException ex) {
+                BatchInfo value = null;
+                try {
+                    value = unmarshalResponse(response, post, BatchInfo.class);
+                } catch (SalesforceException e) {
+                    ex = e;
+                }
+                callback.onResponse(value, ex);
+            }
+        });
+
+    }
+
+    @Override
+    public void getQueryResultIds(String jobId, String batchId,
+                                  final QueryResultIdsCallback callback) {
+        final ContentExchange get = getContentExchange(HttpMethods.GET, batchResultUrl(jobId, batchId, null));
+
+        // make the call and parse the result
+        doHttpRequest(get, new ClientResponseCallback() {
+            @Override
+            public void onResponse(InputStream response, SalesforceException ex) {
+                QueryResultList value = null;
+                try {
+                    value = unmarshalResponse(response, get, QueryResultList.class);
+                } catch (SalesforceException e) {
+                    ex = e;
+                }
+                callback.onResponse(value != null ? Collections.unmodifiableList(value.getResult()) : null,
+                    ex);
+            }
+        });
+
+    }
+
+    @Override
+    public void getQueryResult(String jobId, String batchId, String resultId,
+                               final StreamResponseCallback callback) {
+        final ContentExchange get = getContentExchange(HttpMethods.GET, batchResultUrl(jobId, batchId, resultId));
+
+        // make the call and parse the result
+        doHttpRequest(get, new ClientResponseCallback() {
+            @Override
+            public void onResponse(InputStream response, SalesforceException ex) {
+                callback.onResponse(response, ex);
+            }
+        });
+
+    }
+
+    @Override
+    protected void setAccessToken(HttpExchange httpExchange) {
+        httpExchange.setRequestHeader(TOKEN_HEADER, accessToken);
+    }
+
+    @Override
+    protected void doHttpRequest(ContentExchange request, ClientResponseCallback callback) {
+        // set access token for all requests
+        setAccessToken(request);
+
+        // set default charset
+        request.setRequestHeader(HttpHeaders.ACCEPT_CHARSET, StringUtil.__UTF8);
+
+        // TODO check if this is really needed or not, since SF response content type seems fixed
+        // check if the default accept content type must be used
+        if (!request.getRequestFields().containsKey(HttpHeaders.ACCEPT)) {
+            final String contentType = getContentType(DEFAULT_ACCEPT_TYPE);
+            request.setRequestHeader(HttpHeaders.ACCEPT, contentType);
+            // request content type and charset is set by the request entity
+        }
+
+        super.doHttpRequest(request, callback);
+    }
+
+    private static String getContentType(ContentType type) {
+        String result = null;
+
+        switch (type) {
+            case CSV:
+                result = "text/csv";
+                break;
+
+            case XML:
+                result = "application/xml";
+                break;
+
+            case ZIP_CSV:
+            case ZIP_XML:
+                result = type.toString().toLowerCase().replace('_', '/');
+                break;
+        }
+
+        return result;
+    }
+
+    @Override
+    protected SalesforceException createRestException(ContentExchange request) {
+        // this must be of type Error
+        try {
+            final Error error = unmarshalResponse(new ByteArrayInputStream(request.getResponseContentBytes()),
+                request, Error.class);
+
+            final RestError restError = new RestError();
+            restError.setErrorCode(error.getExceptionCode());
+            restError.setMessage(error.getExceptionMessage());
+
+            return new SalesforceException(Arrays.asList(restError), request.getResponseStatus());
+        } catch (SalesforceException e) {
+            String msg = "Error un-marshaling Salesforce Error: " + e.getMessage();
+            return new SalesforceException(msg, e);
+        }
+    }
+
+    private <T> T unmarshalResponse(InputStream response, ContentExchange request, Class<T> resultClass)
+        throws SalesforceException {
+        try {
+            Unmarshaller unmarshaller = context.createUnmarshaller();
+            JAXBElement<T> result = unmarshaller.unmarshal(new StreamSource(response), resultClass);
+            return result.getValue();
+        } catch (JAXBException e) {
+            throw new SalesforceException(
+                String.format("Error unmarshaling response {%s:%s} : %s",
+                    request.getMethod(), request.getRequestURI(), e.getMessage()),
+                e);
+        } catch (IllegalArgumentException e) {
+            throw new SalesforceException(
+                String.format("Error unmarshaling response for {%s:%s} : %s",
+                    request.getMethod(), request.getRequestURI(), e.getMessage()),
+                e);
+        }
+    }
+
+    private void marshalRequest(Object input, ContentExchange request, String contentType)
+        throws SalesforceException {
+        try {
+            Marshaller marshaller = context.createMarshaller();
+            ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+            marshaller.marshal(input, byteStream);
+            request.setRequestContent(new ByteArrayBuffer(byteStream.toByteArray()));
+            request.setRequestContentType(contentType);
+        } catch (JAXBException e) {
+            throw new SalesforceException(
+                String.format("Error marshaling request for {%s:%s} : %s",
+                    request.getMethod(), request.getRequestURI(), e.getMessage()),
+                e);
+        } catch (IllegalArgumentException e) {
+            throw new SalesforceException(
+                String.format("Error marshaling request for {%s:%s} : %s",
+                    request.getMethod(), request.getRequestURI(), e.getMessage()),
+                e);
+        }
+    }
+
+    private String jobUrl(String jobId) {
+        if (jobId != null) {
+            return super.instanceUrl + "/services/async/" + version + "/job/" + jobId;
+        } else {
+            return super.instanceUrl + "/services/async/" + version + "/job";
+        }
+    }
+
+    private String batchUrl(String jobId, String batchId) {
+        if (batchId != null) {
+            return jobUrl(jobId) + "/batch/" + batchId;
+        } else {
+            return jobUrl(jobId) + "/batch";
+        }
+    }
+
+    private String batchResultUrl(String jobId, String batchId, String resultId) {
+        if (resultId != null) {
+            return batchUrl(jobId, batchId) + "/result/" + resultId;
+        } else {
+            return batchUrl(jobId, batchId) + "/result";
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java
new file mode 100644
index 0000000..07f5af2
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java
@@ -0,0 +1,364 @@
+/**
+ * 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.internal.client;
+
+import com.thoughtworks.xstream.XStream;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
+import org.eclipse.jetty.client.ContentExchange;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.http.HttpHeaders;
+import org.eclipse.jetty.http.HttpMethods;
+import org.eclipse.jetty.util.StringUtil;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.RestError;
+import org.apache.camel.component.salesforce.internal.SalesforceSession;
+import org.apache.camel.component.salesforce.internal.dto.RestErrors;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.List;
+
+public class DefaultRestClient extends AbstractClientBase implements RestClient {
+
+    private static final String SERVICES_DATA = "/services/data/";
+    private static final String TOKEN_HEADER = "Authorization";
+    private static final String TOKEN_PREFIX = "Bearer ";
+
+    private ObjectMapper objectMapper;
+    private XStream xStream;
+    protected String format;
+
+    public DefaultRestClient(HttpClient httpClient,
+                             String version, String format, SalesforceSession session) throws SalesforceException {
+        super(version, session, httpClient);
+
+        this.format = format;
+
+        // initialize error parsers for JSON and XML
+        this.objectMapper = new ObjectMapper();
+        this.xStream = new XStream();
+        xStream.processAnnotations(RestErrors.class);
+    }
+
+    @Override
+    protected void doHttpRequest(ContentExchange request, ClientResponseCallback callback) {
+        // set standard headers for all requests
+        final String contentType = "json".equals(format) ? APPLICATION_JSON_UTF8 : APPLICATION_XML_UTF8;
+        request.setRequestHeader(HttpHeaders.ACCEPT, contentType);
+        request.setRequestHeader(HttpHeaders.ACCEPT_CHARSET, StringUtil.__UTF8);
+        // request content type and charset is set by the request entity
+
+        super.doHttpRequest(request, callback);
+    }
+
+    @Override
+    protected SalesforceException createRestException(ContentExchange httpExchange) {
+        // try parsing response according to format
+        try {
+            if ("json".equals(format)) {
+                List<RestError> restErrors = objectMapper.readValue(
+                    httpExchange.getResponseContent(), new TypeReference<List<RestError>>() {
+                });
+                return new SalesforceException(restErrors, httpExchange.getResponseStatus());
+            } else {
+                RestErrors errors = new RestErrors();
+                xStream.fromXML(httpExchange.getResponseContent(), errors);
+                return new SalesforceException(errors.getErrors(), httpExchange.getResponseStatus());
+            }
+        } catch (IOException e) {
+            // log and ignore
+            String msg = "Unexpected Error parsing " + format + " error response: " + e.getMessage();
+            LOG.warn(msg, e);
+        } catch (RuntimeException e) {
+            // log and ignore
+            String msg = "Unexpected Error parsing " + format + " error response: " + e.getMessage();
+            LOG.warn(msg, e);
+        }
+
+        // just report HTTP status info
+        return new SalesforceException("Unexpected error", httpExchange.getResponseStatus());
+    }
+
+    @Override
+    public void getVersions(final ResponseCallback callback) {
+        ContentExchange get = getContentExchange(HttpMethods.GET, servicesDataUrl());
+        // does not require authorization token
+
+        doHttpRequest(get, new DelegatingClientCallback(callback));
+    }
+
+    @Override
+    public void getResources(ResponseCallback callback) {
+        ContentExchange get = getContentExchange(HttpMethods.GET, versionUrl());
+        // requires authorization token
+        setAccessToken(get);
+
+        doHttpRequest(get, new DelegatingClientCallback(callback));
+    }
+
+    @Override
+    public void getGlobalObjects(ResponseCallback callback) {
+        ContentExchange get = getContentExchange(HttpMethods.GET, sobjectsUrl(""));
+        // requires authorization token
+        setAccessToken(get);
+
+        doHttpRequest(get, new DelegatingClientCallback(callback));
+    }
+
+    @Override
+    public void getBasicInfo(String sObjectName,
+                             ResponseCallback callback) {
+        ContentExchange get = getContentExchange(HttpMethods.GET, sobjectsUrl(sObjectName + "/"));
+        // requires authorization token
+        setAccessToken(get);
+
+        doHttpRequest(get, new DelegatingClientCallback(callback));
+    }
+
+    @Override
+    public void getDescription(String sObjectName,
+                               ResponseCallback callback) {
+        ContentExchange get = getContentExchange(HttpMethods.GET, sobjectsUrl(sObjectName + "/describe/"));
+        // requires authorization token
+        setAccessToken(get);
+
+        doHttpRequest(get, new DelegatingClientCallback(callback));
+    }
+
+    @Override
+    public void getSObject(String sObjectName, String id, String[] fields,
+                           ResponseCallback callback) {
+
+        // parse fields if set
+        String params = "";
+        if (fields != null && fields.length > 0) {
+            StringBuilder fieldsValue = new StringBuilder("?fields=");
+            for (int i = 0; i < fields.length; i++) {
+                fieldsValue.append(fields[i]);
+                if (i < (fields.length - 1)) {
+                    fieldsValue.append(',');
+                }
+            }
+            params = fieldsValue.toString();
+        }
+        ContentExchange get = getContentExchange(HttpMethods.GET, sobjectsUrl(sObjectName + "/" + id + params));
+        // requires authorization token
+        setAccessToken(get);
+
+        doHttpRequest(get, new DelegatingClientCallback(callback));
+    }
+
+    @Override
+    public void createSObject(String sObjectName, InputStream sObject,
+                              ResponseCallback callback) {
+        // post the sObject
+        final ContentExchange post = getContentExchange(HttpMethods.POST, sobjectsUrl(sObjectName));
+
+        // authorization
+        setAccessToken(post);
+
+        // input stream as entity content
+        post.setRequestContentSource(sObject);
+        post.setRequestContentType("json".equals(format) ? APPLICATION_JSON_UTF8 : APPLICATION_XML_UTF8);
+
+        doHttpRequest(post, new DelegatingClientCallback(callback));
+    }
+
+    @Override
+    public void updateSObject(String sObjectName, String id, InputStream sObject,
+                              ResponseCallback callback) {
+        final ContentExchange patch = getContentExchange("PATCH", sobjectsUrl(sObjectName + "/" + id));
+        // requires authorization token
+        setAccessToken(patch);
+
+        // input stream as entity content
+        patch.setRequestContentSource(sObject);
+        patch.setRequestContentType("json".equals(format) ? APPLICATION_JSON_UTF8 : APPLICATION_XML_UTF8);
+
+        doHttpRequest(patch, new DelegatingClientCallback(callback));
+    }
+
+    @Override
+    public void deleteSObject(String sObjectName, String id,
+                              ResponseCallback callback) {
+        final ContentExchange delete = getContentExchange(HttpMethods.DELETE, sobjectsUrl(sObjectName + "/" + id));
+
+        // requires authorization token
+        setAccessToken(delete);
+
+        doHttpRequest(delete, new DelegatingClientCallback(callback));
+    }
+
+    @Override
+    public void getSObjectWithId(String sObjectName, String fieldName, String fieldValue,
+                                 ResponseCallback callback) {
+        final ContentExchange get = getContentExchange(HttpMethods.GET,
+            sobjectsExternalIdUrl(sObjectName, fieldName, fieldValue));
+
+        // requires authorization token
+        setAccessToken(get);
+
+        doHttpRequest(get, new DelegatingClientCallback(callback));
+    }
+
+    @Override
+    public void upsertSObject(String sObjectName, String fieldName, String fieldValue, InputStream sObject,
+                              ResponseCallback callback) {
+        final ContentExchange patch = getContentExchange("PATCH",
+            sobjectsExternalIdUrl(sObjectName, fieldName, fieldValue));
+
+        // requires authorization token
+        setAccessToken(patch);
+
+        // input stream as entity content
+        patch.setRequestContentSource(sObject);
+        // TODO will the encoding always be UTF-8??
+        patch.setRequestContentType("json".equals(format) ? APPLICATION_JSON_UTF8 : APPLICATION_XML_UTF8);
+
+        doHttpRequest(patch, new DelegatingClientCallback(callback));
+    }
+
+    @Override
+    public void deleteSObjectWithId(String sObjectName, String fieldName, String fieldValue,
+                                    ResponseCallback callback) {
+        final ContentExchange delete = getContentExchange(HttpMethods.DELETE,
+            sobjectsExternalIdUrl(sObjectName, fieldName, fieldValue));
+
+        // requires authorization token
+        setAccessToken(delete);
+
+        doHttpRequest(delete, new DelegatingClientCallback(callback));
+    }
+
+    @Override
+    public void getBlobField(String sObjectName, String id, String blobFieldName, ResponseCallback callback) {
+        final ContentExchange get = getContentExchange(HttpMethods.GET,
+            sobjectsUrl(sObjectName + "/" + id +"/" + blobFieldName));
+        // TODO this doesn't seem to be required, the response is always the content binary stream
+        //get.setRequestHeader(HttpHeaders.ACCEPT_ENCODING, "base64");
+
+        // requires authorization token
+        setAccessToken(get);
+
+        doHttpRequest(get, new DelegatingClientCallback(callback));
+    }
+
+    @Override
+    public void query(String soqlQuery, ResponseCallback callback) {
+        try {
+
+            String encodedQuery = URLEncoder.encode(soqlQuery, StringUtil.__UTF8_CHARSET.toString());
+            // URLEncoder likes to use '+' for spaces
+            encodedQuery = encodedQuery.replace("+", "%20");
+            final ContentExchange get = getContentExchange(HttpMethods.GET, versionUrl() + "query/?q=" + encodedQuery);
+
+            // requires authorization token
+            setAccessToken(get);
+
+            doHttpRequest(get, new DelegatingClientCallback(callback));
+
+        } catch (UnsupportedEncodingException e) {
+            String msg = "Unexpected error: " + e.getMessage();
+            callback.onResponse(null, new SalesforceException(msg, e));
+        }
+    }
+
+    @Override
+    public void queryMore(String nextRecordsUrl, ResponseCallback callback) {
+        final ContentExchange get = getContentExchange(HttpMethods.GET, instanceUrl + nextRecordsUrl);
+
+        // requires authorization token
+        setAccessToken(get);
+
+        doHttpRequest(get, new DelegatingClientCallback(callback));
+    }
+
+    @Override
+    public void search(String soslQuery, ResponseCallback callback) {
+        try {
+
+            String encodedQuery = URLEncoder.encode(soslQuery, StringUtil.__UTF8_CHARSET.toString());
+            // URLEncoder likes to use '+' for spaces
+            encodedQuery = encodedQuery.replace("+", "%20");
+            final ContentExchange get = getContentExchange(HttpMethods.GET, versionUrl() + "search/?q=" + encodedQuery);
+
+            // requires authorization token
+            setAccessToken(get);
+
+            doHttpRequest(get, new DelegatingClientCallback(callback));
+
+        } catch (UnsupportedEncodingException e) {
+            String msg = "Unexpected error: " + e.getMessage();
+            callback.onResponse(null, new SalesforceException(msg, e));
+        }
+    }
+
+    private String servicesDataUrl() {
+        return instanceUrl + SERVICES_DATA;
+    }
+
+    private String versionUrl() {
+        if (version == null) {
+            throw new IllegalArgumentException("NULL API version", new NullPointerException("version"));
+        }
+        return servicesDataUrl() + "v" + version + "/";
+    }
+
+    private String sobjectsUrl(String sObjectName) {
+        if (sObjectName == null) {
+            throw new IllegalArgumentException("Null SObject name", new NullPointerException("sObjectName"));
+        }
+        return versionUrl() + "sobjects/" + sObjectName;
+    }
+
+    private String sobjectsExternalIdUrl(String sObjectName, String fieldName, String fieldValue) {
+        if (fieldName == null || fieldValue == null) {
+            throw new IllegalArgumentException("External field name and value cannot be NULL");
+        }
+        try {
+            String encodedValue = URLEncoder.encode(fieldValue, StringUtil.__UTF8_CHARSET.toString());
+            // URLEncoder likes to use '+' for spaces
+            encodedValue = encodedValue.replace("+", "%20");
+            return sobjectsUrl(sObjectName + "/" + fieldName + "/" + encodedValue);
+        } catch (UnsupportedEncodingException e) {
+            String msg = "Unexpected error: " + e.getMessage();
+            throw new IllegalArgumentException(msg, e);
+        }
+    }
+
+    protected void setAccessToken(HttpExchange httpExchange) {
+        httpExchange.setRequestHeader(TOKEN_HEADER, TOKEN_PREFIX + accessToken);
+    }
+
+    private static class DelegatingClientCallback implements ClientResponseCallback {
+        private final ResponseCallback callback;
+
+        public DelegatingClientCallback(ResponseCallback callback) {
+            this.callback = callback;
+        }
+
+        @Override
+        public void onResponse(InputStream response, SalesforceException ex) {
+            callback.onResponse(response, ex);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
new file mode 100644
index 0000000..30186d9
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
@@ -0,0 +1,177 @@
+/**
+ * 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.internal.client;
+
+import org.apache.camel.component.salesforce.api.SalesforceException;
+
+import java.io.InputStream;
+
+public interface RestClient {
+
+    public static interface ResponseCallback {
+        void onResponse(InputStream response, SalesforceException exception);
+    }
+
+    /**
+     * Lists summary information about each API version currently available,
+     * including the version, label, and a link to each version's root.
+     *
+     * @param callback {@link ResponseCallback} to handle response or exception
+    */
+    void getVersions(ResponseCallback callback);
+
+    /**
+     * Lists available resources for the specified API version, including resource name and URI.
+     *
+     * @param callback {@link ResponseCallback} to handle response or exception
+    */
+    void getResources(ResponseCallback callback);
+
+    /**
+     * Lists the available objects and their metadata for your organization's data.
+     *
+     * @param callback {@link ResponseCallback} to handle response or exception
+    */
+    void getGlobalObjects(ResponseCallback callback);
+
+    /**
+     * Describes the individual metadata for the specified object.
+     *
+     * @param sObjectName specified object name
+     * @param callback {@link ResponseCallback} to handle response or exception
+    */
+    void getBasicInfo(String sObjectName, ResponseCallback callback);
+
+    /**
+     * Completely describes the individual metadata at all levels for the specified object.
+     *
+     * @param sObjectName specified object name
+     * @param callback {@link ResponseCallback} to handle response or exception
+    */
+    void getDescription(String sObjectName, ResponseCallback callback);
+
+    /**
+     * Retrieves a record for the specified object ID.
+     *
+     * @param sObjectName specified object name
+     * @param id          object id
+     * @param callback {@link ResponseCallback} to handle response or exception
+    */
+    void getSObject(String sObjectName, String id, String[] fields, ResponseCallback callback);
+
+    /**
+     * Creates a record for the specified object.
+     *
+     * @param sObjectName specified object name
+     * @param sObject     request entity
+     * @param callback {@link ResponseCallback} to handle response or exception
+    */
+    void createSObject(String sObjectName, InputStream sObject, ResponseCallback callback);
+
+    /**
+     * Updates a record for the specified object ID.
+     *
+     * @param sObjectName specified object name
+     * @param id          object id
+     * @param sObject     request entity
+     * @param callback {@link ResponseCallback} to handle response or exception
+    */
+    void updateSObject(String sObjectName, String id, InputStream sObject, ResponseCallback callback);
+
+    /**
+     * Deletes a record for the specified object ID.
+     *
+     * @param sObjectName specified object name
+     * @param id          object id
+     * @param callback {@link ResponseCallback} to handle response or exception
+    */
+    void deleteSObject(String sObjectName, String id, ResponseCallback callback);
+
+    /**
+     * Retrieves a record for the specified external ID.
+     *
+     * @param sObjectName specified object name
+     * @param fieldName external field name
+     * @param fieldValue external field value
+     * @param callback {@link ResponseCallback} to handle response or exception
+    */
+    void getSObjectWithId(String sObjectName, String fieldName, String fieldValue, ResponseCallback callback);
+
+    /**
+     * Creates or updates a record based on the value of a specified external ID field.
+     *
+     * @param sObjectName specified object name
+     * @param fieldName external field name
+     * @param fieldValue external field value
+     * @param sObject input object to insert or update
+     * @param callback {@link ResponseCallback} to handle response or exception
+    */
+    void upsertSObject(String sObjectName,
+                              String fieldName, String fieldValue, InputStream sObject, ResponseCallback callback);
+
+    /**
+     * Deletes a record based on the value of a specified external ID field.
+     *
+     * @param sObjectName specified object name
+     * @param fieldName external field name
+     * @param fieldValue external field value
+     * @param callback {@link ResponseCallback} to handle response or exception
+    */
+    void deleteSObjectWithId(String sObjectName,
+                             String fieldName, String fieldValue, ResponseCallback callback);
+
+
+    /**
+     * Retrieves the specified blob field from an individual record.
+     *
+     */
+    void getBlobField(String sObjectName, String id, String blobFieldName, ResponseCallback callback);
+
+/*
+    TODO
+    SObject User Password
+    /vXX.X/sobjects/User/user id/password
+    /vXX.X/sobjects/SelfServiceUser/self service user id/password
+
+    These methods set, reset, or get information about a user password.
+*/
+
+    /**
+     * Executes the specified SOQL query.
+     *
+     * @param soqlQuery SOQL query
+     * @param callback {@link ResponseCallback} to handle response or exception
+    */
+    void query(String soqlQuery, ResponseCallback callback);
+
+    /**
+     * Get SOQL query results using nextRecordsUrl.
+     *
+     * @param nextRecordsUrl URL for next records to fetch, returned by query()
+     * @param callback {@link ResponseCallback} to handle response or exception
+    */
+    void queryMore(String nextRecordsUrl, ResponseCallback callback);
+
+    /**
+     * Executes the specified SOSL search.
+     *
+     * @param soslQuery SOSL query
+     * @param callback {@link ResponseCallback} to handle response or exception
+    */
+    void search(String soslQuery, ResponseCallback callback);
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/SalesforceExchange.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/SalesforceExchange.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/SalesforceExchange.java
new file mode 100644
index 0000000..b17c5e1
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/SalesforceExchange.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.salesforce.internal.client;
+
+import org.eclipse.jetty.client.ContentExchange;
+
+/**
+ * Wraps a Salesforce Http Exchange
+ */
+public class SalesforceExchange extends ContentExchange {
+
+    private AbstractClientBase client;
+
+    public AbstractClientBase getClient() {
+        return client;
+    }
+
+    public void setClient(AbstractClientBase client) {
+        this.client = client;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/SalesforceSecurityListener.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/SalesforceSecurityListener.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/SalesforceSecurityListener.java
new file mode 100644
index 0000000..5eec212
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/SalesforceSecurityListener.java
@@ -0,0 +1,162 @@
+/**
+ * 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.internal.client;
+
+import org.eclipse.jetty.client.HttpDestination;
+import org.eclipse.jetty.client.HttpEventListenerWrapper;
+import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.http.HttpHeaders;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.io.Buffer;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.internal.SalesforceSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+public class SalesforceSecurityListener extends HttpEventListenerWrapper {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SalesforceSecurityListener.class);
+
+    private final HttpDestination destination;
+    private final HttpExchange exchange;
+    private final SalesforceSession session;
+
+    private String currentToken;
+    private int retries;
+    private boolean retrying;
+    private boolean requestComplete;
+    private boolean responseComplete;
+
+    public SalesforceSecurityListener(HttpDestination destination, HttpExchange exchange,
+                                      SalesforceSession session, String accessToken) {
+        super(exchange.getEventListener(), true);
+        this.destination = destination;
+        this.exchange = exchange;
+        this.session = session;
+        this.currentToken = accessToken;
+    }
+
+    @Override
+    public void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException {
+        if (status == HttpStatus.UNAUTHORIZED_401 &&
+            retries < destination.getHttpClient().maxRetries()) {
+
+            LOG.warn("Retrying on Salesforce authentication error [{}]: [{}]", status, reason);
+            setDelegatingRequests(false);
+            setDelegatingResponses(false);
+
+            retrying = true;
+        }
+        super.onResponseStatus(version, status, reason);
+    }
+
+    @Override
+    public void onRequestComplete() throws IOException {
+        requestComplete = true;
+        if (checkExchangeComplete()) {
+            super.onRequestComplete();
+        }
+    }
+
+    @Override
+    public void onResponseComplete() throws IOException {
+        responseComplete = true;
+        if (checkExchangeComplete()) {
+            super.onResponseComplete();
+        }
+    }
+
+    private boolean checkExchangeComplete() throws IOException {
+        if (retrying && requestComplete && responseComplete) {
+            LOG.debug("Authentication Error, retrying: {}", exchange);
+
+            requestComplete = false;
+            responseComplete = false;
+
+            setDelegatingRequests(true);
+            setDelegatingResponses(true);
+
+            try {
+                // get a new token and retry
+                currentToken = session.login(currentToken);
+
+                if (exchange instanceof SalesforceExchange) {
+                    final SalesforceExchange salesforceExchange = (SalesforceExchange) exchange;
+                    final AbstractClientBase client = salesforceExchange.getClient();
+
+                    // update client cache for this and future requests
+                    client.setAccessToken(currentToken);
+                    client.setInstanceUrl(session.getInstanceUrl());
+                    client.setAccessToken(exchange);
+                } else {
+                    exchange.addRequestHeader(HttpHeaders.AUTHORIZATION,
+                        "OAuth " + currentToken);
+                }
+
+                // TODO handle a change in Salesforce instanceUrl, right now we retry with the same destination
+                destination.resend(exchange);
+
+                // resending, exchange is not done
+                return false;
+
+            } catch (SalesforceException e) {
+                // logging here, since login exception is not propagated!
+                LOG.error(e.getMessage(), e);
+
+                // the HTTP status and reason is pushed up
+                setDelegationResult(false);
+            }
+        }
+
+        return true;
+    }
+
+    @Override
+    public void onRetry() {
+        // ignore retries from other interceptors
+        if (retrying) {
+            retrying = false;
+            retries++;
+
+            setDelegatingRequests(true);
+            setDelegatingResponses(true);
+
+            requestComplete = false;
+            responseComplete = false;
+        }
+        super.onRetry();
+    }
+
+    @Override
+    public void onConnectionFailed(Throwable ex) {
+        setDelegatingRequests(true);
+        setDelegatingResponses(true);
+        // delegate connection failures
+        super.onConnectionFailed(ex);
+    }
+
+    @Override
+    public void onException(Throwable ex) {
+        setDelegatingRequests(true);
+        setDelegatingResponses(true);
+        // delegate exceptions
+        super.onException(ex);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/SyncResponseCallback.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/SyncResponseCallback.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/SyncResponseCallback.java
new file mode 100644
index 0000000..0f567e6
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/SyncResponseCallback.java
@@ -0,0 +1,57 @@
+/**
+ * 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.internal.client;
+
+import org.apache.camel.component.salesforce.api.SalesforceException;
+
+import java.io.InputStream;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Thin wrapper to handle callbacks for {@link RestClient.ResponseCallback} and allow waiting for results
+ */
+public class SyncResponseCallback implements RestClient.ResponseCallback {
+
+    private InputStream response;
+    private SalesforceException exception;
+    private CountDownLatch latch = new CountDownLatch(1);
+
+    @Override
+    public void onResponse(InputStream response, SalesforceException exception) {
+        this.response = response;
+        this.exception = exception;
+        latch.countDown();
+    }
+
+    public void reset() {
+        latch = new CountDownLatch(1);
+    }
+
+    public boolean await(long duration, TimeUnit unit) throws InterruptedException {
+        return latch.await(duration, unit);
+    }
+
+    public InputStream getResponse() {
+        return response;
+    }
+
+    public SalesforceException getException() {
+        return exception;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/LoginError.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/LoginError.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/LoginError.java
new file mode 100644
index 0000000..cec3ef8
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/LoginError.java
@@ -0,0 +1,47 @@
+/**
+ * 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.internal.dto;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * DTO for Salesforce login error
+ */
+public class LoginError {
+
+    private String error;
+
+    private String errorDescription;
+
+    public String getError() {
+        return error;
+    }
+
+    public void setError(String error) {
+        this.error = error;
+    }
+
+    @JsonProperty("error_description")
+    public String getErrorDescription() {
+        return errorDescription;
+    }
+
+    @JsonProperty("error_description")
+    public void setErrorDescription(String errorDescription) {
+        this.errorDescription = errorDescription;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/LoginToken.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/LoginToken.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/LoginToken.java
new file mode 100644
index 0000000..c23338e
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/LoginToken.java
@@ -0,0 +1,81 @@
+/**
+ * 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.internal.dto;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * DTO for Salesforce login
+ */
+public class LoginToken {
+
+    private String accessToken;
+
+    private String instanceUrl;
+
+    private String id;
+
+    private String signature;
+
+    private String issuedAt;
+
+    @JsonProperty("access_token")
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    @JsonProperty("access_token")
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
+    }
+
+    @JsonProperty("instance_url")
+    public String getInstanceUrl() {
+        return instanceUrl;
+    }
+
+    @JsonProperty("instance_url")
+    public void setInstanceUrl(String instanceUrl) {
+        this.instanceUrl = instanceUrl;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getSignature() {
+        return signature;
+    }
+
+    public void setSignature(String signature) {
+        this.signature = signature;
+    }
+
+    @JsonProperty("issued_at")
+    public String getIssuedAt() {
+        return issuedAt;
+    }
+
+    @JsonProperty("issued_at")
+    public void setIssuedAt(String issuedAt) {
+        this.issuedAt = issuedAt;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForFieldsEnum.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForFieldsEnum.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForFieldsEnum.java
new file mode 100644
index 0000000..970b9aa
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForFieldsEnum.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.salesforce.internal.dto;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonValue;
+
+/**
+ * Salesforce Enumeration DTO for picklist NotifyForFields
+ */
+public enum NotifyForFieldsEnum {
+
+    SELECT("Select"),
+    WHERE("Where"),
+    REFERENCED("Referenced"),
+    ALL("All");
+
+    final String value;
+
+    private NotifyForFieldsEnum(String value) {
+        this.value = value;
+    }
+
+    @JsonValue
+    public String value() {
+        return this.value;
+    }
+
+    @JsonCreator
+    public static NotifyForFieldsEnum fromValue(String value) {
+        for (NotifyForFieldsEnum e : NotifyForFieldsEnum.values()) {
+            if (e.value.equals(value)) {
+                return e;
+            }
+        }
+        throw new IllegalArgumentException(value);
+    }
+
+}
\ No newline at end of file


[21/23] camel git commit: CAMEL-8575: Applied patch to fix Salesforce security login retries, with thanks to Dmitry Lysai

Posted by dh...@apache.org.
CAMEL-8575: Applied patch to fix Salesforce security login retries, with thanks to Dmitry Lysai


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

Branch: refs/heads/camel-2.12.x
Commit: 49c609843fadf7de86c87710007e2a6553da6d68
Parents: 588abb5
Author: Dhiraj Bokde <dh...@yahoo.com>
Authored: Mon Apr 6 13:28:01 2015 -0700
Committer: Dhiraj Bokde <dh...@yahoo.com>
Committed: Mon Apr 6 13:31:10 2015 -0700

----------------------------------------------------------------------
 .../internal/client/AbstractClientBase.java     | 26 ++++++++---------
 .../salesforce/RestApiIntegrationTest.java      | 30 ++++++++++++++++++++
 2 files changed, 43 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/49c60984/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
index a00d289..b0c7442 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
@@ -103,19 +103,6 @@ public abstract class AbstractClientBase implements SalesforceSession.Salesforce
 
     protected void doHttpRequest(final ContentExchange request, final ClientResponseCallback callback) {
 
-        // use SalesforceSecurityListener for security login retries
-        try {
-            final boolean isHttps = HttpSchemes.HTTPS.equals(String.valueOf(request.getScheme()));
-            request.setEventListener(new SalesforceSecurityListener(
-                    httpClient.getDestination(request.getAddress(), isHttps),
-                    request, session, accessToken));
-        } catch (IOException e) {
-            // propagate exception
-            callback.onResponse(null, new SalesforceException(
-                    String.format("Error registering security listener: %s", e.getMessage()),
-                    e));
-        }
-
         // use HttpEventListener for lifecycle events
         request.setEventListener(new HttpEventListenerWrapper(request.getEventListener(), true) {
 
@@ -169,6 +156,19 @@ public abstract class AbstractClientBase implements SalesforceSession.Salesforce
             }
         });
 
+        // use SalesforceSecurityListener for security login retries
+        try {
+            final boolean isHttps = HttpSchemes.HTTPS.equals(String.valueOf(request.getScheme()));
+            request.setEventListener(new SalesforceSecurityListener(
+                    httpClient.getDestination(request.getAddress(), isHttps),
+                    request, session, accessToken));
+        } catch (IOException e) {
+            // propagate exception
+            callback.onResponse(null, new SalesforceException(
+                    String.format("Error registering security listener: %s", e.getMessage()),
+                    e));
+        }
+
         // execute the request
         try {
             httpClient.send(request);

http://git-wip-us.apache.org/repos/asf/camel/blob/49c60984/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
index 9627cf3..e87a21f 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
@@ -44,7 +44,14 @@ import org.apache.camel.component.salesforce.dto.generated.Document;
 import org.apache.camel.component.salesforce.dto.generated.Line_Item__c;
 import org.apache.camel.component.salesforce.dto.generated.Merchandise__c;
 import org.apache.camel.component.salesforce.dto.generated.QueryRecordsLine_Item__c;
+import org.apache.camel.util.jsse.SSLContextParameters;
+import org.eclipse.jetty.client.ContentExchange;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.client.RedirectListener;
+import org.eclipse.jetty.http.HttpMethods;
 import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -59,6 +66,29 @@ public class RestApiIntegrationTest extends AbstractSalesforceTestBase {
     private static String testId;
 
     @Test
+    public void testRetry() throws Exception {
+        SalesforceComponent sf = context().getComponent("salesforce", SalesforceComponent.class);
+        String accessToken = sf.getSession().getAccessToken();
+
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        sslContextFactory.setSslContext(new SSLContextParameters().createSSLContext());
+        HttpClient httpClient = new HttpClient(sslContextFactory);
+        httpClient.setConnectTimeout(60000);
+        httpClient.setTimeout(60000);
+        httpClient.registerListener(RedirectListener.class.getName());
+        httpClient.start();
+
+        ContentExchange logoutGet = new ContentExchange(true);
+        logoutGet.setURL(sf.getLoginConfig().getLoginUrl() + "/services/oauth2/revoke?token=" + accessToken);
+        logoutGet.setMethod(HttpMethods.GET);
+        httpClient.send(logoutGet);
+        assertEquals(HttpExchange.STATUS_COMPLETED, logoutGet.waitForDone());
+        assertEquals(HttpStatus.OK_200, logoutGet.getResponseStatus());
+
+        doTestGetGlobalObjects("");
+    }
+
+    @Test
     public void testGetVersions() throws Exception {
         doTestGetVersions("");
         doTestGetVersions("Xml");


[03/23] camel git commit: Added Salesforce component

Posted by dh...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForOperationsEnum.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForOperationsEnum.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForOperationsEnum.java
new file mode 100644
index 0000000..807fef5
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/NotifyForOperationsEnum.java
@@ -0,0 +1,52 @@
+/**
+ * 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.internal.dto;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonValue;
+
+/**
+ * Salesforce Enumeration DTO for picklist NotifyForOperations
+ */
+public enum NotifyForOperationsEnum {
+
+    CREATE("Create"),
+    UPDATE("Update"),
+    ALL("All");
+
+    final String value;
+
+    private NotifyForOperationsEnum(String value) {
+        this.value = value;
+    }
+
+    @JsonValue
+    public String value() {
+        return this.value;
+    }
+
+    @JsonCreator
+    public static NotifyForOperationsEnum forValue(String value) {
+        for (NotifyForOperationsEnum e : NotifyForOperationsEnum.values()) {
+            if (e.value.equals(value)) {
+                return e;
+            }
+        }
+        throw new IllegalArgumentException(value);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/PushTopic.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/PushTopic.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/PushTopic.java
new file mode 100644
index 0000000..2135a16
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/PushTopic.java
@@ -0,0 +1,100 @@
+/**
+ * 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.internal.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import com.thoughtworks.xstream.annotations.XStreamConverter;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.apache.camel.component.salesforce.api.PicklistEnumConverter;
+import org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase;
+
+/**
+ * Salesforce DTO for SObject PushTopic
+ */
+@XStreamAlias("PushTopic")
+public class PushTopic extends AbstractSObjectBase {
+
+    private String Query;
+    private Double ApiVersion;
+    private Boolean IsActive;
+    @XStreamConverter(PicklistEnumConverter.class)
+    private NotifyForFieldsEnum NotifyForFields;
+    @XStreamConverter(PicklistEnumConverter.class)
+    private NotifyForOperationsEnum NotifyForOperations;
+    private String Description;
+
+    @JsonProperty("Query")
+    public String getQuery() {
+        return this.Query;
+    }
+
+    @JsonProperty("Query")
+    public void setQuery(String Query) {
+        this.Query = Query;
+    }
+
+    @JsonProperty("ApiVersion")
+    public Double getApiVersion() {
+        return this.ApiVersion;
+    }
+
+    @JsonProperty("ApiVersion")
+    public void setApiVersion(Double ApiVersion) {
+        this.ApiVersion = ApiVersion;
+    }
+
+    @JsonProperty("IsActive")
+    public Boolean getIsActive() {
+        return this.IsActive;
+    }
+
+    @JsonProperty("IsActive")
+    public void setIsActive(Boolean IsActive) {
+        this.IsActive = IsActive;
+    }
+
+    @JsonProperty("NotifyForFields")
+    public NotifyForFieldsEnum getNotifyForFields() {
+        return this.NotifyForFields;
+    }
+
+    @JsonProperty("NotifyForFields")
+    public void setNotifyForFields(NotifyForFieldsEnum NotifyForFields) {
+        this.NotifyForFields = NotifyForFields;
+    }
+
+    @JsonProperty("NotifyForOperations")
+    public NotifyForOperationsEnum getNotifyForOperations() {
+        return this.NotifyForOperations;
+    }
+
+    @JsonProperty("NotifyForOperations")
+    public void setNotifyForOperations(NotifyForOperationsEnum NotifyForOperations) {
+        this.NotifyForOperations = NotifyForOperations;
+    }
+
+    @JsonProperty("Description")
+    public String getDescription() {
+        return this.Description;
+    }
+
+    @JsonProperty("Description")
+    public void setDescription(String Description) {
+        this.Description = Description;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/QueryRecordsPushTopic.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/QueryRecordsPushTopic.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/QueryRecordsPushTopic.java
new file mode 100644
index 0000000..4adc13c
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/QueryRecordsPushTopic.java
@@ -0,0 +1,38 @@
+/**
+ * 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.internal.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+import org.apache.camel.component.salesforce.api.dto.AbstractQueryRecordsBase;
+
+import java.util.List;
+
+/**
+ * Salesforce Query Records DTO for PushTopic
+ */
+public class QueryRecordsPushTopic extends AbstractQueryRecordsBase {
+    @XStreamImplicit
+    private List<PushTopic> records;
+
+    public List<PushTopic> getRecords() {
+        return records;
+    }
+
+    public void setRecords(List<PushTopic> records) {
+        this.records = records;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/RestErrors.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/RestErrors.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/RestErrors.java
new file mode 100644
index 0000000..caf59fe
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/RestErrors.java
@@ -0,0 +1,41 @@
+/**
+ * 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.internal.dto;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+import org.apache.camel.component.salesforce.api.dto.RestError;
+
+import java.util.List;
+
+/**
+ * DTO for Salesforce REST errors
+ */
+@XStreamAlias("Errors")
+public class RestErrors {
+
+    @XStreamImplicit(itemFieldName = "Error")
+    private List<RestError> errors;
+
+    public List<RestError> getErrors() {
+        return errors;
+    }
+
+    public void setErrors(List<RestError> errors) {
+        this.errors = errors;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java
new file mode 100644
index 0000000..1e40d18
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java
@@ -0,0 +1,538 @@
+/**
+ * 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.internal.processor;
+
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.Exchange;
+import org.apache.camel.util.ServiceHelper;
+import org.apache.camel.component.salesforce.SalesforceEndpoint;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase;
+import org.apache.camel.component.salesforce.internal.PayloadFormat;
+import org.apache.camel.component.salesforce.internal.client.DefaultRestClient;
+import org.apache.camel.component.salesforce.internal.client.RestClient;
+
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.*;
+
+public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor {
+
+    protected static final String RESPONSE_CLASS = AbstractRestProcessor.class.getName() + ".responseClass";
+
+    private RestClient restClient;
+    private Map<String, Class<?>> classMap;
+
+    public AbstractRestProcessor(SalesforceEndpoint endpoint) throws SalesforceException {
+        super(endpoint);
+
+        final PayloadFormat payloadFormat = endpoint.getConfiguration().getPayloadFormat();
+
+        this.restClient = new DefaultRestClient(httpClient, endpointConfigMap.get(API_VERSION),
+            payloadFormat.toString().toLowerCase() , session);
+
+        this.classMap = endpoint.getComponent().getClassMap();
+    }
+
+    @Override
+    public void start() throws Exception {
+        ServiceHelper.startService(restClient);
+    }
+
+    @Override
+    public void stop() throws Exception {
+        ServiceHelper.stopService(restClient);
+    }
+
+    @Override
+    public final boolean process(final Exchange exchange, final AsyncCallback callback) {
+
+        // pre-process request message
+        try {
+            processRequest(exchange);
+        } catch (SalesforceException e) {
+            exchange.setException(e);
+            callback.done(true);
+            return true;
+        } catch (RuntimeException e) {
+            exchange.setException(new SalesforceException(e.getMessage(), e));
+            callback.done(true);
+            return true;
+        }
+
+        // call Salesforce asynchronously
+        try {
+
+            // call Operation using REST client
+            switch (operationName) {
+                case GET_VERSIONS:
+                    restClient.getVersions(new RestClient.ResponseCallback() {
+                        @Override
+                        public void onResponse(InputStream response, SalesforceException exception) {
+                            // process response entity and create out message
+                            processResponse(exchange, response, exception, callback);
+                        }
+                    });
+                    break;
+
+                case GET_RESOURCES:
+                    restClient.getResources(new RestClient.ResponseCallback() {
+                        @Override
+                        public void onResponse(InputStream response, SalesforceException exception) {
+                            processResponse(exchange, response, exception, callback);
+                        }
+                    });
+                    break;
+
+                case GET_GLOBAL_OBJECTS:
+                    restClient.getGlobalObjects(new RestClient.ResponseCallback() {
+                        @Override
+                        public void onResponse(InputStream response, SalesforceException exception) {
+                            processResponse(exchange, response, exception, callback);
+                        }
+                    });
+                    break;
+
+                case GET_BASIC_INFO:
+                    String sObjectName = getParameter(SOBJECT_NAME, exchange, USE_BODY, NOT_OPTIONAL);
+                    restClient.getBasicInfo(sObjectName, new RestClient.ResponseCallback() {
+                        @Override
+                        public void onResponse(InputStream response, SalesforceException exception) {
+                            processResponse(exchange, response, exception, callback);
+                        }
+                    });
+                    break;
+
+                case GET_DESCRIPTION:
+                    sObjectName = getParameter(SOBJECT_NAME, exchange, USE_BODY, NOT_OPTIONAL);
+                    restClient.getDescription(sObjectName, new RestClient.ResponseCallback() {
+                        @Override
+                        public void onResponse(InputStream response, SalesforceException exception) {
+                            processResponse(exchange, response, exception, callback);
+                        }
+                    });
+                    break;
+
+                case GET_SOBJECT:
+                {
+                    String sObjectIdValue;
+                    // determine parameters from input AbstractSObject
+                    final AbstractSObjectBase sObjectBase = exchange.getIn().getBody(AbstractSObjectBase.class);
+                    if (sObjectBase != null) {
+                        sObjectName = sObjectBase.getClass().getSimpleName();
+                        sObjectIdValue = sObjectBase.getId();
+                    } else {
+                        sObjectName = getParameter(SOBJECT_NAME, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                        sObjectIdValue = getParameter(SOBJECT_ID, exchange, USE_BODY, NOT_OPTIONAL);
+                    }
+                    final String sObjectId = sObjectIdValue;
+
+                    // use sObject name to load class
+                    setResponseClass(exchange, sObjectName);
+
+                    // get optional field list
+                    String fieldsValue = getParameter(SOBJECT_FIELDS, exchange, IGNORE_BODY, IS_OPTIONAL);
+                    String[] fields = null;
+                    if (fieldsValue != null) {
+                        fields = fieldsValue.split(",");
+                    }
+
+                    restClient.getSObject(sObjectName, sObjectId, fields, new RestClient.ResponseCallback() {
+                        @Override
+                        public void onResponse(InputStream response, SalesforceException exception) {
+                            processResponse(exchange, response, exception, callback);
+                            restoreFields(exchange, sObjectBase, sObjectId, null, null);
+                        }
+                    });
+
+                    break;
+                }
+
+                case CREATE_SOBJECT:
+                {
+                    // determine parameters from input AbstractSObject
+                    AbstractSObjectBase sObjectBase = exchange.getIn().getBody(AbstractSObjectBase.class);
+                    if (sObjectBase != null) {
+                        sObjectName = sObjectBase.getClass().getSimpleName();
+                    } else {
+                        sObjectName = getParameter(SOBJECT_NAME, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                    }
+
+                    restClient.createSObject(sObjectName, getRequestStream(exchange),
+                        new RestClient.ResponseCallback() {
+                        @Override
+                        public void onResponse(InputStream response, SalesforceException exception) {
+                            processResponse(exchange, response, exception, callback);
+                        }
+                    });
+
+                    break;
+                }
+
+                case UPDATE_SOBJECT:
+                {
+                    // determine parameters from input AbstractSObject
+                    final AbstractSObjectBase sObjectBase = exchange.getIn().getBody(AbstractSObjectBase.class);
+                    String sObjectId;
+                    if (sObjectBase != null) {
+                        sObjectName = sObjectBase.getClass().getSimpleName();
+                        // remember the sObject Id
+                        sObjectId = sObjectBase.getId();
+                        // clear base object fields, which cannot be updated
+                        sObjectBase.clearBaseFields();
+                    } else {
+                        sObjectName = getParameter(SOBJECT_NAME, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                        sObjectId = getParameter(SOBJECT_ID, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                    }
+
+                    final String finalsObjectId = sObjectId;
+                    restClient.updateSObject(sObjectName, sObjectId, getRequestStream(exchange),
+                        new RestClient.ResponseCallback() {
+                            @Override
+                            public void onResponse(InputStream response, SalesforceException exception) {
+                                processResponse(exchange, response, exception, callback);
+                                restoreFields(exchange, sObjectBase, finalsObjectId, null, null);
+                            }
+                        });
+
+                    break;
+                }
+
+                case DELETE_SOBJECT:
+                {
+                    // determine parameters from input AbstractSObject
+                    final AbstractSObjectBase sObjectBase = exchange.getIn().getBody(AbstractSObjectBase.class);
+                    String sObjectIdValue;
+                    if (sObjectBase != null) {
+                        sObjectName = sObjectBase.getClass().getSimpleName();
+                        sObjectIdValue = sObjectBase.getId();
+                    } else {
+                        sObjectName = getParameter(SOBJECT_NAME, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                        sObjectIdValue = getParameter(SOBJECT_ID, exchange, USE_BODY, NOT_OPTIONAL);
+                    }
+                    final String sObjectId = sObjectIdValue;
+
+                    restClient.deleteSObject(sObjectName, sObjectId, new RestClient.ResponseCallback() {
+                        @Override
+                        public void onResponse(InputStream response, SalesforceException exception) {
+                            processResponse(exchange, response, exception, callback);
+                            restoreFields(exchange, sObjectBase, sObjectId, null, null);
+                        }
+                    });
+                    break;
+                }
+
+                case GET_SOBJECT_WITH_ID:
+                {
+                    Object oldValue = null;
+                    String sObjectExtIdValue;
+                    final String sObjectExtIdName = getParameter(SOBJECT_EXT_ID_NAME,
+                        exchange, IGNORE_BODY, NOT_OPTIONAL);
+
+                    // determine parameters from input AbstractSObject
+                    final AbstractSObjectBase sObjectBase = exchange.getIn().getBody(AbstractSObjectBase.class);
+                    if (sObjectBase != null) {
+                        sObjectName = sObjectBase.getClass().getSimpleName();
+                        oldValue = getAndClearPropertyValue(sObjectBase, sObjectExtIdName);
+                        sObjectExtIdValue = oldValue.toString();
+                    } else {
+                        sObjectName = getParameter(SOBJECT_NAME, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                        sObjectExtIdValue = getParameter(SOBJECT_EXT_ID_VALUE, exchange, USE_BODY, NOT_OPTIONAL);
+                    }
+
+                    // use sObject name to load class
+                    setResponseClass(exchange, sObjectName);
+
+                    final Object finalOldValue = oldValue;
+                    restClient.getSObjectWithId(sObjectName, sObjectExtIdName, sObjectExtIdValue,
+                        new RestClient.ResponseCallback() {
+                            @Override
+                            public void onResponse(InputStream response, SalesforceException exception) {
+                                processResponse(exchange, response, exception, callback);
+                                restoreFields(exchange, sObjectBase, null, sObjectExtIdName, finalOldValue);
+                            }
+                        });
+
+                    break;
+                }
+
+                case UPSERT_SOBJECT:
+                {
+                    String sObjectExtIdValue;
+                    final String sObjectExtIdName = getParameter(SOBJECT_EXT_ID_NAME, exchange,
+                        IGNORE_BODY, NOT_OPTIONAL);
+
+                    // determine parameters from input AbstractSObject
+                    Object oldValue = null;
+                    final AbstractSObjectBase sObjectBase = exchange.getIn().getBody(AbstractSObjectBase.class);
+                    if (sObjectBase != null) {
+                        sObjectName = sObjectBase.getClass().getSimpleName();
+                        oldValue = getAndClearPropertyValue(sObjectBase, sObjectExtIdName);
+                        sObjectExtIdValue = oldValue.toString();
+                        // clear base object fields, which cannot be updated
+                        sObjectBase.clearBaseFields();
+                    } else {
+                        sObjectName = getParameter(SOBJECT_NAME, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                        sObjectExtIdValue = getParameter(SOBJECT_EXT_ID_VALUE, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                    }
+
+                    final Object finalOldValue = oldValue;
+                    restClient.upsertSObject(sObjectName, sObjectExtIdName, sObjectExtIdValue,
+                        getRequestStream(exchange), new RestClient.ResponseCallback() {
+                        @Override
+                        public void onResponse(InputStream response, SalesforceException exception) {
+                            processResponse(exchange, response, exception, callback);
+                            restoreFields(exchange, sObjectBase, null, sObjectExtIdName, finalOldValue);
+                        }
+                    });
+
+                    break;
+                }
+
+                case DELETE_SOBJECT_WITH_ID:
+                {
+                    final String sObjectExtIdName = getParameter(SOBJECT_EXT_ID_NAME, exchange, IGNORE_BODY, NOT_OPTIONAL);
+
+                    // determine parameters from input AbstractSObject
+                    Object oldValue = null;
+                    final AbstractSObjectBase sObjectBase = exchange.getIn().getBody(AbstractSObjectBase.class);
+                    String sObjectExtIdValue;
+                    if (sObjectBase != null) {
+                        sObjectName = sObjectBase.getClass().getSimpleName();
+                        oldValue = getAndClearPropertyValue(sObjectBase, sObjectExtIdName);
+                        sObjectExtIdValue = oldValue.toString();
+                    } else {
+                        sObjectName = getParameter(SOBJECT_NAME, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                        sObjectExtIdValue = getParameter(SOBJECT_EXT_ID_VALUE, exchange, USE_BODY, NOT_OPTIONAL);
+                    }
+
+                    final Object finalOldValue = oldValue;
+                    restClient.deleteSObjectWithId(sObjectName, sObjectExtIdName, sObjectExtIdValue,
+                        new RestClient.ResponseCallback() {
+                            @Override
+                            public void onResponse(InputStream response, SalesforceException exception) {
+                                processResponse(exchange, response, exception, callback);
+                                restoreFields(exchange, sObjectBase, null, sObjectExtIdName, finalOldValue);
+                            }
+                        });
+
+                    break;
+                }
+
+                case GET_BLOB_FIELD:
+                {
+                    // get blob field name
+                    final String sObjectBlobFieldName = getParameter(SOBJECT_BLOB_FIELD_NAME,
+                        exchange, IGNORE_BODY, NOT_OPTIONAL);
+
+                    // determine parameters from input AbstractSObject
+                    final AbstractSObjectBase sObjectBase = exchange.getIn().getBody(AbstractSObjectBase.class);
+                    String sObjectIdValue;
+                    if (sObjectBase != null) {
+                        sObjectName = sObjectBase.getClass().getSimpleName();
+                        sObjectIdValue = sObjectBase.getId();
+                    } else {
+                        sObjectName = getParameter(SOBJECT_NAME, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                        sObjectIdValue = getParameter(SOBJECT_ID, exchange, USE_BODY, NOT_OPTIONAL);
+                    }
+                    final String sObjectId = sObjectIdValue;
+
+                    restClient.getBlobField(sObjectName, sObjectId, sObjectBlobFieldName,
+                        new RestClient.ResponseCallback() {
+                            @Override
+                            public void onResponse(InputStream response, SalesforceException exception) {
+                                processResponse(exchange, response, exception, callback);
+                                restoreFields(exchange, sObjectBase, sObjectId, null, null);
+                            }
+                        });
+                    break;
+                }
+
+                case QUERY:
+                    final String sObjectQuery = getParameter(SOBJECT_QUERY, exchange, USE_BODY, NOT_OPTIONAL);
+
+                    // use sObject name to load class
+                    setResponseClass(exchange, null);
+
+                    restClient.query(sObjectQuery, new RestClient.ResponseCallback() {
+                        @Override
+                        public void onResponse(InputStream response, SalesforceException exception) {
+                            processResponse(exchange, response, exception, callback);
+                        }
+                    });
+                    break;
+
+                case QUERY_MORE:
+                    // reuse SOBJECT_QUERY parameter name for nextRecordsUrl
+                    final String nextRecordsUrl = getParameter(SOBJECT_QUERY, exchange, USE_BODY, NOT_OPTIONAL);
+
+                    // use custom response class property
+                    setResponseClass(exchange, null);
+
+                    restClient.queryMore(nextRecordsUrl, new RestClient.ResponseCallback() {
+                        @Override
+                        public void onResponse(InputStream response, SalesforceException exception) {
+                            processResponse(exchange, response, exception, callback);
+                        }
+                    });
+                    break;
+
+                case SEARCH:
+                    final String sObjectSearch = getParameter(SOBJECT_SEARCH, exchange, USE_BODY, NOT_OPTIONAL);
+
+                    restClient.search(sObjectSearch, new RestClient.ResponseCallback() {
+                        @Override
+                        public void onResponse(InputStream response, SalesforceException exception) {
+                            processResponse(exchange, response, exception, callback);
+                        }
+                    });
+                    break;
+
+            }
+
+        } catch (SalesforceException e) {
+            exchange.setException(new SalesforceException(
+                String.format("Error processing %s: [%s] \"%s\"",
+                    operationName, e.getStatusCode(), e.getMessage()),
+                e));
+            callback.done(true);
+            return true;
+        } catch (RuntimeException e) {
+            exchange.setException(new SalesforceException(
+                String.format("Unexpected Error processing %s: \"%s\"",
+                    operationName, e.getMessage()),
+                e));
+            callback.done(true);
+            return true;
+        }
+
+        // continue routing asynchronously
+        return false;
+    }
+
+    private void restoreFields(Exchange exchange, AbstractSObjectBase sObjectBase,
+                               String sObjectId, String sObjectExtIdName, Object oldValue) {
+        // restore fields
+        if (sObjectBase != null) {
+            // restore the Id if it was cleared
+            if (sObjectId != null) {
+                sObjectBase.setId(sObjectId);
+            }
+            // restore the external id if it was cleared
+            if (sObjectExtIdName != null && oldValue != null) {
+                try {
+                    setPropertyValue(sObjectBase, sObjectExtIdName, oldValue);
+                } catch (SalesforceException e) {
+                    // YES, the exchange may fail if the property cannot be reset!!!
+                    exchange.setException(e);
+                }
+            }
+        }
+    }
+
+    private void setPropertyValue(AbstractSObjectBase sObjectBase, String name, Object value) throws SalesforceException {
+        try {
+            // set the value with the set method
+            Method setMethod = sObjectBase.getClass().getMethod("set" + name, value.getClass());
+            setMethod.invoke(sObjectBase, value);
+        } catch (NoSuchMethodException e) {
+            throw new SalesforceException(
+                String.format("SObject %s does not have a field %s",
+                    sObjectBase.getClass().getName(), name),
+                e);
+        } catch (InvocationTargetException e) {
+            throw new SalesforceException(
+                String.format("Error setting value %s.%s",
+                    sObjectBase.getClass().getSimpleName(), name),
+                e);
+        } catch (IllegalAccessException e) {
+            throw new SalesforceException(
+                String.format("Error accessing value %s.%s",
+                    sObjectBase.getClass().getSimpleName(), name),
+                e);
+        }
+    }
+
+    private Object getAndClearPropertyValue(AbstractSObjectBase sObjectBase, String propertyName) throws SalesforceException {
+        try {
+            // obtain the value using the get method
+            Method getMethod = sObjectBase.getClass().getMethod("get" + propertyName);
+            Object value = getMethod.invoke(sObjectBase);
+
+            // clear the value with the set method
+            Method setMethod = sObjectBase.getClass().getMethod("set" + propertyName, getMethod.getReturnType());
+            setMethod.invoke(sObjectBase, new Object[] { null });
+
+            return value;
+        } catch (NoSuchMethodException e) {
+            throw new SalesforceException(
+                String.format("SObject %s does not have a field %s",
+                    sObjectBase.getClass().getSimpleName(), propertyName),
+                e);
+        } catch (InvocationTargetException e) {
+            throw new SalesforceException(
+                String.format("Error getting/setting value %s.%s",
+                    sObjectBase.getClass().getSimpleName(), propertyName),
+                e);
+        } catch (IllegalAccessException e) {
+            throw new SalesforceException(
+                String.format("Error accessing value %s.%s",
+                    sObjectBase.getClass().getSimpleName(), propertyName),
+                e);
+        }
+    }
+
+    // pre-process request message
+    protected abstract void processRequest(Exchange exchange) throws SalesforceException;
+
+    // get request stream from In message
+    protected abstract InputStream getRequestStream(Exchange exchange) throws SalesforceException;
+
+    private void setResponseClass(Exchange exchange, String sObjectName) throws SalesforceException {
+        Class<?> sObjectClass;
+
+        if (sObjectName != null) {
+            // lookup class from class map
+            sObjectClass = classMap.get(sObjectName);
+            if (null == sObjectClass) {
+                throw new SalesforceException(String.format("No class found for SObject %s", sObjectName), null);
+            }
+
+        } else {
+
+            // use custom response class property
+            final String className = getParameter(SOBJECT_CLASS, exchange, IGNORE_BODY, NOT_OPTIONAL);
+            try {
+                sObjectClass = endpoint.getComponent().getCamelContext()
+                    .getClassResolver().resolveMandatoryClass(className);
+            } catch (ClassNotFoundException e) {
+                throw new SalesforceException(
+                    String.format("SObject class not found %s, %s",
+                        className, e.getMessage()),
+                    e);
+            }
+        }
+        exchange.setProperty(RESPONSE_CLASS, sObjectClass);
+    }
+
+    // process response entity and set out message in exchange
+    protected abstract void processResponse(Exchange exchange, InputStream responseEntity, SalesforceException ex, AsyncCallback callback);
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractSalesforceProcessor.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractSalesforceProcessor.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractSalesforceProcessor.java
new file mode 100644
index 0000000..e784458
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractSalesforceProcessor.java
@@ -0,0 +1,84 @@
+/**
+ * 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.internal.processor;
+
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.Exchange;
+import org.eclipse.jetty.client.HttpClient;
+import org.apache.camel.component.salesforce.SalesforceComponent;
+import org.apache.camel.component.salesforce.SalesforceEndpoint;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.internal.OperationName;
+import org.apache.camel.component.salesforce.internal.SalesforceSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+
+public abstract class AbstractSalesforceProcessor implements SalesforceProcessor {
+
+    protected static final boolean NOT_OPTIONAL = false;
+    protected static final boolean IS_OPTIONAL = true;
+    protected static final boolean USE_BODY = true;
+    protected static final boolean IGNORE_BODY = false;
+    protected final Logger LOG = LoggerFactory.getLogger(this.getClass());
+
+    protected final SalesforceEndpoint endpoint;
+    protected final Map<String, String> endpointConfigMap;
+
+    protected final OperationName operationName;
+    protected final SalesforceSession session;
+    protected final HttpClient httpClient;
+
+    public AbstractSalesforceProcessor(SalesforceEndpoint endpoint) {
+        this.endpoint = endpoint;
+        this.operationName = endpoint.getOperationName();
+        this.endpointConfigMap = endpoint.getConfiguration().toValueMap();
+
+        final SalesforceComponent component = endpoint.getComponent();
+        this.session = component.getSession();
+        this.httpClient = endpoint.getConfiguration().getHttpClient();
+    }
+
+    @Override
+    public abstract boolean process(Exchange exchange, AsyncCallback callback);
+
+    /**
+     * Gets value for a parameter from header, endpoint config, or exchange body (optional).
+     *
+     * @param exchange exchange to inspect
+     * @param convertInBody converts In body to String value if true
+     * @param propName name of property
+     * @param optional if {@code true} returns null, otherwise throws RestException
+     * @return value of property, or {@code null} for optional parameters if not found.
+     * @throws org.apache.camel.component.salesforce.api.SalesforceException if the property can't be found.
+     */
+    protected final String getParameter(String propName, Exchange exchange, boolean convertInBody, boolean optional) throws SalesforceException {
+        String propValue = exchange.getIn().getHeader(propName, String.class);
+        propValue = propValue == null ? endpointConfigMap.get(propName) : propValue;
+        propValue = (propValue == null && convertInBody) ? exchange.getIn().getBody(String.class) : propValue;
+
+        // error if property was not set
+        if (propValue == null && !optional) {
+            String msg = "Missing property " + propName;
+            throw new SalesforceException(msg, null);
+        }
+
+        return propValue;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/BulkApiProcessor.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/BulkApiProcessor.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/BulkApiProcessor.java
new file mode 100644
index 0000000..6e070f7
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/BulkApiProcessor.java
@@ -0,0 +1,377 @@
+/**
+ * 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.internal.processor;
+
+import org.apache.camel.*;
+import org.apache.camel.converter.stream.StreamCacheConverter;
+import org.apache.camel.util.ServiceHelper;
+import org.apache.camel.component.salesforce.SalesforceEndpoint;
+import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.bulk.*;
+import org.apache.camel.component.salesforce.internal.client.BulkApiClient;
+import org.apache.camel.component.salesforce.internal.client.DefaultBulkApiClient;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.*;
+
+public class BulkApiProcessor extends AbstractSalesforceProcessor {
+
+    private BulkApiClient bulkClient;
+
+    public BulkApiProcessor(SalesforceEndpoint endpoint) throws SalesforceException {
+        super(endpoint);
+
+        this.bulkClient = new DefaultBulkApiClient(
+            endpointConfigMap.get(SalesforceEndpointConfig.API_VERSION), session, httpClient);
+    }
+
+    @Override
+    public boolean process(final Exchange exchange, final AsyncCallback callback) {
+
+        boolean done = false;
+        try {
+            switch (operationName) {
+                case CREATE_JOB:
+                    JobInfo jobBody = exchange.getIn().getMandatoryBody(JobInfo.class);
+                    bulkClient.createJob(jobBody, new BulkApiClient.JobInfoResponseCallback() {
+                        @Override
+                        public void onResponse(JobInfo jobInfo, SalesforceException ex) {
+                            processResponse(exchange, jobInfo, ex, callback);
+                        }
+                    });
+
+                    break;
+
+                case GET_JOB:
+                    jobBody = exchange.getIn().getBody(JobInfo.class);
+                    String jobId;
+                    if (jobBody != null) {
+                        jobId = jobBody.getId();
+                    } else {
+                        jobId = getParameter(JOB_ID, exchange, USE_BODY, NOT_OPTIONAL);
+                    }
+                    bulkClient.getJob(jobId, new BulkApiClient.JobInfoResponseCallback() {
+                        @Override
+                        public void onResponse(JobInfo jobInfo, SalesforceException ex) {
+                            processResponse(exchange, jobInfo, ex, callback);
+                        }
+                    });
+
+                    break;
+
+                case CLOSE_JOB:
+                    jobBody = exchange.getIn().getBody(JobInfo.class);
+                    if (jobBody != null) {
+                        jobId = jobBody.getId();
+                    } else {
+                        jobId = getParameter(JOB_ID, exchange, USE_BODY, NOT_OPTIONAL);
+                    }
+                    bulkClient.closeJob(jobId, new BulkApiClient.JobInfoResponseCallback() {
+                        @Override
+                        public void onResponse(JobInfo jobInfo, SalesforceException ex) {
+                            processResponse(exchange, jobInfo, ex, callback);
+                        }
+                    });
+
+                    break;
+
+                case ABORT_JOB:
+                    jobBody = exchange.getIn().getBody(JobInfo.class);
+                    if (jobBody != null) {
+                        jobId = jobBody.getId();
+                    } else {
+                        jobId = getParameter(JOB_ID, exchange, USE_BODY, NOT_OPTIONAL);
+                    }
+                    bulkClient.abortJob(jobId, new BulkApiClient.JobInfoResponseCallback() {
+                        @Override
+                        public void onResponse(JobInfo jobInfo, SalesforceException ex) {
+                            processResponse(exchange, jobInfo, ex, callback);
+                        }
+                    });
+
+                    break;
+
+                case CREATE_BATCH:
+                    // since request is in the body, use headers or endpoint params
+                    ContentType contentType = ContentType.fromValue(
+                        getParameter(CONTENT_TYPE, exchange, IGNORE_BODY, NOT_OPTIONAL));
+                    jobId = getParameter(JOB_ID, exchange, IGNORE_BODY, NOT_OPTIONAL);
+
+                    InputStream request;
+                    try {
+                        request = exchange.getIn().getMandatoryBody(InputStream.class);
+                    } catch (CamelException e) {
+                        String msg = "Error preparing batch request: " + e.getMessage();
+                        throw new SalesforceException(msg, e);
+                    }
+
+                    bulkClient.createBatch(request, jobId, contentType, new BulkApiClient.BatchInfoResponseCallback() {
+                        @Override
+                        public void onResponse(BatchInfo batchInfo, SalesforceException ex) {
+                            processResponse(exchange, batchInfo, ex, callback);
+                        }
+                    });
+
+                    break;
+
+                case GET_BATCH:
+                    BatchInfo batchBody = exchange.getIn().getBody(BatchInfo.class);
+                    String batchId;
+                    if (batchBody != null) {
+                        jobId = batchBody.getJobId();
+                        batchId = batchBody.getId();
+                    } else {
+                        jobId = getParameter(JOB_ID, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                        batchId = getParameter(BATCH_ID, exchange, USE_BODY, NOT_OPTIONAL);
+                    }
+                    bulkClient.getBatch(jobId, batchId, new BulkApiClient.BatchInfoResponseCallback() {
+                        @Override
+                        public void onResponse(BatchInfo batchInfo, SalesforceException ex) {
+                            processResponse(exchange, batchInfo, ex, callback);
+                        }
+                    });
+
+                    break;
+
+                case GET_ALL_BATCHES:
+                    jobBody = exchange.getIn().getBody(JobInfo.class);
+                    if (jobBody != null) {
+                        jobId = jobBody.getId();
+                    } else {
+                        jobId = getParameter(JOB_ID, exchange, USE_BODY, NOT_OPTIONAL);
+                    }
+                    bulkClient.getAllBatches(jobId, new BulkApiClient.BatchInfoListResponseCallback() {
+                        @Override
+                        public void onResponse(List<BatchInfo> batchInfoList, SalesforceException ex) {
+                            processResponse(exchange, batchInfoList, ex, callback);
+                        }
+                    });
+
+                    break;
+
+                case GET_REQUEST:
+                    batchBody = exchange.getIn().getBody(BatchInfo.class);
+                    if (batchBody != null) {
+                        jobId = batchBody.getJobId();
+                        batchId = batchBody.getId();
+                    } else {
+                        jobId = getParameter(JOB_ID, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                        batchId = getParameter(BATCH_ID, exchange, USE_BODY, NOT_OPTIONAL);
+                    }
+
+                    bulkClient.getRequest(jobId, batchId, new BulkApiClient.StreamResponseCallback() {
+                        @Override
+                        public void onResponse(InputStream inputStream, SalesforceException ex) {
+                            // read the request stream into a StreamCache temp file
+                            // ensures the connection is read
+                            StreamCache body = null;
+                            if (inputStream != null) {
+                                try {
+                                    body = StreamCacheConverter.convertToStreamCache(inputStream, exchange);
+                                } catch (IOException e) {
+                                    String msg = "Error retrieving batch request: " + e.getMessage();
+                                    ex = new SalesforceException(msg, e);
+                                } finally {
+                                    // close the input stream to release the Http connection
+                                    try {
+                                        inputStream.close();
+                                    } catch (IOException ignore) {
+                                    }
+                                }
+                            }
+                            processResponse(exchange, body, ex, callback);
+                        }
+                    });
+
+                    break;
+
+                case GET_RESULTS:
+                    batchBody = exchange.getIn().getBody(BatchInfo.class);
+                    if (batchBody != null) {
+                        jobId = batchBody.getJobId();
+                        batchId = batchBody.getId();
+                    } else {
+                        jobId = getParameter(JOB_ID, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                        batchId = getParameter(BATCH_ID, exchange, USE_BODY, NOT_OPTIONAL);
+                    }
+                    bulkClient.getResults(jobId, batchId, new BulkApiClient.StreamResponseCallback() {
+                        @Override
+                        public void onResponse(InputStream inputStream, SalesforceException ex) {
+                            // read the result stream into a StreamCache temp file
+                            // ensures the connection is read
+                            StreamCache body = null;
+                            if (inputStream != null) {
+                                try {
+                                    body = StreamCacheConverter.convertToStreamCache(inputStream, exchange);
+                                } catch (IOException e) {
+                                    String msg = "Error retrieving batch results: " + e.getMessage();
+                                    ex = new SalesforceException(msg, e);
+                                } finally {
+                                    // close the input stream to release the Http connection
+                                    try {
+                                        inputStream.close();
+                                    } catch (IOException ignore) {
+                                    }
+                                }
+                            }
+                            processResponse(exchange, body, ex, callback);
+                        }
+                    });
+
+                    break;
+
+                case CREATE_BATCH_QUERY:
+                    jobBody = exchange.getIn().getBody(JobInfo.class);
+                    String soqlQuery;
+                    if (jobBody != null) {
+                        jobId = jobBody.getId();
+                        contentType = jobBody.getContentType();
+                        // use SOQL query from header or endpoint config
+                        soqlQuery = getParameter(SOBJECT_QUERY, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                    } else {
+                        jobId = getParameter(JOB_ID, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                        contentType = ContentType.fromValue(
+                            getParameter(CONTENT_TYPE, exchange, IGNORE_BODY, NOT_OPTIONAL));
+                        // reuse SOBJECT_QUERY property
+                        soqlQuery = getParameter(SOBJECT_QUERY, exchange, USE_BODY, NOT_OPTIONAL);
+                    }
+                    bulkClient.createBatchQuery(jobId, soqlQuery, contentType,
+                        new BulkApiClient.BatchInfoResponseCallback() {
+                        @Override
+                        public void onResponse(BatchInfo batchInfo, SalesforceException ex) {
+                            processResponse(exchange, batchInfo, ex, callback);
+                        }
+                    });
+
+                    break;
+
+                case GET_QUERY_RESULT_IDS:
+                    batchBody = exchange.getIn().getBody(BatchInfo.class);
+                    if (batchBody != null) {
+                        jobId = batchBody.getJobId();
+                        batchId = batchBody.getId();
+                    } else {
+                        jobId = getParameter(JOB_ID, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                        batchId = getParameter(BATCH_ID, exchange, USE_BODY, NOT_OPTIONAL);
+                    }
+                    bulkClient.getQueryResultIds(jobId, batchId, new BulkApiClient.QueryResultIdsCallback() {
+                        @Override
+                        public void onResponse(List<String> ids, SalesforceException ex) {
+                            processResponse(exchange, ids, ex, callback);
+                        }
+                    });
+
+                    break;
+
+                case GET_QUERY_RESULT:
+                    batchBody = exchange.getIn().getBody(BatchInfo.class);
+                    String resultId;
+                    if (batchBody != null) {
+                        jobId = batchBody.getJobId();
+                        batchId = batchBody.getId();
+                        resultId = getParameter(RESULT_ID, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                    } else {
+                        jobId = getParameter(JOB_ID, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                        batchId = getParameter(BATCH_ID, exchange, IGNORE_BODY, NOT_OPTIONAL);
+                        resultId = getParameter(RESULT_ID, exchange, USE_BODY, NOT_OPTIONAL);
+                    }
+                    bulkClient.getQueryResult(jobId, batchId, resultId, new BulkApiClient.StreamResponseCallback() {
+                        @Override
+                        public void onResponse(InputStream inputStream, SalesforceException ex) {
+                            StreamCache body = null;
+                            if (inputStream != null) {
+                                // read the result stream into a StreamCache temp file
+                                // ensures the connection is read
+                                try {
+                                    body = StreamCacheConverter.convertToStreamCache(inputStream, exchange);
+                                } catch (IOException e) {
+                                    String msg = "Error retrieving query result: " + e.getMessage();
+                                    ex = new SalesforceException(msg, e);
+                                } finally {
+                                    // close the input stream to release the Http connection
+                                    try {
+                                        inputStream.close();
+                                    } catch (IOException e) {
+                                        // ignore
+                                    }
+                                }
+                            }
+                            processResponse(exchange, body, ex, callback);
+                        }
+                    });
+
+                    break;
+            }
+
+        } catch (SalesforceException e) {
+            exchange.setException(new SalesforceException(
+                String.format("Error processing %s: [%s] \"%s\"",
+                    operationName, e.getStatusCode(), e.getMessage()),
+                e));
+            callback.done(true);
+            done = true;
+        } catch (InvalidPayloadException e) {
+            exchange.setException(new SalesforceException(
+                String.format("Unexpected Error processing %s: \"%s\"",
+                    operationName, e.getMessage()),
+                e));
+            callback.done(true);
+            done = true;
+        } catch (RuntimeException e) {
+            exchange.setException(new SalesforceException(
+                String.format("Unexpected Error processing %s: \"%s\"",
+                    operationName, e.getMessage()),
+                e));
+            callback.done(true);
+            done = true;
+        }
+
+        // continue routing asynchronously if false
+        return done;
+    }
+
+    private void processResponse(Exchange exchange, Object body, SalesforceException ex, AsyncCallback callback) {
+        final Message out = exchange.getOut();
+        if (ex != null) {
+            exchange.setException(ex);
+        } else {
+            out.setBody(body);
+        }
+
+        // copy headers and attachments
+        out.getHeaders().putAll(exchange.getIn().getHeaders());
+        out.getAttachments().putAll(exchange.getIn().getAttachments());
+
+        // signal exchange completion
+        callback.done(false);
+    }
+
+    @Override
+    public void start() throws Exception {
+        ServiceHelper.startService(bulkClient);
+    }
+
+    @Override
+    public void stop() throws Exception {
+        // stop the client
+        ServiceHelper.stopService(bulkClient);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java
new file mode 100644
index 0000000..3ac32c6
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java
@@ -0,0 +1,180 @@
+/**
+ * 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.internal.processor;
+
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.SerializationConfig;
+import org.codehaus.jackson.type.TypeReference;
+import org.eclipse.jetty.util.StringUtil;
+import org.apache.camel.component.salesforce.SalesforceEndpoint;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.*;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+public class JsonRestProcessor extends AbstractRestProcessor {
+
+    // it is ok to use a single thread safe ObjectMapper
+    private final ObjectMapper objectMapper;
+    private static final String RESPONSE_TYPE = JsonRestProcessor.class.getName() + ".responseType";
+
+    public JsonRestProcessor(SalesforceEndpoint endpoint) throws SalesforceException {
+        super(endpoint);
+
+        this.objectMapper = new ObjectMapper();
+        // enable date time support including Joda DateTime
+        this.objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
+    }
+
+    @Override
+    protected void processRequest(Exchange exchange) {
+
+        switch (operationName) {
+            case GET_VERSIONS:
+                // handle in built response types
+                exchange.setProperty(RESPONSE_TYPE, new TypeReference<List<Version>>() {});
+                break;
+
+            case GET_RESOURCES:
+                // handle in built response types
+                exchange.setProperty(RESPONSE_CLASS, RestResources.class);
+                break;
+
+            case GET_GLOBAL_OBJECTS:
+                // handle in built response types
+                exchange.setProperty(RESPONSE_CLASS, GlobalObjects.class);
+                break;
+
+            case GET_BASIC_INFO:
+                // handle in built response types
+                exchange.setProperty(RESPONSE_CLASS, SObjectBasicInfo.class);
+                break;
+
+            case GET_DESCRIPTION:
+                // handle in built response types
+                exchange.setProperty(RESPONSE_CLASS, SObjectDescription.class);
+                break;
+
+            case CREATE_SOBJECT:
+                // handle known response type
+                exchange.setProperty(RESPONSE_CLASS, CreateSObjectResult.class);
+                break;
+
+            case UPSERT_SOBJECT:
+                // handle known response type
+                exchange.setProperty(RESPONSE_CLASS, CreateSObjectResult.class);
+                break;
+
+            case SEARCH:
+                // handle known response type
+                exchange.setProperty(RESPONSE_TYPE, new TypeReference<List<SearchResult>>() {});
+                break;
+
+        }
+    }
+
+    @Override
+    protected InputStream getRequestStream(Exchange exchange) throws SalesforceException {
+        try {
+            InputStream request;
+            Message in = exchange.getIn();
+            request = in.getBody(InputStream.class);
+            if (request == null) {
+                AbstractSObjectBase sObject = in.getBody(AbstractSObjectBase.class);
+                if (sObject != null) {
+                    // marshall the SObject
+                    ByteArrayOutputStream out = new ByteArrayOutputStream();
+                    objectMapper.writeValue(out, sObject);
+                    request = new ByteArrayInputStream(out.toByteArray());
+                } else {
+                    // if all else fails, get body as String
+                    final String body = in.getBody(String.class);
+                    if (null == body) {
+                        String msg = "Unsupported request message body " +
+                            (in.getBody() == null ? null : in.getBody().getClass());
+                        throw new SalesforceException(msg, null);
+                    } else {
+                        request = new ByteArrayInputStream(body.getBytes(StringUtil.__UTF8_CHARSET));
+                    }
+                }
+            }
+
+            return request;
+
+        } catch (IOException e) {
+            String msg = "Error marshaling request: " + e.getMessage();
+            throw new SalesforceException(msg, e);
+        }
+    }
+
+    @Override
+    protected void processResponse(Exchange exchange, InputStream responseEntity, SalesforceException ex, AsyncCallback callback) {
+
+        // process JSON response for TypeReference
+        try {
+            // do we need to un-marshal a response
+            if (responseEntity != null) {
+                Object response = null;
+                Class<?> responseClass = exchange.getProperty(RESPONSE_CLASS, Class.class);
+                if (responseClass != null) {
+                    response = objectMapper.readValue(responseEntity, responseClass);
+                } else {
+                    TypeReference<?> responseType = exchange.getProperty(RESPONSE_TYPE, TypeReference.class);
+                    if (responseType != null) {
+                        response = objectMapper.readValue(responseEntity, responseType);
+                    } else {
+                        // return the response as a stream, for getBlobField
+                        response = responseEntity;
+                    }
+                }
+                exchange.getOut().setBody(response);
+            } else {
+                exchange.setException(ex);
+            }
+            // copy headers and attachments
+            exchange.getOut().getHeaders().putAll(exchange.getIn().getHeaders());
+            exchange.getOut().getAttachments().putAll(exchange.getIn().getAttachments());
+        } catch (IOException e) {
+            String msg = "Error parsing JSON response: " + e.getMessage();
+            exchange.setException(new SalesforceException(msg, e));
+        } finally {
+            // cleanup temporary exchange headers
+            exchange.removeProperty(RESPONSE_CLASS);
+            exchange.removeProperty(RESPONSE_TYPE);
+
+            // consume response entity
+            try {
+                if (responseEntity != null) {
+                    responseEntity.close();
+                }
+            } catch (IOException ignored) {
+            }
+
+            // notify callback that exchange is done
+            callback.done(false);
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/SalesforceProcessor.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/SalesforceProcessor.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/SalesforceProcessor.java
new file mode 100644
index 0000000..36f77f6
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/SalesforceProcessor.java
@@ -0,0 +1,27 @@
+/**
+ * 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.internal.processor;
+
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.Exchange;
+import org.apache.camel.Service;
+
+public interface SalesforceProcessor extends Service {
+
+    boolean process(Exchange exchange, AsyncCallback callback);
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/72a1767e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/XmlRestProcessor.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/XmlRestProcessor.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/XmlRestProcessor.java
new file mode 100644
index 0000000..75449b6
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/XmlRestProcessor.java
@@ -0,0 +1,240 @@
+/**
+ * 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.internal.processor;
+
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.XStreamException;
+import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+import com.thoughtworks.xstream.io.naming.NoNameCoder;
+import com.thoughtworks.xstream.io.xml.CompactWriter;
+import com.thoughtworks.xstream.io.xml.XppDriver;
+import com.thoughtworks.xstream.mapper.CachingMapper;
+import com.thoughtworks.xstream.mapper.CannotResolveClassException;
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.eclipse.jetty.util.StringUtil;
+import org.apache.camel.component.salesforce.SalesforceEndpoint;
+import org.apache.camel.component.salesforce.api.JodaTimeConverter;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.*;
+
+import java.io.*;
+
+import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.SOBJECT_NAME;
+
+public class XmlRestProcessor extends AbstractRestProcessor {
+
+    // although XStream is generally thread safe, because of the way we use aliases
+    // for GET_BASIC_INFO and GET_DESCRIPTION, we need to use a ThreadLocal
+    // not very efficient when both JSON and XML are used together with a single Thread pool
+    // but this will do for now
+    private static ThreadLocal<XStream> xStream =
+        new ThreadLocal<XStream>() {
+            @Override
+            protected XStream initialValue() {
+                // use NoNameCoder to avoid escaping __ in custom field names
+                // and CompactWriter to avoid pretty printing
+                XStream result = new XStream(new XppDriver(new NoNameCoder()) {
+                    @Override
+                    public HierarchicalStreamWriter createWriter(Writer out) {
+                        return new CompactWriter(out, getNameCoder());
+                    }
+
+                });
+                result.registerConverter(new JodaTimeConverter());
+                return result;
+            }
+        };
+
+    private static final String RESPONSE_ALIAS = XmlRestProcessor.class.getName() + ".responseAlias";
+
+    public XmlRestProcessor(SalesforceEndpoint endpoint) throws SalesforceException {
+        super(endpoint);
+
+    }
+
+    @Override
+    protected void processRequest(Exchange exchange) throws SalesforceException {
+
+        switch (operationName) {
+            case GET_VERSIONS:
+                exchange.setProperty(RESPONSE_CLASS, Versions.class);
+                break;
+
+            case GET_RESOURCES:
+                exchange.setProperty(RESPONSE_CLASS, RestResources.class);
+                break;
+
+            case GET_GLOBAL_OBJECTS:
+                // handle in built response types
+                exchange.setProperty(RESPONSE_CLASS, GlobalObjects.class);
+                break;
+
+            case GET_BASIC_INFO:
+                // handle in built response types
+                exchange.setProperty(RESPONSE_CLASS, SObjectBasicInfo.class);
+
+                // need to add alias for Salesforce XML that uses SObject name as root element
+                exchange.setProperty(RESPONSE_ALIAS,
+                    getParameter(SOBJECT_NAME, exchange, USE_BODY, NOT_OPTIONAL));
+                break;
+
+            case GET_DESCRIPTION:
+                // handle in built response types
+                exchange.setProperty(RESPONSE_CLASS, SObjectDescription.class);
+
+                // need to add alias for Salesforce XML that uses SObject name as root element
+                exchange.setProperty(RESPONSE_ALIAS,
+                    getParameter(SOBJECT_NAME, exchange, USE_BODY, NOT_OPTIONAL));
+                break;
+
+            case GET_SOBJECT:
+                // need to add alias for Salesforce XML that uses SObject name as root element
+                exchange.setProperty(RESPONSE_ALIAS,
+                    getParameter(SOBJECT_NAME, exchange, IGNORE_BODY, NOT_OPTIONAL));
+                break;
+
+            case CREATE_SOBJECT:
+                // handle known response type
+                exchange.setProperty(RESPONSE_CLASS, CreateSObjectResult.class);
+                break;
+
+            case GET_SOBJECT_WITH_ID:
+                // need to add alias for Salesforce XML that uses SObject name as root element
+                exchange.setProperty(RESPONSE_ALIAS,
+                    getParameter(SOBJECT_NAME, exchange, IGNORE_BODY, NOT_OPTIONAL));
+                break;
+
+            case UPSERT_SOBJECT:
+                // handle known response type
+                exchange.setProperty(RESPONSE_CLASS, CreateSObjectResult.class);
+                break;
+
+            case QUERY:
+            case QUERY_MORE:
+                // need to add alias for Salesforce XML that uses SObject name as root element
+                exchange.setProperty(RESPONSE_ALIAS,
+                    "QueryResult");
+                break;
+
+            case SEARCH:
+                // handle known response type
+                exchange.setProperty(RESPONSE_CLASS, SearchResults.class);
+                break;
+
+        }
+
+    }
+
+    protected InputStream getRequestStream(Exchange exchange) throws SalesforceException {
+        final XStream localXStream = xStream.get();
+        try {
+            // get request stream from In message
+            Message in = exchange.getIn();
+            InputStream request = in.getBody(InputStream.class);
+            if (request == null) {
+                AbstractSObjectBase sObject = in.getBody(AbstractSObjectBase.class);
+                if (sObject != null) {
+                    // marshall the SObject
+                    // first process annotations on the class, for things like alias, etc.
+                    localXStream.processAnnotations(sObject.getClass());
+                    ByteArrayOutputStream out = new ByteArrayOutputStream();
+                    // make sure we write the XML with the right encoding
+                    localXStream.toXML(sObject, new OutputStreamWriter(out, StringUtil.__UTF8_CHARSET));
+                    request = new ByteArrayInputStream(out.toByteArray());
+                } else {
+                    // if all else fails, get body as String
+                    final String body = in.getBody(String.class);
+                    if (null == body) {
+                        String msg = "Unsupported request message body " +
+                            (in.getBody() == null ? null : in.getBody().getClass());
+                        throw new SalesforceException(msg, null);
+                    } else {
+                        request = new ByteArrayInputStream(body.getBytes(StringUtil.__UTF8_CHARSET));
+                    }
+                }
+            }
+            return request;
+        } catch (XStreamException e) {
+            String msg = "Error marshaling request: " + e.getMessage();
+            throw new SalesforceException(msg, e);
+        }
+    }
+
+    @Override
+    protected void processResponse(Exchange exchange, InputStream responseEntity,
+                                   SalesforceException exception, AsyncCallback callback) {
+        final XStream localXStream = xStream.get();
+        try {
+            // do we need to un-marshal a response
+            if (responseEntity != null) {
+                final Class<?> responseClass = exchange.getProperty(RESPONSE_CLASS, Class.class);
+                Object response;
+                if (responseClass != null) {
+                    // its ok to call this multiple times, as xstream ignores duplicate calls
+                    localXStream.processAnnotations(responseClass);
+                    final String responseAlias = exchange.getProperty(RESPONSE_ALIAS, String.class);
+                    if (responseAlias != null) {
+                        // extremely dirty, need to flush entire cache if its holding on to an old alias!!!
+                        final CachingMapper mapper = (CachingMapper) localXStream.getMapper();
+                        try {
+                            if (mapper.realClass(responseAlias) != responseClass) {
+                                mapper.flushCache();
+                            }
+                        } catch (CannotResolveClassException ignore) {
+                        }
+                        localXStream.alias(responseAlias, responseClass);
+                    }
+                    response = responseClass.newInstance();
+                    localXStream.fromXML(responseEntity, response);
+                } else {
+                    // return the response as a stream, for getBlobField
+                    response = responseEntity;
+                }
+                exchange.getOut().setBody(response);
+            } else {
+                exchange.setException(exception);
+            }
+            // copy headers and attachments
+            exchange.getOut().getHeaders().putAll(exchange.getIn().getHeaders());
+            exchange.getOut().getAttachments().putAll(exchange.getIn().getAttachments());
+        } catch (XStreamException e) {
+            String msg = "Error parsing XML response: " + e.getMessage();
+            exchange.setException(new SalesforceException(msg, e));
+        } catch (Exception e) {
+            String msg = "Error creating XML response: " + e.getMessage();
+            exchange.setException(new SalesforceException(msg, e));
+        } finally {
+            // cleanup temporary exchange headers
+            exchange.removeProperty(RESPONSE_CLASS);
+            exchange.removeProperty(RESPONSE_ALIAS);
+
+            // consume response entity
+            if (responseEntity != null) {
+                try {
+                    responseEntity.close();
+                } catch (IOException ignored) {
+                }
+            }
+
+            // notify callback that exchange is done
+            callback.done(false);
+        }
+    }
+
+}


[11/23] camel git commit: Minor polish in API Component Framework

Posted by dh...@apache.org.
Minor polish in 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/bd7d94d3
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/bd7d94d3
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/bd7d94d3

Branch: refs/heads/linkedin-component
Commit: bd7d94d3f0da9a3ae07b5b022108e0bf80416a72
Parents: 5a8714a
Author: Dhiraj Bokde <dh...@yahoo.com>
Authored: Wed Jul 2 11:08:27 2014 -0700
Committer: Dhiraj Bokde <dh...@yahoo.com>
Committed: Wed Jul 2 11:08:27 2014 -0700

----------------------------------------------------------------------
 .../src/test/resources/test-options.properties                     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/bd7d94d3/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/test/resources/test-options.properties
----------------------------------------------------------------------
diff --git a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/test/resources/test-options.properties b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/test/resources/test-options.properties
index b38298a..5119847 100644
--- a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/test/resources/test-options.properties
+++ b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/test/resources/test-options.properties
@@ -1 +1 @@
-## TODO provide test values for ${name} configuration properties
\ No newline at end of file
+# TODO provide test values for ${name} configuration properties
\ No newline at end of file


[22/23] camel git commit: CAMEL-8575: Applied patch to fix Salesforce security login retries, with thanks to Dmitry Lysai

Posted by dh...@apache.org.
CAMEL-8575: Applied patch to fix Salesforce security login retries, with thanks to Dmitry Lysai


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

Branch: refs/heads/camel-2.13.x
Commit: ebec06b579b11b047c74095ebca88f82224a4dc2
Parents: ede4a72
Author: Dhiraj Bokde <dh...@yahoo.com>
Authored: Mon Apr 6 13:28:01 2015 -0700
Committer: Dhiraj Bokde <dh...@yahoo.com>
Committed: Mon Apr 6 13:31:57 2015 -0700

----------------------------------------------------------------------
 .../internal/client/AbstractClientBase.java     | 26 ++++++++---------
 .../salesforce/RestApiIntegrationTest.java      | 30 ++++++++++++++++++++
 2 files changed, 43 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/ebec06b5/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
index a00d289..b0c7442 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
@@ -103,19 +103,6 @@ public abstract class AbstractClientBase implements SalesforceSession.Salesforce
 
     protected void doHttpRequest(final ContentExchange request, final ClientResponseCallback callback) {
 
-        // use SalesforceSecurityListener for security login retries
-        try {
-            final boolean isHttps = HttpSchemes.HTTPS.equals(String.valueOf(request.getScheme()));
-            request.setEventListener(new SalesforceSecurityListener(
-                    httpClient.getDestination(request.getAddress(), isHttps),
-                    request, session, accessToken));
-        } catch (IOException e) {
-            // propagate exception
-            callback.onResponse(null, new SalesforceException(
-                    String.format("Error registering security listener: %s", e.getMessage()),
-                    e));
-        }
-
         // use HttpEventListener for lifecycle events
         request.setEventListener(new HttpEventListenerWrapper(request.getEventListener(), true) {
 
@@ -169,6 +156,19 @@ public abstract class AbstractClientBase implements SalesforceSession.Salesforce
             }
         });
 
+        // use SalesforceSecurityListener for security login retries
+        try {
+            final boolean isHttps = HttpSchemes.HTTPS.equals(String.valueOf(request.getScheme()));
+            request.setEventListener(new SalesforceSecurityListener(
+                    httpClient.getDestination(request.getAddress(), isHttps),
+                    request, session, accessToken));
+        } catch (IOException e) {
+            // propagate exception
+            callback.onResponse(null, new SalesforceException(
+                    String.format("Error registering security listener: %s", e.getMessage()),
+                    e));
+        }
+
         // execute the request
         try {
             httpClient.send(request);

http://git-wip-us.apache.org/repos/asf/camel/blob/ebec06b5/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
index 9627cf3..e87a21f 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
@@ -44,7 +44,14 @@ import org.apache.camel.component.salesforce.dto.generated.Document;
 import org.apache.camel.component.salesforce.dto.generated.Line_Item__c;
 import org.apache.camel.component.salesforce.dto.generated.Merchandise__c;
 import org.apache.camel.component.salesforce.dto.generated.QueryRecordsLine_Item__c;
+import org.apache.camel.util.jsse.SSLContextParameters;
+import org.eclipse.jetty.client.ContentExchange;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.client.RedirectListener;
+import org.eclipse.jetty.http.HttpMethods;
 import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -59,6 +66,29 @@ public class RestApiIntegrationTest extends AbstractSalesforceTestBase {
     private static String testId;
 
     @Test
+    public void testRetry() throws Exception {
+        SalesforceComponent sf = context().getComponent("salesforce", SalesforceComponent.class);
+        String accessToken = sf.getSession().getAccessToken();
+
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        sslContextFactory.setSslContext(new SSLContextParameters().createSSLContext());
+        HttpClient httpClient = new HttpClient(sslContextFactory);
+        httpClient.setConnectTimeout(60000);
+        httpClient.setTimeout(60000);
+        httpClient.registerListener(RedirectListener.class.getName());
+        httpClient.start();
+
+        ContentExchange logoutGet = new ContentExchange(true);
+        logoutGet.setURL(sf.getLoginConfig().getLoginUrl() + "/services/oauth2/revoke?token=" + accessToken);
+        logoutGet.setMethod(HttpMethods.GET);
+        httpClient.send(logoutGet);
+        assertEquals(HttpExchange.STATUS_COMPLETED, logoutGet.waitForDone());
+        assertEquals(HttpStatus.OK_200, logoutGet.getResponseStatus());
+
+        doTestGetGlobalObjects("");
+    }
+
+    @Test
     public void testGetVersions() throws Exception {
         doTestGetVersions("");
         doTestGetVersions("Xml");


[14/23] camel git commit: CAMEL-6568: Initial version of LinkedIn component

Posted by dh...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInConsumer.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInConsumer.java b/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInConsumer.java
new file mode 100644
index 0000000..bb1e029
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInConsumer.java
@@ -0,0 +1,58 @@
+/**
+ * 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.linkedin;
+
+import java.util.Map;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+
+import org.apache.camel.Processor;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.linkedin.api.LinkedInException;
+import org.apache.camel.component.linkedin.api.model.Error;
+import org.apache.camel.component.linkedin.internal.LinkedInApiName;
+import org.apache.camel.util.component.AbstractApiConsumer;
+
+/**
+ * The LinkedIn consumer.
+ */
+public class LinkedInConsumer extends AbstractApiConsumer<LinkedInApiName, LinkedInConfiguration> {
+
+    public LinkedInConsumer(LinkedInEndpoint endpoint, Processor processor) {
+        super(endpoint, processor);
+    }
+
+    @Override
+    protected Object doInvokeMethod(Map<String, Object> args) {
+        try {
+            return super.doInvokeMethod(args);
+        } catch (RuntimeCamelException e) {
+            if (e.getCause() instanceof WebApplicationException) {
+                WebApplicationException cause = (WebApplicationException) e.getCause();
+                final Response response = cause.getResponse();
+                if (response.hasEntity()) {
+                    // try and convert it to LinkedInException
+                    final org.apache.camel.component.linkedin.api.model.Error error = response.readEntity(Error.class);
+                    throw new RuntimeCamelException(
+                        String.format("Error invoking %s: %s", method.getName(), error.getMessage()),
+                        new LinkedInException(error, response));
+                }
+            }
+            throw e;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInEndpoint.java b/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInEndpoint.java
new file mode 100644
index 0000000..12f8ade
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInEndpoint.java
@@ -0,0 +1,174 @@
+/**
+ * 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.linkedin;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import org.apache.camel.Consumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.component.linkedin.api.CommentsResource;
+import org.apache.camel.component.linkedin.api.CompaniesResource;
+import org.apache.camel.component.linkedin.api.GroupsResource;
+import org.apache.camel.component.linkedin.api.JobsResource;
+import org.apache.camel.component.linkedin.api.LinkedInOAuthRequestFilter;
+import org.apache.camel.component.linkedin.api.PeopleResource;
+import org.apache.camel.component.linkedin.api.PostsResource;
+import org.apache.camel.component.linkedin.api.SearchResource;
+import org.apache.camel.component.linkedin.internal.LinkedInApiCollection;
+import org.apache.camel.component.linkedin.internal.LinkedInApiName;
+import org.apache.camel.component.linkedin.internal.LinkedInConstants;
+import org.apache.camel.component.linkedin.internal.LinkedInPropertiesHelper;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.util.component.AbstractApiEndpoint;
+import org.apache.camel.util.component.ApiMethod;
+import org.apache.camel.util.component.ApiMethodPropertiesHelper;
+import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
+import org.apache.cxf.jaxrs.client.WebClient;
+
+/**
+ * Represents a LinkedIn endpoint.
+ */
+@UriEndpoint(scheme = "linkedin", consumerClass = LinkedInConsumer.class, consumerPrefix = "consumer")
+public class LinkedInEndpoint extends AbstractApiEndpoint<LinkedInApiName, LinkedInConfiguration> {
+
+    private static final String DEFAULT_FIELDS_SELECTOR = "";
+    private static final String FIELDS_OPTION = "fields";
+    // OAuth request filter
+    private LinkedInOAuthRequestFilter requestFilter;
+
+    // Resource API proxy
+    private Object resourceProxy;
+
+    public LinkedInEndpoint(String uri, LinkedInComponent component,
+                         LinkedInApiName apiName, String methodName, LinkedInConfiguration endpointConfiguration) {
+        super(uri, component, apiName, methodName, LinkedInApiCollection.getCollection().getHelper(apiName), endpointConfiguration);
+
+    }
+
+    public Producer createProducer() throws Exception {
+        return new LinkedInProducer(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 LinkedInConsumer consumer = new LinkedInConsumer(this, processor);
+        // also set consumer.* properties
+        configureConsumer(consumer);
+        return consumer;
+    }
+
+    @Override
+    protected ApiMethodPropertiesHelper<LinkedInConfiguration> getPropertiesHelper() {
+        return LinkedInPropertiesHelper.getHelper();
+    }
+
+    protected String getThreadProfileName() {
+        return LinkedInConstants.THREAD_PROFILE_NAME;
+    }
+
+    @Override
+    protected void afterConfigureProperties() {
+        createProxy();
+    }
+
+    // create API proxy, set connection properties, etc.
+    private void createProxy() {
+        // create endpoint filter or get shared filter if configuration values are same as component
+        requestFilter = getComponent().getRequestFilter(configuration);
+
+        final Class<?> proxyClass;
+        switch (apiName) {
+        case COMMENTS:
+            proxyClass = CommentsResource.class;
+            break;
+        case COMPANIES:
+            proxyClass = CompaniesResource.class;
+            break;
+        case GROUPS:
+            proxyClass = GroupsResource.class;
+            break;
+        case JOBS:
+            proxyClass = JobsResource.class;
+            break;
+        case PEOPLE:
+            proxyClass = PeopleResource.class;
+            break;
+        case POSTS:
+            proxyClass = PostsResource.class;
+            break;
+        case SEARCH:
+            proxyClass = SearchResource.class;
+            break;
+        default:
+            throw new IllegalArgumentException("Invalid API name " + apiName);
+        }
+
+        // create endpoint proxy
+        resourceProxy = JAXRSClientFactory.create(LinkedInOAuthRequestFilter.BASE_ADDRESS, proxyClass,
+            Arrays.asList(new Object[]{requestFilter}));
+    }
+
+    @Override
+    public Object getApiProxy(ApiMethod method, Map<String, Object> args) {
+        return resourceProxy;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+
+        if (resourceProxy == null) {
+            createProxy();
+        }
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        super.doStop();
+
+        if (resourceProxy != null) {
+            try {
+                WebClient.client(resourceProxy).close();
+            } catch (Exception e) {
+                log.warn("Error closing LinkedIn REST proxy: " + e.getMessage(), e);
+            }
+            resourceProxy = null;
+        }
+
+        if (requestFilter != null) {
+            getComponent().closeRequestFilter(requestFilter);
+            requestFilter = null;
+        }
+    }
+
+    @Override
+    public LinkedInComponent getComponent() {
+        return (LinkedInComponent) super.getComponent();
+    }
+
+    @Override
+    public void interceptProperties(Map<String, Object> properties) {
+        if (!properties.containsKey(FIELDS_OPTION)) {
+            properties.put(FIELDS_OPTION, DEFAULT_FIELDS_SELECTOR);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInProducer.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInProducer.java b/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInProducer.java
new file mode 100644
index 0000000..4c03856
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/LinkedInProducer.java
@@ -0,0 +1,59 @@
+/**
+ * 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.linkedin;
+
+import java.util.Map;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.linkedin.api.LinkedInException;
+import org.apache.camel.component.linkedin.api.model.Error;
+import org.apache.camel.component.linkedin.internal.LinkedInApiName;
+import org.apache.camel.component.linkedin.internal.LinkedInPropertiesHelper;
+import org.apache.camel.util.component.AbstractApiProducer;
+import org.apache.camel.util.component.ApiMethod;
+
+/**
+ * The LinkedIn producer.
+ */
+public class LinkedInProducer extends AbstractApiProducer<LinkedInApiName, LinkedInConfiguration> {
+
+    public LinkedInProducer(LinkedInEndpoint endpoint) {
+        super(endpoint, LinkedInPropertiesHelper.getHelper());
+    }
+
+    @Override
+    protected Object doInvokeMethod(ApiMethod method, Map<String, Object> properties) throws RuntimeCamelException {
+        try {
+            return super.doInvokeMethod(method, properties);
+        } catch (RuntimeCamelException e) {
+            if (e.getCause() instanceof WebApplicationException) {
+                final WebApplicationException cause = (WebApplicationException) e.getCause();
+                final Response response = cause.getResponse();
+                if (response.hasEntity()) {
+                    // try and convert it to LinkedInException
+                    final org.apache.camel.component.linkedin.api.model.Error error = response.readEntity(Error.class);
+                    throw new RuntimeCamelException(
+                        String.format("Error invoking %s: %s", method.getName(), error.getMessage()),
+                        new LinkedInException(error, response));
+                }
+            }
+            throw e;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/internal/CachingOAuthSecureStorage.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/internal/CachingOAuthSecureStorage.java b/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/internal/CachingOAuthSecureStorage.java
new file mode 100644
index 0000000..029e3ab
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/internal/CachingOAuthSecureStorage.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.linkedin.internal;
+
+import org.apache.camel.component.linkedin.api.OAuthSecureStorage;
+import org.apache.camel.component.linkedin.api.OAuthToken;
+
+/**
+ * Caching implementation of {@link org.apache.camel.component.linkedin.api.OAuthSecureStorage}
+ */
+public class CachingOAuthSecureStorage implements OAuthSecureStorage {
+
+    private final OAuthSecureStorage secureStorage;
+    private OAuthToken token;
+
+    public CachingOAuthSecureStorage(OAuthSecureStorage secureStorage) {
+        this.secureStorage = secureStorage;
+    }
+
+    @Override
+    public OAuthToken getOAuthToken() {
+        // delegate only if token doesn't exist or has expired
+        if (secureStorage != null && (token == null || token.getExpiryTime() < System.currentTimeMillis())) {
+            token = secureStorage.getOAuthToken();
+        }
+        return token;
+    }
+
+    @Override
+    public void saveOAuthToken(OAuthToken newToken) {
+        token = newToken;
+        if (secureStorage != null) {
+            secureStorage.saveOAuthToken(newToken);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/internal/LinkedInConstants.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/internal/LinkedInConstants.java b/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/internal/LinkedInConstants.java
new file mode 100644
index 0000000..9ef5575b
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/main/java/org/apache/camel/component/linkedin/internal/LinkedInConstants.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.linkedin.internal;
+
+/**
+ * Constants for LinkedIn component.
+ */
+public interface LinkedInConstants {
+
+    // suffix for parameters when passed as exchange header properties
+    String PROPERTY_PREFIX = "CamelLinkedIn.";
+
+    // thread profile name for this component
+    String THREAD_PROFILE_NAME = "CamelLinkedIn";
+}

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

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/main/resources/META-INF/services/org/apache/camel/component/linkedin
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/main/resources/META-INF/services/org/apache/camel/component/linkedin b/components/camel-linkedin/camel-linkedin-component/src/main/resources/META-INF/services/org/apache/camel/component/linkedin
new file mode 100644
index 0000000..6d67bad
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/main/resources/META-INF/services/org/apache/camel/component/linkedin
@@ -0,0 +1 @@
+class=org.apache.camel.component.linkedin.LinkedInComponent

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/AbstractLinkedInTestSupport.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/AbstractLinkedInTestSupport.java b/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/AbstractLinkedInTestSupport.java
new file mode 100644
index 0000000..1282aef
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/AbstractLinkedInTestSupport.java
@@ -0,0 +1,73 @@
+package org.apache.camel.component.linkedin;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.component.linkedin.api.OAuthScope;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.apache.camel.util.IntrospectionSupport;
+
+/**
+ * Abstract base class for LinkedIn Integration tests generated by Camel API component maven plugin.
+ */
+public class AbstractLinkedInTestSupport extends CamelTestSupport {
+
+    private static final String TEST_OPTIONS_PROPERTIES = "/test-options.properties";
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+
+        final CamelContext context = super.createCamelContext();
+
+        // read LinkedIn component configuration from TEST_OPTIONS_PROPERTIES
+        final Properties properties = new Properties();
+        try {
+            properties.load(getClass().getResourceAsStream(TEST_OPTIONS_PROPERTIES));
+        } catch (Exception e) {
+            throw new IOException(String.format("%s could not be loaded: %s", TEST_OPTIONS_PROPERTIES, e.getMessage()),
+                e);
+        }
+
+        Map<String, Object> options = new HashMap<String, Object>();
+        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
+            options.put(entry.getKey().toString(), entry.getValue());
+        }
+        // set scopes
+        final String scope = properties.getProperty("scope");
+        if (scope != null) {
+            options.put("scopes", OAuthScope.fromValues(scope.split(",")));
+        }
+        // TODO save and load token from TEST_OPTIONS_PROPERTIES
+
+        final LinkedInConfiguration configuration = new LinkedInConfiguration();
+        IntrospectionSupport.setProperties(configuration, options);
+
+        // add LinkedInComponent to Camel context
+        final LinkedInComponent component = new LinkedInComponent(context);
+        component.setConfiguration(configuration);
+        context.addComponent("linkedin", component);
+
+        return context;
+    }
+
+    @Override
+    public boolean isCreateCamelContextPerClass() {
+        // only create the context once for this class
+        return true;
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <T> T requestBodyAndHeaders(String endpointUri, Object body, Map<String, Object> headers)
+        throws CamelExecutionException {
+        return (T) template().requestBodyAndHeaders(endpointUri, body, headers);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <T> T requestBody(String endpoint, Object body) throws CamelExecutionException {
+        return (T) template().requestBody(endpoint, body);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/CommentsResourceIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/CommentsResourceIntegrationTest.java b/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/CommentsResourceIntegrationTest.java
new file mode 100644
index 0000000..844ff7a
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/CommentsResourceIntegrationTest.java
@@ -0,0 +1,66 @@
+/*
+ * Camel Api Route test generated by camel-component-util-maven-plugin
+ * Generated on: Wed Jul 09 19:57:10 PDT 2014
+ */
+package org.apache.camel.component.linkedin;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.camel.component.linkedin.internal.LinkedInApiCollection;
+import org.apache.camel.component.linkedin.internal.CommentsResourceApiMethod;
+
+/**
+ * Test class for {@link org.apache.camel.component.linkedin.api.CommentsResource} APIs.
+ */
+public class CommentsResourceIntegrationTest extends AbstractLinkedInTestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(CommentsResourceIntegrationTest.class);
+    private static final String PATH_PREFIX = LinkedInApiCollection.getCollection().getApiName(CommentsResourceApiMethod.class).getName();
+
+    // TODO provide parameter values for getComment
+    @Ignore
+    @Test
+    public void testGetComment() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.comment_id", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+
+        final org.apache.camel.component.linkedin.api.model.Comment result = requestBodyAndHeaders("direct://GETCOMMENT", null, headers);
+
+        assertNotNull("getComment result", result);
+        LOG.debug("getComment: " + result);
+    }
+
+    // TODO provide parameter values for removeComment
+    @Ignore
+    @Test
+    public void testRemoveComment() throws Exception {
+        // using String message body for single parameter "comment_id"
+        requestBody("direct://REMOVECOMMENT", null);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                // test route for getComment
+                from("direct://GETCOMMENT")
+                  .to("linkedin://" + PATH_PREFIX + "/getComment");
+
+                // test route for removeComment
+                from("direct://REMOVECOMMENT")
+                  .to("linkedin://" + PATH_PREFIX + "/removeComment?inBody=comment_id");
+
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/CompaniesResourceIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/CompaniesResourceIntegrationTest.java b/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/CompaniesResourceIntegrationTest.java
new file mode 100644
index 0000000..fd7cb47
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/CompaniesResourceIntegrationTest.java
@@ -0,0 +1,353 @@
+/*
+ * Camel Api Route test generated by camel-component-util-maven-plugin
+ * Generated on: Wed Jul 09 19:57:10 PDT 2014
+ */
+package org.apache.camel.component.linkedin;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.camel.component.linkedin.internal.LinkedInApiCollection;
+import org.apache.camel.component.linkedin.internal.CompaniesResourceApiMethod;
+
+/**
+ * Test class for {@link org.apache.camel.component.linkedin.api.CompaniesResource} APIs.
+ */
+public class CompaniesResourceIntegrationTest extends AbstractLinkedInTestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(CompaniesResourceIntegrationTest.class);
+    private static final String PATH_PREFIX = LinkedInApiCollection.getCollection().getApiName(CompaniesResourceApiMethod.class).getName();
+    private static final Long TEST_COMPANY_ID = 1337L;
+
+    // TODO provide parameter values for addCompanyUpdateComment
+    @Ignore
+    @Test
+    public void testAddCompanyUpdateComment() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.company_id", 0L);
+        // parameter type is String
+        headers.put("CamelLinkedIn.update_key", null);
+        // parameter type is org.apache.camel.component.linkedin.api.model.UpdateComment
+        headers.put("CamelLinkedIn.updatecomment", null);
+
+        requestBodyAndHeaders("direct://ADDCOMPANYUPDATECOMMENT", null, headers);
+    }
+
+    // TODO provide parameter values for addCompanyUpdateCommentAsCompany
+    @Ignore
+    @Test
+    public void testAddCompanyUpdateCommentAsCompany() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.company_id", 0L);
+        // parameter type is String
+        headers.put("CamelLinkedIn.update_key", null);
+        // parameter type is org.apache.camel.component.linkedin.api.model.UpdateComment
+        headers.put("CamelLinkedIn.updatecomment", null);
+
+        requestBodyAndHeaders("direct://ADDCOMPANYUPDATECOMMENTASCOMPANY", null, headers);
+    }
+
+    // TODO provide parameter values for addShare
+    @Ignore
+    @Test
+    public void testAddShare() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.company_id", 0L);
+        // parameter type is org.apache.camel.component.linkedin.api.model.Share
+        headers.put("CamelLinkedIn.share", null);
+
+        requestBodyAndHeaders("direct://ADDSHARE", null, headers);
+    }
+
+    @Test
+    public void testGetCompanies() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // use defaults
+        // parameter type is String
+//        headers.put("CamelLinkedIn.fields", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.email_domain", "linkedin.com");
+        // parameter type is Boolean
+//        headers.put("CamelLinkedIn.is_company_admin", null);
+
+        final org.apache.camel.component.linkedin.api.model.Companies result = requestBodyAndHeaders("direct://GETCOMPANIES", null, headers);
+
+        assertNotNull("getCompanies result", result);
+        LOG.debug("getCompanies: " + result);
+    }
+
+    @Test
+    public void testGetCompanyById() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.company_id", TEST_COMPANY_ID);
+        // use default value
+/*
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+*/
+
+        final org.apache.camel.component.linkedin.api.model.Company result = requestBodyAndHeaders("direct://GETCOMPANYBYID", null, headers);
+
+        assertNotNull("getCompanyById result", result);
+        LOG.debug("getCompanyById: " + result);
+    }
+
+    @Test
+    public void testGetCompanyByName() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.universal_name", "linkedin");
+        // use default fields
+/*
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+*/
+
+        final org.apache.camel.component.linkedin.api.model.Company result = requestBodyAndHeaders("direct://GETCOMPANYBYNAME", null, headers);
+
+        assertNotNull("getCompanyByName result", result);
+        LOG.debug("getCompanyByName: " + result);
+    }
+
+    // TODO provide parameter values for getCompanyUpdateComments
+    @Ignore
+    @Test
+    public void testGetCompanyUpdateComments() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.company_id", 0L);
+        // parameter type is String
+        headers.put("CamelLinkedIn.update_key", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+        // parameter type is Boolean
+        headers.put("CamelLinkedIn.secure_urls", null);
+
+        final org.apache.camel.component.linkedin.api.model.Comments result = requestBodyAndHeaders("direct://GETCOMPANYUPDATECOMMENTS", null, headers);
+
+        assertNotNull("getCompanyUpdateComments result", result);
+        LOG.debug("getCompanyUpdateComments: " + result);
+    }
+
+    // TODO provide parameter values for getCompanyUpdateLikes
+    @Ignore
+    @Test
+    public void testGetCompanyUpdateLikes() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.company_id", 0L);
+        // parameter type is String
+        headers.put("CamelLinkedIn.update_key", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+        // parameter type is Boolean
+        headers.put("CamelLinkedIn.secure_urls", null);
+
+        final org.apache.camel.component.linkedin.api.model.Likes result = requestBodyAndHeaders("direct://GETCOMPANYUPDATELIKES", null, headers);
+
+        assertNotNull("getCompanyUpdateLikes result", result);
+        LOG.debug("getCompanyUpdateLikes: " + result);
+    }
+
+    @Test
+    public void testGetCompanyUpdates() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.company_id", TEST_COMPANY_ID);
+        // use defaults
+/*
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+        // parameter type is org.apache.camel.component.linkedin.api.Eventtype
+        headers.put("CamelLinkedIn.event_type", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.start", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.count", null);
+*/
+
+        final org.apache.camel.component.linkedin.api.model.Updates result = requestBodyAndHeaders("direct://GETCOMPANYUPDATES", null, headers);
+
+        assertNotNull("getCompanyUpdates result", result);
+        LOG.debug("getCompanyUpdates: " + result);
+    }
+
+    // TODO provide parameter values for getHistoricalFollowStatistics
+    @Ignore
+    @Test
+    public void testGetHistoricalFollowStatistics() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.company_id", 0L);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.start_timestamp", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.end_timestamp", null);
+        // parameter type is org.apache.camel.component.linkedin.api.Timegranularity
+        headers.put("CamelLinkedIn.time_granularity", null);
+
+        final org.apache.camel.component.linkedin.api.model.HistoricalFollowStatistics result = requestBodyAndHeaders("direct://GETHISTORICALFOLLOWSTATISTICS", null, headers);
+
+        assertNotNull("getHistoricalFollowStatistics result", result);
+        LOG.debug("getHistoricalFollowStatistics: " + result);
+    }
+
+    // TODO provide parameter values for getHistoricalStatusUpdateStatistics
+    @Ignore
+    @Test
+    public void testGetHistoricalStatusUpdateStatistics() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.company_id", TEST_COMPANY_ID);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.start_timestamp", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.end_timestamp", null);
+        // parameter type is org.apache.camel.component.linkedin.api.Timegranularity
+        headers.put("CamelLinkedIn.time_granularity", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.update_key", null);
+
+        final org.apache.camel.component.linkedin.api.model.HistoricalStatusUpdateStatistics result = requestBodyAndHeaders("direct://GETHISTORICALSTATUSUPDATESTATISTICS", null, headers);
+
+        assertNotNull("getHistoricalStatusUpdateStatistics result", result);
+        LOG.debug("getHistoricalStatusUpdateStatistics: " + result);
+    }
+
+    @Test
+    public void testGetNumberOfFollowers() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.company_id", TEST_COMPANY_ID);
+        // parameter type is java.util.List
+        headers.put("CamelLinkedIn.geos", null);
+        // parameter type is java.util.List
+        headers.put("CamelLinkedIn.companySizes", null);
+        // parameter type is java.util.List
+        headers.put("CamelLinkedIn.jobFunc", null);
+        // parameter type is java.util.List
+        headers.put("CamelLinkedIn.industries", null);
+        // parameter type is java.util.List
+        headers.put("CamelLinkedIn.seniorities", null);
+
+        final org.apache.camel.component.linkedin.api.model.NumFollowers result = requestBodyAndHeaders("direct://GETNUMBEROFFOLLOWERS", null, headers);
+
+        assertNotNull("getNumberOfFollowers result", result);
+        LOG.debug("getNumberOfFollowers: " + result);
+    }
+
+    // TODO provide parameter values for getStatistics
+    @Ignore
+    @Test
+    public void testGetStatistics() throws Exception {
+        // using long message body for single parameter "company_id"
+        final org.apache.camel.component.linkedin.api.model.CompanyStatistics result = requestBody("direct://GETSTATISTICS", 0L);
+
+        assertNotNull("getStatistics result", result);
+        LOG.debug("getStatistics: " + result);
+    }
+
+    @Test
+    public void testIsShareEnabled() throws Exception {
+        // using long message body for single parameter "company_id"
+        final org.apache.camel.component.linkedin.api.model.IsCompanyShareEnabled result = requestBody("direct://ISSHAREENABLED", TEST_COMPANY_ID);
+
+        assertNotNull("isShareEnabled result", result);
+        LOG.debug("isShareEnabled: " + result);
+    }
+
+    @Test
+    public void testIsViewerShareEnabled() throws Exception {
+        // using long message body for single parameter "company_id"
+        final org.apache.camel.component.linkedin.api.model.IsCompanyShareEnabled result = requestBody("direct://ISVIEWERSHAREENABLED", TEST_COMPANY_ID);
+
+        assertNotNull("isViewerShareEnabled result", result);
+        LOG.debug("isViewerShareEnabled: " + result);
+    }
+
+    // TODO provide parameter values for likeCompanyUpdate
+    @Ignore
+    @Test
+    public void testLikeCompanyUpdate() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.company_id", 0L);
+        // parameter type is String
+        headers.put("CamelLinkedIn.update_key", null);
+        // parameter type is org.apache.camel.component.linkedin.api.model.IsLiked
+        headers.put("CamelLinkedIn.isliked", null);
+
+        requestBodyAndHeaders("direct://LIKECOMPANYUPDATE", null, headers);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                // test route for addCompanyUpdateComment
+                from("direct://ADDCOMPANYUPDATECOMMENT")
+                  .to("linkedin://" + PATH_PREFIX + "/addCompanyUpdateComment");
+
+                // test route for addCompanyUpdateCommentAsCompany
+                from("direct://ADDCOMPANYUPDATECOMMENTASCOMPANY")
+                  .to("linkedin://" + PATH_PREFIX + "/addCompanyUpdateCommentAsCompany");
+
+                // test route for addShare
+                from("direct://ADDSHARE")
+                  .to("linkedin://" + PATH_PREFIX + "/addShare");
+
+                // test route for getCompanies
+                from("direct://GETCOMPANIES")
+                  .to("linkedin://" + PATH_PREFIX + "/getCompanies");
+
+                // test route for getCompanyById
+                from("direct://GETCOMPANYBYID")
+                  .to("linkedin://" + PATH_PREFIX + "/getCompanyById");
+
+                // test route for getCompanyByName
+                from("direct://GETCOMPANYBYNAME")
+                  .to("linkedin://" + PATH_PREFIX + "/getCompanyByName");
+
+                // test route for getCompanyUpdateComments
+                from("direct://GETCOMPANYUPDATECOMMENTS")
+                  .to("linkedin://" + PATH_PREFIX + "/getCompanyUpdateComments");
+
+                // test route for getCompanyUpdateLikes
+                from("direct://GETCOMPANYUPDATELIKES")
+                  .to("linkedin://" + PATH_PREFIX + "/getCompanyUpdateLikes");
+
+                // test route for getCompanyUpdates
+                from("direct://GETCOMPANYUPDATES")
+                  .to("linkedin://" + PATH_PREFIX + "/getCompanyUpdates");
+
+                // test route for getHistoricalFollowStatistics
+                from("direct://GETHISTORICALFOLLOWSTATISTICS")
+                  .to("linkedin://" + PATH_PREFIX + "/getHistoricalFollowStatistics");
+
+                // test route for getHistoricalStatusUpdateStatistics
+                from("direct://GETHISTORICALSTATUSUPDATESTATISTICS")
+                  .to("linkedin://" + PATH_PREFIX + "/getHistoricalStatusUpdateStatistics");
+
+                // test route for getNumberOfFollowers
+                from("direct://GETNUMBEROFFOLLOWERS")
+                  .to("linkedin://" + PATH_PREFIX + "/getNumberOfFollowers");
+
+                // test route for getStatistics
+                from("direct://GETSTATISTICS")
+                  .to("linkedin://" + PATH_PREFIX + "/getStatistics?inBody=company_id");
+
+                // test route for isShareEnabled
+                from("direct://ISSHAREENABLED")
+                  .to("linkedin://" + PATH_PREFIX + "/isShareEnabled?inBody=company_id");
+
+                // test route for isViewerShareEnabled
+                from("direct://ISVIEWERSHAREENABLED")
+                  .to("linkedin://" + PATH_PREFIX + "/isViewerShareEnabled?inBody=company_id");
+
+                // test route for likeCompanyUpdate
+                from("direct://LIKECOMPANYUPDATE")
+                  .to("linkedin://" + PATH_PREFIX + "/likeCompanyUpdate");
+
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/GroupsResourceIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/GroupsResourceIntegrationTest.java b/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/GroupsResourceIntegrationTest.java
new file mode 100644
index 0000000..0c7ab84
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/GroupsResourceIntegrationTest.java
@@ -0,0 +1,65 @@
+/*
+ * Camel Api Route test generated by camel-component-util-maven-plugin
+ * Generated on: Wed Jul 09 19:57:10 PDT 2014
+ */
+package org.apache.camel.component.linkedin;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.camel.component.linkedin.internal.LinkedInApiCollection;
+import org.apache.camel.component.linkedin.internal.GroupsResourceApiMethod;
+
+/**
+ * Test class for {@link org.apache.camel.component.linkedin.api.GroupsResource} APIs.
+ */
+public class GroupsResourceIntegrationTest extends AbstractLinkedInTestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GroupsResourceIntegrationTest.class);
+    private static final String PATH_PREFIX = LinkedInApiCollection.getCollection().getApiName(GroupsResourceApiMethod.class).getName();
+
+    // TODO provide parameter values for addPost
+    @Ignore
+    @Test
+    public void testAddPost() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.group_id", 0L);
+        // parameter type is org.apache.camel.component.linkedin.api.model.Post
+        headers.put("CamelLinkedIn.post", null);
+
+        requestBodyAndHeaders("direct://ADDPOST", null, headers);
+    }
+
+    // TODO provide parameter values for getGroup
+    @Ignore
+    @Test
+    public void testGetGroup() throws Exception {
+        // using long message body for single parameter "group_id"
+        final org.apache.camel.component.linkedin.api.model.Group result = requestBody("direct://GETGROUP", 0L);
+
+        assertNotNull("getGroup result", result);
+        LOG.debug("getGroup: " + result);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                // test route for addPost
+                from("direct://ADDPOST")
+                  .to("linkedin://" + PATH_PREFIX + "/addPost");
+
+                // test route for getGroup
+                from("direct://GETGROUP")
+                  .to("linkedin://" + PATH_PREFIX + "/getGroup?inBody=group_id");
+
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/JobsResourceIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/JobsResourceIntegrationTest.java b/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/JobsResourceIntegrationTest.java
new file mode 100644
index 0000000..43cf3c0
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/JobsResourceIntegrationTest.java
@@ -0,0 +1,93 @@
+/*
+ * Camel Api Route test generated by camel-component-util-maven-plugin
+ * Generated on: Wed Jul 09 19:57:11 PDT 2014
+ */
+package org.apache.camel.component.linkedin;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.camel.component.linkedin.internal.LinkedInApiCollection;
+import org.apache.camel.component.linkedin.internal.JobsResourceApiMethod;
+
+/**
+ * Test class for {@link org.apache.camel.component.linkedin.api.JobsResource} APIs.
+ */
+public class JobsResourceIntegrationTest extends AbstractLinkedInTestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JobsResourceIntegrationTest.class);
+    private static final String PATH_PREFIX = LinkedInApiCollection.getCollection().getApiName(JobsResourceApiMethod.class).getName();
+
+    // TODO provide parameter values for addJob
+    @Ignore
+    @Test
+    public void testAddJob() throws Exception {
+        // using org.apache.camel.component.linkedin.api.model.Job message body for single parameter "job"
+        requestBody("direct://ADDJOB", null);
+    }
+
+    // TODO provide parameter values for editJob
+    @Ignore
+    @Test
+    public void testEditJob() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.partner_job_id", 0L);
+        // parameter type is org.apache.camel.component.linkedin.api.model.Job
+        headers.put("CamelLinkedIn.job", null);
+
+        requestBodyAndHeaders("direct://EDITJOB", null, headers);
+    }
+
+    // TODO provide parameter values for getJob
+    @Ignore
+    @Test
+    public void testGetJob() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.job_id", 0L);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+
+        final org.apache.camel.component.linkedin.api.model.Job result = requestBodyAndHeaders("direct://GETJOB", null, headers);
+
+        assertNotNull("getJob result", result);
+        LOG.debug("getJob: " + result);
+    }
+
+    // TODO provide parameter values for removeJob
+    @Ignore
+    @Test
+    public void testRemoveJob() throws Exception {
+        // using long message body for single parameter "partner_job_id"
+        requestBody("direct://REMOVEJOB", 0L);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                // test route for addJob
+                from("direct://ADDJOB")
+                  .to("linkedin://" + PATH_PREFIX + "/addJob?inBody=job");
+
+                // test route for editJob
+                from("direct://EDITJOB")
+                  .to("linkedin://" + PATH_PREFIX + "/editJob");
+
+                // test route for getJob
+                from("direct://GETJOB")
+                  .to("linkedin://" + PATH_PREFIX + "/getJob");
+
+                // test route for removeJob
+                from("direct://REMOVEJOB")
+                  .to("linkedin://" + PATH_PREFIX + "/removeJob?inBody=partner_job_id");
+
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/PeopleResourceIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/PeopleResourceIntegrationTest.java b/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/PeopleResourceIntegrationTest.java
new file mode 100644
index 0000000..53567cf
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/PeopleResourceIntegrationTest.java
@@ -0,0 +1,636 @@
+/*
+ * Camel Api Route test generated by camel-component-util-maven-plugin
+ * Generated on: Wed Jul 09 19:57:11 PDT 2014
+ */
+package org.apache.camel.component.linkedin;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.linkedin.api.model.Person;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.camel.component.linkedin.internal.LinkedInApiCollection;
+import org.apache.camel.component.linkedin.internal.PeopleResourceApiMethod;
+
+/**
+ * Test class for {@link org.apache.camel.component.linkedin.api.PeopleResource} APIs.
+ */
+public class PeopleResourceIntegrationTest extends AbstractLinkedInTestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PeopleResourceIntegrationTest.class);
+    private static final String PATH_PREFIX = LinkedInApiCollection.getCollection().getApiName(PeopleResourceApiMethod.class).getName();
+
+    // TODO provide parameter values for addActivity
+    @Ignore
+    @Test
+    public void testAddActivity() throws Exception {
+        // using org.apache.camel.component.linkedin.api.model.Activity message body for single parameter "activity"
+        requestBody("direct://ADDACTIVITY", null);
+    }
+
+    // TODO provide parameter values for addGroupMembership
+    @Ignore
+    @Test
+    public void testAddGroupMembership() throws Exception {
+        // using org.apache.camel.component.linkedin.api.model.GroupMembership message body for single parameter "groupmembership"
+        requestBody("direct://ADDGROUPMEMBERSHIP", null);
+    }
+
+    // TODO provide parameter values for addInvite
+    @Ignore
+    @Test
+    public void testAddInvite() throws Exception {
+        // using org.apache.camel.component.linkedin.api.model.MailboxItem message body for single parameter "mailboxitem"
+        requestBody("direct://ADDINVITE", null);
+    }
+
+    // TODO provide parameter values for addJobBookmark
+    @Ignore
+    @Test
+    public void testAddJobBookmark() throws Exception {
+        // using org.apache.camel.component.linkedin.api.model.JobBookmark message body for single parameter "jobbookmark"
+        requestBody("direct://ADDJOBBOOKMARK", null);
+    }
+
+    // TODO provide parameter values for addUpdateComment
+    @Ignore
+    @Test
+    public void testAddUpdateComment() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.update_key", null);
+        // parameter type is org.apache.camel.component.linkedin.api.model.UpdateComment
+        headers.put("CamelLinkedIn.updatecomment", null);
+
+        requestBodyAndHeaders("direct://ADDUPDATECOMMENT", null, headers);
+    }
+
+    // TODO provide parameter values for followCompany
+    @Ignore
+    @Test
+    public void testFollowCompany() throws Exception {
+        // using org.apache.camel.component.linkedin.api.model.Company message body for single parameter "company"
+        requestBody("direct://FOLLOWCOMPANY", null);
+    }
+
+    @Test
+    public void testGetConnections() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // use defaults
+/*
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+        // parameter type is Boolean
+        headers.put("CamelLinkedIn.secure_urls", null);
+*/
+
+        final org.apache.camel.component.linkedin.api.model.Connections result = requestBodyAndHeaders("direct://GETCONNECTIONS", null, headers);
+
+        assertNotNull("getConnections result", result);
+        LOG.debug("getConnections: " + result);
+    }
+
+    // TODO provide parameter values for getConnectionsById
+    @Ignore
+    @Test
+    public void testGetConnectionsById() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.person_id", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+        // parameter type is Boolean
+        headers.put("CamelLinkedIn.secure_urls", null);
+
+        final org.apache.camel.component.linkedin.api.model.Connections result = requestBodyAndHeaders("direct://GETCONNECTIONSBYID", null, headers);
+
+        assertNotNull("getConnectionsById result", result);
+        LOG.debug("getConnectionsById: " + result);
+    }
+
+    // TODO provide parameter values for getConnectionsByUrl
+    @Ignore
+    @Test
+    public void testGetConnectionsByUrl() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.public_profile_url", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+        // parameter type is Boolean
+        headers.put("CamelLinkedIn.secure_urls", null);
+
+        final org.apache.camel.component.linkedin.api.model.Connections result = requestBodyAndHeaders("direct://GETCONNECTIONSBYURL", null, headers);
+
+        assertNotNull("getConnectionsByUrl result", result);
+        LOG.debug("getConnectionsByUrl: " + result);
+    }
+
+    @Test
+    public void testGetFollowedCompanies() throws Exception {
+        // using String message body for single parameter "fields"
+        final org.apache.camel.component.linkedin.api.model.Companies result = requestBody("direct://GETFOLLOWEDCOMPANIES", "");
+
+        assertNotNull("getFollowedCompanies result", result);
+        LOG.debug("getFollowedCompanies: " + result);
+    }
+
+    // TODO provide parameter values for getGroupMembershipSettings
+    @Ignore
+    @Test
+    public void testGetGroupMembershipSettings() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.group_id", 0L);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.count", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.start", null);
+
+        final org.apache.camel.component.linkedin.api.model.GroupMemberships result = requestBodyAndHeaders("direct://GETGROUPMEMBERSHIPSETTINGS", null, headers);
+
+        assertNotNull("getGroupMembershipSettings result", result);
+        LOG.debug("getGroupMembershipSettings: " + result);
+    }
+
+    @Test
+    public void testGetGroupMemberships() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // use defaults
+/*
+        // parameter type is org.apache.camel.component.linkedin.api.model.MembershipState
+        headers.put("CamelLinkedIn.membership_state", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.count", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.start", null);
+*/
+
+        final org.apache.camel.component.linkedin.api.model.GroupMemberships result = requestBodyAndHeaders("direct://GETGROUPMEMBERSHIPS", null, headers);
+
+        assertNotNull("getGroupMemberships result", result);
+        LOG.debug("getGroupMemberships: " + result);
+    }
+
+    @Test
+    public void testGetJobBookmarks() throws Exception {
+        final org.apache.camel.component.linkedin.api.model.JobBookmarks result = requestBody("direct://GETJOBBOOKMARKS", null);
+
+        assertNotNull("getJobBookmarks result", result);
+        LOG.debug("getJobBookmarks: " + result);
+    }
+
+    @Test
+    public void testGetNetworkStats() throws Exception {
+        final org.apache.camel.component.linkedin.api.model.NetworkStats result = requestBody("direct://GETNETWORKSTATS", null);
+
+        assertNotNull("getNetworkStats result", result);
+        LOG.debug("getNetworkStats: " + result);
+    }
+
+    @Test
+    public void testGetNetworkUpdates() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // use defaults
+/*
+        // parameter type is String
+        headers.put("CamelLinkedIn.scope", null);
+        // parameter type is org.apache.camel.component.linkedin.api.Type
+        headers.put("CamelLinkedIn.type", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.count", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.start", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.after", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.before", null);
+        // parameter type is Boolean
+        headers.put("CamelLinkedIn.show_hidden_members", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+        // parameter type is Boolean
+        headers.put("CamelLinkedIn.secure_urls", null);
+*/
+
+        final org.apache.camel.component.linkedin.api.model.Updates result = requestBodyAndHeaders("direct://GETNETWORKUPDATES", null, headers);
+
+        assertNotNull("getNetworkUpdates result", result);
+        LOG.debug("getNetworkUpdates: " + result);
+    }
+
+    // TODO provide parameter values for getNetworkUpdatesById
+    @Ignore
+    @Test
+    public void testGetNetworkUpdatesById() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.scope", null);
+        // parameter type is org.apache.camel.component.linkedin.api.Type
+        headers.put("CamelLinkedIn.type", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.count", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.start", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.after", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.before", null);
+        // parameter type is Boolean
+        headers.put("CamelLinkedIn.show_hidden_members", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.person_id", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+        // parameter type is Boolean
+        headers.put("CamelLinkedIn.secure_urls", null);
+
+        final org.apache.camel.component.linkedin.api.model.Updates result = requestBodyAndHeaders("direct://GETNETWORKUPDATESBYID", null, headers);
+
+        assertNotNull("getNetworkUpdatesById result", result);
+        LOG.debug("getNetworkUpdatesById: " + result);
+    }
+
+    @Test
+    public void testGetPerson() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", "");
+        // parameter type is Boolean
+        headers.put("CamelLinkedIn.secure_urls", true);
+
+        final Person result = requestBodyAndHeaders("direct://GETPERSON", null, headers);
+
+        assertNotNull("getPerson result", result);
+        LOG.debug("getPerson: " + result);
+    }
+
+    // TODO provide parameter values for getPersonById
+    @Ignore
+    @Test
+    public void testGetPersonById() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.person_id", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+        // parameter type is Boolean
+        headers.put("CamelLinkedIn.secure_urls", null);
+
+        final Person result = requestBodyAndHeaders("direct://GETPERSONBYID", null, headers);
+
+        assertNotNull("getPersonById result", result);
+        LOG.debug("getPersonById: " + result);
+    }
+
+    // TODO provide parameter values for getPersonByUrl
+    @Ignore
+    @Test
+    public void testGetPersonByUrl() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.public_profile_url", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+        // parameter type is Boolean
+        headers.put("CamelLinkedIn.secure_urls", null);
+
+        final Person result = requestBodyAndHeaders("direct://GETPERSONBYURL", null, headers);
+
+        assertNotNull("getPersonByUrl result", result);
+        LOG.debug("getPersonByUrl: " + result);
+    }
+
+    // TODO provide parameter values for getPosts
+    @Ignore
+    @Test
+    public void testGetPosts() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.group_id", 0L);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.start", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.count", null);
+        // parameter type is org.apache.camel.component.linkedin.api.Order
+        headers.put("CamelLinkedIn.order", null);
+        // parameter type is org.apache.camel.component.linkedin.api.Role
+        headers.put("CamelLinkedIn.role", null);
+        // parameter type is org.apache.camel.component.linkedin.api.Category
+        headers.put("CamelLinkedIn.category", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.modified_since", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+
+        final org.apache.camel.component.linkedin.api.model.Posts result = requestBodyAndHeaders("direct://GETPOSTS", null, headers);
+
+        assertNotNull("getPosts result", result);
+        LOG.debug("getPosts: " + result);
+    }
+
+    @Test
+    public void testGetSuggestedCompanies() throws Exception {
+        // using String message body for single parameter "fields"
+        final org.apache.camel.component.linkedin.api.model.Companies result = requestBody("direct://GETSUGGESTEDCOMPANIES", "");
+
+        assertNotNull("getSuggestedCompanies result", result);
+        LOG.debug("getSuggestedCompanies: " + result);
+    }
+
+    // TODO provide parameter values for getSuggestedGroupPosts
+    @Ignore
+    @Test
+    public void testGetSuggestedGroupPosts() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.group_id", 0L);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.start", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.count", null);
+        // parameter type is org.apache.camel.component.linkedin.api.Order
+        headers.put("CamelLinkedIn.order", null);
+        // parameter type is org.apache.camel.component.linkedin.api.Role
+        headers.put("CamelLinkedIn.role", null);
+        // parameter type is org.apache.camel.component.linkedin.api.Category
+        headers.put("CamelLinkedIn.category", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.modified_since", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+
+        final org.apache.camel.component.linkedin.api.model.Posts result = requestBodyAndHeaders("direct://GETSUGGESTEDGROUPPOSTS", null, headers);
+
+        assertNotNull("getSuggestedGroupPosts result", result);
+        LOG.debug("getSuggestedGroupPosts: " + result);
+    }
+
+    @Test
+    public void testGetSuggestedGroups() throws Exception {
+        // using String message body for single parameter "fields"
+        final org.apache.camel.component.linkedin.api.model.Groups result = requestBody("direct://GETSUGGESTEDGROUPS", "");
+
+        assertNotNull("getSuggestedGroups result", result);
+        LOG.debug("getSuggestedGroups: " + result);
+    }
+
+    @Test
+    public void testGetSuggestedJobs() throws Exception {
+        // using String message body for single parameter "fields"
+        final org.apache.camel.component.linkedin.api.model.JobSuggestions result = requestBody("direct://GETSUGGESTEDJOBS", "");
+
+        assertNotNull("getSuggestedJobs result", result);
+        LOG.debug("getSuggestedJobs: " + result);
+    }
+
+    // TODO provide parameter values for getUpdateComments
+    @Ignore
+    @Test
+    public void testGetUpdateComments() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.update_key", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+        // parameter type is Boolean
+        headers.put("CamelLinkedIn.secure_urls", null);
+
+        final org.apache.camel.component.linkedin.api.model.Comments result = requestBodyAndHeaders("direct://GETUPDATECOMMENTS", null, headers);
+
+        assertNotNull("getUpdateComments result", result);
+        LOG.debug("getUpdateComments: " + result);
+    }
+
+    // TODO provide parameter values for getUpdateLikes
+    @Ignore
+    @Test
+    public void testGetUpdateLikes() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.update_key", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+        // parameter type is Boolean
+        headers.put("CamelLinkedIn.secure_urls", null);
+
+        final org.apache.camel.component.linkedin.api.model.Likes result = requestBodyAndHeaders("direct://GETUPDATELIKES", null, headers);
+
+        assertNotNull("getUpdateLikes result", result);
+        LOG.debug("getUpdateLikes: " + result);
+    }
+
+    // TODO provide parameter values for likeUpdate
+    @Ignore
+    @Test
+    public void testLikeUpdate() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.update_key", null);
+        // parameter type is org.apache.camel.component.linkedin.api.model.IsLiked
+        headers.put("CamelLinkedIn.isliked", null);
+
+        requestBodyAndHeaders("direct://LIKEUPDATE", null, headers);
+    }
+
+    // TODO provide parameter values for removeGroupMembership
+    @Ignore
+    @Test
+    public void testRemoveGroupMembership() throws Exception {
+        // using long message body for single parameter "group_id"
+        requestBody("direct://REMOVEGROUPMEMBERSHIP", 0L);
+    }
+
+    // TODO provide parameter values for removeGroupSuggestion
+    @Ignore
+    @Test
+    public void testRemoveGroupSuggestion() throws Exception {
+        // using long message body for single parameter "group_id"
+        requestBody("direct://REMOVEGROUPSUGGESTION", 0L);
+    }
+
+    // TODO provide parameter values for removeJobBookmark
+    @Ignore
+    @Test
+    public void testRemoveJobBookmark() throws Exception {
+        // using long message body for single parameter "job_id"
+        requestBody("direct://REMOVEJOBBOOKMARK", 0L);
+    }
+
+    // TODO provide parameter values for share
+    @Ignore
+    @Test
+    public void testShare() throws Exception {
+        // using org.apache.camel.component.linkedin.api.model.Share message body for single parameter "share"
+        final org.apache.camel.component.linkedin.api.model.Update result = requestBody("direct://SHARE", null);
+
+        assertNotNull("share result", result);
+        LOG.debug("share: " + result);
+    }
+
+    // TODO provide parameter values for stopFollowingCompany
+    @Ignore
+    @Test
+    public void testStopFollowingCompany() throws Exception {
+        // using long message body for single parameter "company_id"
+        requestBody("direct://STOPFOLLOWINGCOMPANY", 0L);
+    }
+
+    // TODO provide parameter values for updateGroupMembership
+    @Ignore
+    @Test
+    public void testUpdateGroupMembership() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        headers.put("CamelLinkedIn.group_id", 0L);
+        // parameter type is org.apache.camel.component.linkedin.api.model.GroupMembership
+        headers.put("CamelLinkedIn.groupmembership", null);
+
+        requestBodyAndHeaders("direct://UPDATEGROUPMEMBERSHIP", null, headers);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                // test route for addActivity
+                from("direct://ADDACTIVITY")
+                  .to("linkedin://" + PATH_PREFIX + "/addActivity?inBody=activity");
+
+                // test route for addGroupMembership
+                from("direct://ADDGROUPMEMBERSHIP")
+                  .to("linkedin://" + PATH_PREFIX + "/addGroupMembership?inBody=groupmembership");
+
+                // test route for addInvite
+                from("direct://ADDINVITE")
+                  .to("linkedin://" + PATH_PREFIX + "/addInvite?inBody=mailboxitem");
+
+                // test route for addJobBookmark
+                from("direct://ADDJOBBOOKMARK")
+                  .to("linkedin://" + PATH_PREFIX + "/addJobBookmark?inBody=jobbookmark");
+
+                // test route for addUpdateComment
+                from("direct://ADDUPDATECOMMENT")
+                  .to("linkedin://" + PATH_PREFIX + "/addUpdateComment");
+
+                // test route for followCompany
+                from("direct://FOLLOWCOMPANY")
+                  .to("linkedin://" + PATH_PREFIX + "/followCompany?inBody=company");
+
+                // test route for getConnections
+                from("direct://GETCONNECTIONS")
+                  .to("linkedin://" + PATH_PREFIX + "/getConnections");
+
+                // test route for getConnectionsById
+                from("direct://GETCONNECTIONSBYID")
+                  .to("linkedin://" + PATH_PREFIX + "/getConnectionsById");
+
+                // test route for getConnectionsByUrl
+                from("direct://GETCONNECTIONSBYURL")
+                  .to("linkedin://" + PATH_PREFIX + "/getConnectionsByUrl");
+
+                // test route for getFollowedCompanies
+                from("direct://GETFOLLOWEDCOMPANIES")
+                  .to("linkedin://" + PATH_PREFIX + "/getFollowedCompanies?inBody=fields");
+
+                // test route for getGroupMembershipSettings
+                from("direct://GETGROUPMEMBERSHIPSETTINGS")
+                  .to("linkedin://" + PATH_PREFIX + "/getGroupMembershipSettings");
+
+                // test route for getGroupMemberships
+                from("direct://GETGROUPMEMBERSHIPS")
+                  .to("linkedin://" + PATH_PREFIX + "/getGroupMemberships");
+
+                // test route for getJobBookmarks
+                from("direct://GETJOBBOOKMARKS")
+                  .to("linkedin://" + PATH_PREFIX + "/getJobBookmarks");
+
+                // test route for getNetworkStats
+                from("direct://GETNETWORKSTATS")
+                  .to("linkedin://" + PATH_PREFIX + "/getNetworkStats");
+
+                // test route for getNetworkUpdates
+                from("direct://GETNETWORKUPDATES")
+                  .to("linkedin://" + PATH_PREFIX + "/getNetworkUpdates");
+
+                // test route for getNetworkUpdatesById
+                from("direct://GETNETWORKUPDATESBYID")
+                  .to("linkedin://" + PATH_PREFIX + "/getNetworkUpdatesById");
+
+                // test route for getPerson
+                from("direct://GETPERSON")
+                  .to("linkedin://" + PATH_PREFIX + "/getPerson");
+
+                // test route for getPersonById
+                from("direct://GETPERSONBYID")
+                  .to("linkedin://" + PATH_PREFIX + "/getPersonById");
+
+                // test route for getPersonByUrl
+                from("direct://GETPERSONBYURL")
+                  .to("linkedin://" + PATH_PREFIX + "/getPersonByUrl");
+
+                // test route for getPosts
+                from("direct://GETPOSTS")
+                  .to("linkedin://" + PATH_PREFIX + "/getPosts");
+
+                // test route for getSuggestedCompanies
+                from("direct://GETSUGGESTEDCOMPANIES")
+                  .to("linkedin://" + PATH_PREFIX + "/getSuggestedCompanies?inBody=fields");
+
+                // test route for getSuggestedGroupPosts
+                from("direct://GETSUGGESTEDGROUPPOSTS")
+                  .to("linkedin://" + PATH_PREFIX + "/getSuggestedGroupPosts");
+
+                // test route for getSuggestedGroups
+                from("direct://GETSUGGESTEDGROUPS")
+                  .to("linkedin://" + PATH_PREFIX + "/getSuggestedGroups?inBody=fields");
+
+                // test route for getSuggestedJobs
+                from("direct://GETSUGGESTEDJOBS")
+                  .to("linkedin://" + PATH_PREFIX + "/getSuggestedJobs?inBody=fields");
+
+                // test route for getUpdateComments
+                from("direct://GETUPDATECOMMENTS")
+                  .to("linkedin://" + PATH_PREFIX + "/getUpdateComments");
+
+                // test route for getUpdateLikes
+                from("direct://GETUPDATELIKES")
+                  .to("linkedin://" + PATH_PREFIX + "/getUpdateLikes");
+
+                // test route for likeUpdate
+                from("direct://LIKEUPDATE")
+                  .to("linkedin://" + PATH_PREFIX + "/likeUpdate");
+
+                // test route for removeGroupMembership
+                from("direct://REMOVEGROUPMEMBERSHIP")
+                  .to("linkedin://" + PATH_PREFIX + "/removeGroupMembership?inBody=group_id");
+
+                // test route for removeGroupSuggestion
+                from("direct://REMOVEGROUPSUGGESTION")
+                  .to("linkedin://" + PATH_PREFIX + "/removeGroupSuggestion?inBody=group_id");
+
+                // test route for removeJobBookmark
+                from("direct://REMOVEJOBBOOKMARK")
+                  .to("linkedin://" + PATH_PREFIX + "/removeJobBookmark?inBody=job_id");
+
+                // test route for share
+                from("direct://SHARE")
+                  .to("linkedin://" + PATH_PREFIX + "/share?inBody=share");
+
+                // test route for stopFollowingCompany
+                from("direct://STOPFOLLOWINGCOMPANY")
+                  .to("linkedin://" + PATH_PREFIX + "/stopFollowingCompany?inBody=company_id");
+
+                // test route for updateGroupMembership
+                from("direct://UPDATEGROUPMEMBERSHIP")
+                  .to("linkedin://" + PATH_PREFIX + "/updateGroupMembership");
+
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/PostsResourceIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/PostsResourceIntegrationTest.java b/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/PostsResourceIntegrationTest.java
new file mode 100644
index 0000000..5f79673
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/PostsResourceIntegrationTest.java
@@ -0,0 +1,162 @@
+/*
+ * Camel Api Route test generated by camel-component-util-maven-plugin
+ * Generated on: Wed Jul 09 19:57:11 PDT 2014
+ */
+package org.apache.camel.component.linkedin;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.camel.component.linkedin.internal.LinkedInApiCollection;
+import org.apache.camel.component.linkedin.internal.PostsResourceApiMethod;
+
+/**
+ * Test class for {@link org.apache.camel.component.linkedin.api.PostsResource} APIs.
+ */
+public class PostsResourceIntegrationTest extends AbstractLinkedInTestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PostsResourceIntegrationTest.class);
+    private static final String PATH_PREFIX = LinkedInApiCollection.getCollection().getApiName(PostsResourceApiMethod.class).getName();
+
+    // TODO provide parameter values for addComment
+    @Ignore
+    @Test
+    public void testAddComment() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.post_id", null);
+        // parameter type is org.apache.camel.component.linkedin.api.model.Comment
+        headers.put("CamelLinkedIn.comment", null);
+
+        requestBodyAndHeaders("direct://ADDCOMMENT", null, headers);
+    }
+
+    // TODO provide parameter values for flagCategory
+    @Ignore
+    @Test
+    public void testFlagCategory() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.post_id", null);
+        // parameter type is org.apache.camel.component.linkedin.api.model.PostCategoryCode
+        headers.put("CamelLinkedIn.postcategorycode", null);
+
+        requestBodyAndHeaders("direct://FLAGCATEGORY", null, headers);
+    }
+
+    // TODO provide parameter values for followPost
+    @Ignore
+    @Test
+    public void testFollowPost() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.post_id", null);
+        // parameter type is org.apache.camel.component.linkedin.api.model.IsFollowing
+        headers.put("CamelLinkedIn.isfollowing", null);
+
+        requestBodyAndHeaders("direct://FOLLOWPOST", null, headers);
+    }
+
+    // TODO provide parameter values for getPost
+    @Ignore
+    @Test
+    public void testGetPost() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.post_id", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.count", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.start", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+
+        final org.apache.camel.component.linkedin.api.model.Post result = requestBodyAndHeaders("direct://GETPOST", null, headers);
+
+        assertNotNull("getPost result", result);
+        LOG.debug("getPost: " + result);
+    }
+
+    // TODO provide parameter values for getPostComments
+    @Ignore
+    @Test
+    public void testGetPostComments() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.post_id", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.count", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.start", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", null);
+
+        final org.apache.camel.component.linkedin.api.model.Comments result = requestBodyAndHeaders("direct://GETPOSTCOMMENTS", null, headers);
+
+        assertNotNull("getPostComments result", result);
+        LOG.debug("getPostComments: " + result);
+    }
+
+    // TODO provide parameter values for likePost
+    @Ignore
+    @Test
+    public void testLikePost() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.post_id", null);
+        // parameter type is org.apache.camel.component.linkedin.api.model.IsLiked
+        headers.put("CamelLinkedIn.isliked", null);
+
+        requestBodyAndHeaders("direct://LIKEPOST", null, headers);
+    }
+
+    // TODO provide parameter values for removePost
+    @Ignore
+    @Test
+    public void testRemovePost() throws Exception {
+        // using String message body for single parameter "post_id"
+        requestBody("direct://REMOVEPOST", null);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                // test route for addComment
+                from("direct://ADDCOMMENT")
+                  .to("linkedin://" + PATH_PREFIX + "/addComment");
+
+                // test route for flagCategory
+                from("direct://FLAGCATEGORY")
+                  .to("linkedin://" + PATH_PREFIX + "/flagCategory");
+
+                // test route for followPost
+                from("direct://FOLLOWPOST")
+                  .to("linkedin://" + PATH_PREFIX + "/followPost");
+
+                // test route for getPost
+                from("direct://GETPOST")
+                  .to("linkedin://" + PATH_PREFIX + "/getPost");
+
+                // test route for getPostComments
+                from("direct://GETPOSTCOMMENTS")
+                  .to("linkedin://" + PATH_PREFIX + "/getPostComments");
+
+                // test route for likePost
+                from("direct://LIKEPOST")
+                  .to("linkedin://" + PATH_PREFIX + "/likePost");
+
+                // test route for removePost
+                from("direct://REMOVEPOST")
+                  .to("linkedin://" + PATH_PREFIX + "/removePost?inBody=post_id");
+
+            }
+        };
+    }
+}


[20/23] camel git commit: CAMEL-8575: Applied patch to fix Salesforce security login retries, with thanks to Dmitry Lysai

Posted by dh...@apache.org.
CAMEL-8575: Applied patch to fix Salesforce security login retries, with thanks to Dmitry Lysai


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

Branch: refs/heads/master
Commit: b858dbb913e04ca3a2943924aeb377736fb512ec
Parents: 3ef0af5
Author: Dhiraj Bokde <dh...@yahoo.com>
Authored: Mon Apr 6 13:28:01 2015 -0700
Committer: Dhiraj Bokde <dh...@yahoo.com>
Committed: Mon Apr 6 13:29:00 2015 -0700

----------------------------------------------------------------------
 .../internal/client/AbstractClientBase.java     | 26 ++++++++---------
 .../salesforce/RestApiIntegrationTest.java      | 30 ++++++++++++++++++++
 2 files changed, 43 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/b858dbb9/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
index a00d289..b0c7442 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
@@ -103,19 +103,6 @@ public abstract class AbstractClientBase implements SalesforceSession.Salesforce
 
     protected void doHttpRequest(final ContentExchange request, final ClientResponseCallback callback) {
 
-        // use SalesforceSecurityListener for security login retries
-        try {
-            final boolean isHttps = HttpSchemes.HTTPS.equals(String.valueOf(request.getScheme()));
-            request.setEventListener(new SalesforceSecurityListener(
-                    httpClient.getDestination(request.getAddress(), isHttps),
-                    request, session, accessToken));
-        } catch (IOException e) {
-            // propagate exception
-            callback.onResponse(null, new SalesforceException(
-                    String.format("Error registering security listener: %s", e.getMessage()),
-                    e));
-        }
-
         // use HttpEventListener for lifecycle events
         request.setEventListener(new HttpEventListenerWrapper(request.getEventListener(), true) {
 
@@ -169,6 +156,19 @@ public abstract class AbstractClientBase implements SalesforceSession.Salesforce
             }
         });
 
+        // use SalesforceSecurityListener for security login retries
+        try {
+            final boolean isHttps = HttpSchemes.HTTPS.equals(String.valueOf(request.getScheme()));
+            request.setEventListener(new SalesforceSecurityListener(
+                    httpClient.getDestination(request.getAddress(), isHttps),
+                    request, session, accessToken));
+        } catch (IOException e) {
+            // propagate exception
+            callback.onResponse(null, new SalesforceException(
+                    String.format("Error registering security listener: %s", e.getMessage()),
+                    e));
+        }
+
         // execute the request
         try {
             httpClient.send(request);

http://git-wip-us.apache.org/repos/asf/camel/blob/b858dbb9/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
index 9627cf3..e87a21f 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
@@ -44,7 +44,14 @@ import org.apache.camel.component.salesforce.dto.generated.Document;
 import org.apache.camel.component.salesforce.dto.generated.Line_Item__c;
 import org.apache.camel.component.salesforce.dto.generated.Merchandise__c;
 import org.apache.camel.component.salesforce.dto.generated.QueryRecordsLine_Item__c;
+import org.apache.camel.util.jsse.SSLContextParameters;
+import org.eclipse.jetty.client.ContentExchange;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.client.RedirectListener;
+import org.eclipse.jetty.http.HttpMethods;
 import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -59,6 +66,29 @@ public class RestApiIntegrationTest extends AbstractSalesforceTestBase {
     private static String testId;
 
     @Test
+    public void testRetry() throws Exception {
+        SalesforceComponent sf = context().getComponent("salesforce", SalesforceComponent.class);
+        String accessToken = sf.getSession().getAccessToken();
+
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        sslContextFactory.setSslContext(new SSLContextParameters().createSSLContext());
+        HttpClient httpClient = new HttpClient(sslContextFactory);
+        httpClient.setConnectTimeout(60000);
+        httpClient.setTimeout(60000);
+        httpClient.registerListener(RedirectListener.class.getName());
+        httpClient.start();
+
+        ContentExchange logoutGet = new ContentExchange(true);
+        logoutGet.setURL(sf.getLoginConfig().getLoginUrl() + "/services/oauth2/revoke?token=" + accessToken);
+        logoutGet.setMethod(HttpMethods.GET);
+        httpClient.send(logoutGet);
+        assertEquals(HttpExchange.STATUS_COMPLETED, logoutGet.waitForDone());
+        assertEquals(HttpStatus.OK_200, logoutGet.getResponseStatus());
+
+        doTestGetGlobalObjects("");
+    }
+
+    @Test
     public void testGetVersions() throws Exception {
         doTestGetVersions("");
         doTestGetVersions("Xml");


[08/23] camel git commit: Fixed copyright

Posted by dh...@apache.org.
Fixed copyright


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

Branch: refs/heads/trunk
Commit: c87d4c053ea783bc0e971737c6f1d9a647a175ef
Parents: 72a1767
Author: Dhiraj Bokde <db...@fusesource.com>
Authored: Wed Jun 5 02:54:44 2013 -0700
Committer: Dhiraj Bokde <db...@fusesource.com>
Committed: Wed Jun 5 02:54:44 2013 -0700

----------------------------------------------------------------------
 .../salesforce/SalesforceEndpointConfig.java        | 16 ++++++++++++++++
 .../internal/streaming/PushTopicHelper.java         | 16 ++++++++++++++++
 .../component/salesforce/LoginConfigHelper.java     | 16 ++++++++++++++++
 .../salesforce/internal/SessionIntegrationTest.java | 16 ++++++++++++++++
 .../org/apache/camel/maven/CamelSalesforceMojo.java | 13 +++++++------
 .../maven/CamelSalesforceMojoIntegrationTest.java   | 14 +++++++-------
 6 files changed, 78 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/c87d4c05/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 065f2f1..817871b 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
@@ -1,3 +1,19 @@
+/**
+ * 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 org.apache.camel.RuntimeCamelException;

http://git-wip-us.apache.org/repos/asf/camel/blob/c87d4c05/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/PushTopicHelper.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/PushTopicHelper.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/PushTopicHelper.java
index b1c7f4d..4e51281 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/PushTopicHelper.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/streaming/PushTopicHelper.java
@@ -1,3 +1,19 @@
+/**
+ * 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.internal.streaming;
 
 import org.apache.camel.CamelException;

http://git-wip-us.apache.org/repos/asf/camel/blob/c87d4c05/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java
index 8c5d343..1f8b480 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java
@@ -1,3 +1,19 @@
+/**
+ * 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 org.junit.Assert;

http://git-wip-us.apache.org/repos/asf/camel/blob/c87d4c05/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SessionIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SessionIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SessionIntegrationTest.java
index f36775d..5e5ab5f 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SessionIntegrationTest.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SessionIntegrationTest.java
@@ -1,3 +1,19 @@
+/**
+ * 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.internal;
 
 import org.eclipse.jetty.client.HttpClient;

http://git-wip-us.apache.org/repos/asf/camel/blob/c87d4c05/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 b0a4791..70942a4 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
@@ -1,9 +1,10 @@
-/*
- * Copyright 2001-2005 The Apache Software Foundation.
- *
- * Licensed 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
+/**
+ * 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
  *

http://git-wip-us.apache.org/repos/asf/camel/blob/c87d4c05/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 fe7bf88..781c592 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
@@ -1,9 +1,10 @@
-/*
- * Copyright 2001-2005 The Apache Software Foundation.
- *
- * Licensed 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
+/**
+ * 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
  *
@@ -13,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.camel.maven;
 
 import org.apache.maven.plugin.logging.SystemStreamLog;


[17/23] camel git commit: CAMEL-6568: Initial version of LinkedIn component

Posted by dh...@apache.org.
CAMEL-6568: Initial version of LinkedIn component


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

Branch: refs/heads/linkedin-component
Commit: b490a90cd2d4ecd2d2382e0c09323db75b9c0918
Parents: 91e19c1
Author: Dhiraj Bokde <dh...@yahoo.com>
Authored: Thu Jul 10 17:46:47 2014 -0700
Committer: Dhiraj Bokde <dh...@yahoo.com>
Committed: Thu Jul 10 17:49:20 2014 -0700

----------------------------------------------------------------------
 .../camel-linkedin/camel-linkedin-api/pom.xml   |  214 ++
 .../component/linkedin/api/DoubleAdapter.java   |   35 +
 .../linkedin/api/LinkedInException.java         |   47 +
 .../api/LinkedInExceptionResponseFilter.java    |   77 +
 .../api/LinkedInOAuthRequestFilter.java         |  269 +++
 .../component/linkedin/api/LongAdapter.java     |   35 +
 .../component/linkedin/api/OAuthParams.java     |  107 +
 .../component/linkedin/api/OAuthScope.java      |   64 +
 .../linkedin/api/OAuthSecureStorage.java        |   36 +
 .../component/linkedin/api/OAuthToken.java      |   50 +
 .../src/main/resources/linkedin-api-schema.xjb  |  447 ++++
 .../src/main/resources/linkedin-api-schema.xsd  | 2255 ++++++++++++++++++
 .../src/main/resources/linkedin-api-wadl.xml    | 1045 ++++++++
 .../src/main/resources/wadl.xsd                 |  263 ++
 .../api/AbstractResourceIntegrationTest.java    |  125 +
 .../api/PeopleResourceIntegrationTest.java      |   99 +
 .../api/SearchResourceIntegrationTest.java      |   47 +
 .../camel-linkedin-component/pom.xml            |  280 +++
 .../component/linkedin/LinkedInComponent.java   |  106 +
 .../linkedin/LinkedInConfiguration.java         |  155 ++
 .../component/linkedin/LinkedInConsumer.java    |   58 +
 .../component/linkedin/LinkedInEndpoint.java    |  174 ++
 .../component/linkedin/LinkedInProducer.java    |   59 +
 .../internal/CachingOAuthSecureStorage.java     |   50 +
 .../linkedin/internal/LinkedInConstants.java    |   29 +
 .../internal/LinkedInPropertiesHelper.java      |   40 +
 .../org/apache/camel/component/linkedin         |    1 +
 .../linkedin/AbstractLinkedInTestSupport.java   |   73 +
 .../CommentsResourceIntegrationTest.java        |   66 +
 .../CompaniesResourceIntegrationTest.java       |  353 +++
 .../linkedin/GroupsResourceIntegrationTest.java |   65 +
 .../linkedin/JobsResourceIntegrationTest.java   |   93 +
 .../linkedin/PeopleResourceIntegrationTest.java |  636 +++++
 .../linkedin/PostsResourceIntegrationTest.java  |  162 ++
 .../linkedin/SearchResourceIntegrationTest.java |  161 ++
 .../src/test/resources/log4j.properties         |   36 +
 .../src/test/resources/test-options.properties  |   28 +
 components/camel-linkedin/pom.xml               |   66 +
 components/pom.xml                              |    1 +
 39 files changed, 7907 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/pom.xml b/components/camel-linkedin/camel-linkedin-api/pom.xml
new file mode 100644
index 0000000..012d04f
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/pom.xml
@@ -0,0 +1,214 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<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.component.linkedin</groupId>
+    <artifactId>camel-linkedin-parent</artifactId>
+    <version>2.14-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>camel-linkedin-api</artifactId>
+  <name>Camel LinkedIn Component API</name>
+  <description>API for Camel LinkedIn Component</description>
+  <packaging>bundle</packaging>
+
+  <properties>
+    <camel.osgi.export.pkg>org.apache.camel.component.linkedin.api*</camel.osgi.export.pkg>
+    <htmlunit-version>2.15</htmlunit-version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.cxf</groupId>
+      <artifactId>cxf-core</artifactId>
+      <version>${cxf-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cxf</groupId>
+      <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+      <version>${cxf-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cxf</groupId>
+      <artifactId>cxf-rt-rs-security-oauth2</artifactId>
+      <version>${cxf-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cxf</groupId>
+      <artifactId>cxf-rt-rs-extension-providers</artifactId>
+      <version>${cxf-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cxf</groupId>
+      <artifactId>cxf-tools-wadlto-jaxrs</artifactId>
+      <version>${cxf-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>net.sourceforge.htmlunit</groupId>
+      <artifactId>htmlunit</artifactId>
+      <version>${htmlunit-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
+      <version>${jackson2-version}</version>
+    </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.cxf</groupId>
+      <artifactId>cxf-rt-rs-client</artifactId>
+      <version>${cxf-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <testResources>
+      <testResource>
+        <directory>${project.basedir}/src/test/resources</directory>
+      </testResource>
+      <testResource>
+        <directory>${project.basedir}/../camel-linkedin-component/src/test/resources</directory>
+      </testResource>
+    </testResources>
+
+    <plugins>
+
+      <!-- uncomment to validate XSD since wadl2java doesn't report line numbers in errors -->
+<!--
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>jaxb2-maven-plugin</artifactId>
+        <version>1.6</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>xjc</goal>
+            </goals>
+            <configuration>
+              <target>2.1</target>
+              <schemaDirectory>src/main/resources</schemaDirectory>
+              <schemaFiles>linkedin-api-schema.xsd</schemaFiles>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+-->
+
+      <!-- Generate API from WADL -->
+      <plugin>
+        <groupId>org.apache.cxf</groupId>
+        <artifactId>cxf-wadl2java-plugin</artifactId>
+        <version>${cxf-version}</version>
+        <executions>
+          <execution>
+            <id>generate-wadl-sources</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>wadl2java</goal>
+            </goals>
+            <configuration>
+              <sourceRoot>${project.build.directory}/generated-sources/cxf</sourceRoot>
+              <wadlOptions>
+                <wadlOption>
+                  <wadl>${project.basedir}/src/main/resources/linkedin-api-wadl.xml</wadl>
+                  <packagename>org.apache.camel.component.linkedin.api</packagename>
+                  <bindingFiles>
+                    <bindingFile>${project.basedir}/src/main/resources/linkedin-api-schema.xjb</bindingFile>
+                  </bindingFiles>
+                  <extraargs>
+                    <extraarg>-verbose</extraarg>
+                    <extraarg>-generateEnums</extraarg>
+                    <extraarg>-xjc-quiet</extraarg>
+                  </extraargs>
+                </wadlOption>
+              </wadlOptions>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!-- add generated source to build -->
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>add-generated-sources</id>
+            <goals>
+              <goal>add-source</goal>
+            </goals>
+            <configuration>
+              <sources>
+                <source>${project.build.directory}/generated-sources/cxf</source>
+              </sources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!-- to generate API Javadoc -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>add-javadoc</id>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+            <configuration>
+              <attach>true</attach>
+              <source>1.6</source>
+              <quiet>true</quiet>
+              <detectOfflineLinks>false</detectOfflineLinks>
+              <javadocVersion>1.6</javadocVersion>
+              <encoding>UTF-8</encoding>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+    </plugins>
+  </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/DoubleAdapter.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/DoubleAdapter.java b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/DoubleAdapter.java
new file mode 100644
index 0000000..029681a
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/DoubleAdapter.java
@@ -0,0 +1,35 @@
+/**
+ * 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.linkedin.api;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+public class DoubleAdapter extends XmlAdapter<String, Double>
+{
+
+    public Double unmarshal(String value) {
+        return javax.xml.bind.DatatypeConverter.parseDouble(value);
+    }
+
+    public String marshal(Double value) {
+        if (value == null) {
+            return null;
+        }
+        return javax.xml.bind.DatatypeConverter.printDouble(value);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/LinkedInException.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/LinkedInException.java b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/LinkedInException.java
new file mode 100644
index 0000000..74b7520
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/LinkedInException.java
@@ -0,0 +1,47 @@
+/**
+ * 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.linkedin.api;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+
+import org.apache.camel.component.linkedin.api.model.Error;
+
+/**
+ * Exception wrapper for {@link org.apache.camel.component.linkedin.api.model.Error}
+ */
+public class LinkedInException extends WebApplicationException {
+
+    private static final long serialVersionUID = -6570614972033527197L;
+
+    private final Error error;
+    private final Response response;
+
+    public LinkedInException(Error error, Response response) {
+        super(error.getMessage(), response);
+        this.error = error;
+        this.response = response;
+    }
+
+    public Error getError() {
+        return error;
+    }
+
+    public Response getResponse() {
+        return response;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/LinkedInExceptionResponseFilter.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/LinkedInExceptionResponseFilter.java b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/LinkedInExceptionResponseFilter.java
new file mode 100644
index 0000000..4b180d9
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/LinkedInExceptionResponseFilter.java
@@ -0,0 +1,77 @@
+/**
+ * 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.linkedin.api;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Priority;
+import javax.ws.rs.Priorities;
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientResponseContext;
+import javax.ws.rs.client.ClientResponseFilter;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.Provider;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+
+import org.apache.camel.component.linkedin.api.model.Error;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Response filter for throwing {@link LinkedInException}
+ * when response contains {@link org.apache.camel.component.linkedin.api.model.Error}
+ */
+@Provider
+@Priority(Priorities.USER)
+public class LinkedInExceptionResponseFilter implements ClientResponseFilter {
+
+    private static final Logger LOG = LoggerFactory.getLogger(LinkedInExceptionResponseFilter.class);
+    private final JAXBContext jaxbContext;
+
+    public LinkedInExceptionResponseFilter() {
+        try {
+            jaxbContext = JAXBContext.newInstance(Error.class.getPackage().getName());
+        } catch (JAXBException e) {
+            throw new IllegalArgumentException("Error initializing JAXB: " + e.getMessage(), e);
+        }
+    }
+
+    @Override
+    public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
+        if (responseContext.getStatus() != Response.Status.OK.getStatusCode() && responseContext.hasEntity()) {
+            try {
+                final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+                final Error error = (Error) unmarshaller.unmarshal(responseContext.getEntityStream());
+
+                final Response.ResponseBuilder builder = Response.status(responseContext.getStatusInfo());
+                builder.entity(error);
+                // copy response headers
+                for (Map.Entry<String, List<String>> header : responseContext.getHeaders().entrySet()) {
+                    builder.header(header.getKey(), header.getValue());
+                }
+
+                throw new LinkedInException(error, builder.build());
+            } catch (JAXBException e) {
+                // log and ignore
+                LOG.warn("Unable to parse LinkedIn error: " + e.getMessage(), e);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/LinkedInOAuthRequestFilter.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/LinkedInOAuthRequestFilter.java b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/LinkedInOAuthRequestFilter.java
new file mode 100644
index 0000000..4fd7194
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/LinkedInOAuthRequestFilter.java
@@ -0,0 +1,269 @@
+/**
+ * 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.linkedin.api;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.annotation.Priority;
+import javax.ws.rs.Priorities;
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.ext.Provider;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.gargoylesoftware.htmlunit.BrowserVersion;
+import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
+import com.gargoylesoftware.htmlunit.HttpMethod;
+import com.gargoylesoftware.htmlunit.Page;
+import com.gargoylesoftware.htmlunit.ProxyConfig;
+import com.gargoylesoftware.htmlunit.WebClient;
+import com.gargoylesoftware.htmlunit.WebClientOptions;
+import com.gargoylesoftware.htmlunit.WebRequest;
+import com.gargoylesoftware.htmlunit.WebResponse;
+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.http.HttpHost;
+import org.apache.http.HttpStatus;
+import org.apache.http.conn.params.ConnRoutePNames;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * LinkedIn OAuth request filter to handle OAuth token.
+ */
+@Provider
+@Priority(Priorities.AUTHENTICATION)
+public final class LinkedInOAuthRequestFilter implements ClientRequestFilter {
+
+    public static final String BASE_ADDRESS = "https://api.linkedin.com/v1";
+
+    private static final Logger LOG = LoggerFactory.getLogger(LinkedInOAuthRequestFilter.class);
+
+    private static final String AUTHORIZATION_URL = "https://www.linkedin.com/uas/oauth2/authorization?"
+        + "response_type=code&client_id=%s&state=%s&redirect_uri=%s";
+    private static final String AUTHORIZATION_URL_WITH_SCOPE = "https://www.linkedin.com/uas/oauth2/authorization?"
+        + "response_type=code&client_id=%s&state=%s&scope=%s&redirect_uri=%s";
+
+    private static final String ACCESS_TOKEN_URL = "https://www.linkedin.com/uas/oauth2/accessToken?"
+        + "grant_type=authorization_code&code=%s&redirect_uri=%s&client_id=%s&client_secret=%s";
+
+    private static final Pattern QUERY_PARAM_PATTERN = Pattern.compile("&?([^=]+)=([^&]+)");
+
+    private final WebClient webClient;
+
+    private final OAuthParams oAuthParams;
+
+    private OAuthToken oAuthToken;
+
+    @SuppressWarnings("deprecation")
+    public LinkedInOAuthRequestFilter(OAuthParams oAuthParams, Map<String, Object> httpParams,
+                                      boolean lazyAuth) {
+
+        this.oAuthParams = oAuthParams;
+        this.oAuthToken = null;
+
+        // create HtmlUnit client
+        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
+        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);
+        }
+
+        if (!lazyAuth) {
+            try {
+                updateOAuthToken();
+            } catch (IOException e) {
+                throw new IllegalArgumentException(
+                    String.format("Error authorizing user %s: %s", oAuthParams.getUserName(), e.getMessage()), e);
+            }
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    private String getRefreshToken() {
+        // authorize application on user's behalf
+        webClient.getOptions().setRedirectEnabled(true);
+
+        try {
+            final String csrfId = String.valueOf(new SecureRandom().nextLong());
+
+            final String encodedRedirectUri = URLEncoder.encode(oAuthParams.getRedirectUri(), "UTF-8");
+            final OAuthScope[] scopes = oAuthParams.getScopes();
+
+            final String url;
+            if (scopes == null || scopes.length == 0) {
+                url = String.format(AUTHORIZATION_URL, oAuthParams.getClientId(),
+                    csrfId, encodedRedirectUri);
+            } else {
+                final int nScopes = scopes.length;
+                final StringBuilder builder = new StringBuilder();
+                int i = 0;
+                for (OAuthScope scope : scopes) {
+                    builder.append(scope.getValue());
+                    if (++i < nScopes) {
+                        builder.append("%20");
+                    }
+                }
+                url = String.format(AUTHORIZATION_URL_WITH_SCOPE, oAuthParams.getClientId(), csrfId,
+                    builder.toString(), encodedRedirectUri);
+            }
+            final HtmlPage authPage = webClient.getPage(url);
+
+            // submit login credentials
+            final HtmlForm loginForm = authPage.getFormByName("oauth2SAuthorizeForm");
+            final HtmlTextInput login = loginForm.getInputByName("session_key");
+            login.setText(oAuthParams.getUserName());
+            final HtmlPasswordInput password = loginForm.getInputByName("session_password");
+            password.setText(oAuthParams.getUserPassword());
+            final HtmlSubmitInput submitInput = loginForm.getInputByName("authorize");
+
+            // disable redirect to avoid loading redirect URL
+            webClient.getOptions().setRedirectEnabled(false);
+
+            // validate CSRF and get authorization code
+            String redirectQuery;
+            try {
+                final Page redirectPage = submitInput.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)) {
+                throw new SecurityException("Invalid CSRF code!");
+            } else {
+                // return authorization code
+                // TODO check results??
+                return params.get("code");
+            }
+
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Error authorizing application: " + e.getMessage(), e);
+        }
+    }
+
+    public void close() {
+        webClient.closeAllWindows();
+    }
+
+    private OAuthToken getAccessToken(String refreshToken) throws IOException {
+        final String tokenUrl = String.format(ACCESS_TOKEN_URL, refreshToken,
+            oAuthParams.getRedirectUri(), oAuthParams.getClientId(), oAuthParams.getClientSecret());
+        final WebRequest webRequest = new WebRequest(new URL(tokenUrl), HttpMethod.POST);
+
+        final WebResponse webResponse = webClient.loadWebResponse(webRequest);
+        if (webResponse.getStatusCode() != HttpStatus.SC_OK) {
+            throw new IOException(String.format("Error getting access token: [%s: %s]",
+                webResponse.getStatusCode(), webResponse.getStatusMessage()));
+        }
+        final long currentTime = System.currentTimeMillis();
+        final ObjectMapper mapper = new ObjectMapper();
+        final Map map = mapper.readValue(webResponse.getContentAsStream(), Map.class);
+        final String accessToken = map.get("access_token").toString();
+        final Integer expiresIn = Integer.valueOf(map.get("expires_in").toString());
+        return new OAuthToken(refreshToken, accessToken,
+            currentTime + TimeUnit.MILLISECONDS.convert(expiresIn, TimeUnit.SECONDS));
+    }
+
+    public synchronized OAuthToken getOAuthToken() {
+        return oAuthToken;
+    }
+
+    @Override
+    public void filter(ClientRequestContext requestContext) throws IOException {
+        updateOAuthToken();
+
+        // add OAuth query param
+        final String requestUri = requestContext.getUri().toString();
+        final StringBuilder builder = new StringBuilder(requestUri);
+        if (requestUri.contains("?")) {
+            builder.append('&');
+        } else {
+            builder.append('?');
+        }
+        builder.append("oauth2_access_token=").append(oAuthToken.getAccessToken());
+        requestContext.setUri(URI.create(builder.toString()));
+    }
+
+    private synchronized void updateOAuthToken() throws IOException {
+
+        // check whether an update is needed
+        final long currentTime = System.currentTimeMillis();
+        if (oAuthToken == null || oAuthToken.getExpiryTime() < currentTime) {
+            LOG.info("OAuth token doesn't exist or has expired");
+
+            // check whether a secure store is provided
+            final OAuthSecureStorage secureStorage = oAuthParams.getSecureStorage();
+            if (secureStorage != null) {
+
+                oAuthToken = secureStorage.getOAuthToken();
+                // if it returned a valid token, we are done, otherwise fall through and generate a new token
+                if (oAuthToken != null && oAuthToken.getExpiryTime() > currentTime) {
+                    return;
+                }
+                LOG.info("OAuth secure storage returned a null or expired token, creating a new token...");
+
+                // throw an exception if a user password is not set for authorization
+                if (oAuthParams.getUserPassword() == null || oAuthParams.getUserPassword().isEmpty()) {
+                    throw new IllegalArgumentException("Missing password for LinkedIn authorization");
+                }
+            }
+
+            // need new OAuth token, authorize user, LinkedIn does not support OAuth2 grant_type=refresh_token
+            final String refreshToken = getRefreshToken();
+            this.oAuthToken = getAccessToken(refreshToken);
+            LOG.info("OAuth token created!");
+
+            // notify secure storage
+            if (secureStorage != null) {
+                secureStorage.saveOAuthToken(this.oAuthToken);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/LongAdapter.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/LongAdapter.java b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/LongAdapter.java
new file mode 100644
index 0000000..3fe63cc
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/LongAdapter.java
@@ -0,0 +1,35 @@
+/**
+ * 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.linkedin.api;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+public class LongAdapter extends XmlAdapter<String, Long>
+{
+
+    public Long unmarshal(String value) {
+        return new Long(value);
+    }
+
+    public String marshal(Long value) {
+        if (value == null) {
+            return null;
+        }
+        return value.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/OAuthParams.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/OAuthParams.java b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/OAuthParams.java
new file mode 100644
index 0000000..0e73a13
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/OAuthParams.java
@@ -0,0 +1,107 @@
+/**
+ * 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.linkedin.api;
+
+import java.util.Arrays;
+
+/**
+ * Parameters for OAuth 2.0 flow used by {@link LinkedInOAuthRequestFilter}.
+*/
+public class OAuthParams {
+
+    private String userName;
+    private String userPassword;
+
+    private OAuthSecureStorage secureStorage;
+
+    private String clientId;
+    private String clientSecret;
+
+    private OAuthScope[] scopes;
+    private String redirectUri;
+
+    public OAuthParams() {
+    }
+
+    public OAuthParams(String userName, String userPassword, OAuthSecureStorage secureStorage,
+                       String clientId, String clientSecret,
+                       String redirectUri, OAuthScope... scopes) {
+        this.userName = userName;
+        this.userPassword = userPassword;
+        this.secureStorage = secureStorage;
+        this.clientId = clientId;
+        this.clientSecret = clientSecret;
+        this.scopes = scopes != null ? Arrays.copyOf(scopes, scopes.length) : null;
+        this.redirectUri = redirectUri;
+    }
+
+    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 String getClientId() {
+        return clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public OAuthScope[] getScopes() {
+        return scopes;
+    }
+
+    public void setScopes(OAuthScope[] scopes) {
+        this.scopes = scopes;
+    }
+
+    public String getRedirectUri() {
+        return redirectUri;
+    }
+
+    public void setRedirectUri(String redirectUri) {
+        this.redirectUri = redirectUri;
+    }
+
+    public String getClientSecret() {
+        return clientSecret;
+    }
+
+    public void setClientSecret(String clientSecret) {
+        this.clientSecret = clientSecret;
+    }
+
+    public OAuthSecureStorage getSecureStorage() {
+        return secureStorage;
+    }
+
+    public void setSecureStorage(OAuthSecureStorage secureStorage) {
+        this.secureStorage = secureStorage;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/OAuthScope.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/OAuthScope.java b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/OAuthScope.java
new file mode 100644
index 0000000..aadf353
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/OAuthScope.java
@@ -0,0 +1,64 @@
+/**
+ * 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.linkedin.api;
+
+/**
+ * OAuth scope for use in {@link LinkedInOAuthRequestFilter}
+ */
+public enum OAuthScope {
+    
+    R_BASICPROFILE("r_basicprofile"),
+    R_FULLPROFILE("r_fullprofile"),
+    R_EMAILADDRESS("r_emailaddress"),
+    R_NETWORK("r_network"),
+    R_CONTACTINFO("r_contactinfo"),
+    RW_NUS("rw_nus"),
+    RW_COMPANY_ADMIN("rw_company_admin"),
+    RW_GROUPS("rw_groups"),
+    W_MESSAGES("w_messages");
+
+    private final String value;
+
+    private OAuthScope(String value) {
+        this.value = value;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public static OAuthScope fromValue(String value) {
+        for (OAuthScope scope : values()) {
+            if (scope.value.equals(value)) {
+                return scope;
+            }
+        }
+        throw new IllegalArgumentException(value);
+    }
+
+    public static OAuthScope[] fromValues(String... values) {
+        if (values == null || values.length == 0) {
+            return new OAuthScope[0];
+        }
+        final OAuthScope[] result = new OAuthScope[values.length];
+        int i = 0;
+        for (String value : values) {
+            result[i++] = fromValue(value);
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/OAuthSecureStorage.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/OAuthSecureStorage.java b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/OAuthSecureStorage.java
new file mode 100644
index 0000000..cf5542e
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/OAuthSecureStorage.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.linkedin.api;
+
+/**
+ * Secure token storage for {@link OAuthToken}
+ */
+public interface OAuthSecureStorage {
+
+    /**
+     * Get token from secure storage.
+     * @return null if a secure token doesn't exist and {@link LinkedInOAuthRequestFilter} must create one.
+     */
+    OAuthToken getOAuthToken();
+
+    /**
+     * Save token to secure storage.
+     * Only called when {@link LinkedInOAuthRequestFilter} creates one.
+     * @param newToken
+     */
+    void saveOAuthToken(OAuthToken newToken);
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/OAuthToken.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/OAuthToken.java b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/OAuthToken.java
new file mode 100644
index 0000000..cf04380
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/src/main/java/org/apache/camel/component/linkedin/api/OAuthToken.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.linkedin.api;
+
+/**
+* LinkedIn OAuth Token
+*/
+public final class OAuthToken {
+
+    private final String refreshToken;
+    private final String accessToken;
+    private long expiryTime;
+
+    public OAuthToken(String refreshToken, String accessToken, long expiryTime) {
+        this.refreshToken = refreshToken;
+        this.accessToken = accessToken;
+        this.expiryTime = expiryTime;
+    }
+
+    public String getRefreshToken() {
+        return refreshToken;
+    }
+
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    public long getExpiryTime() {
+        return expiryTime;
+    }
+
+    // package method for testing only
+    void setExpiryTime(long expiryTime) {
+        this.expiryTime = expiryTime;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-api/src/main/resources/linkedin-api-schema.xjb
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-api/src/main/resources/linkedin-api-schema.xjb b/components/camel-linkedin/camel-linkedin-api/src/main/resources/linkedin-api-schema.xjb
new file mode 100644
index 0000000..778a4f5
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-api/src/main/resources/linkedin-api-schema.xjb
@@ -0,0 +1,447 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<bindings version="2.0" xmlns="http://java.sun.com/xml/ns/jaxb"
+    xmlns:xs="http://www.w3.org/2001/XMLSchema"
+	xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
+    extensionBindingPrefixes="xjc"
+    schemaLocation="linkedin-api-schema.xsd" node="/xs:schema">
+
+    <!-- Copied with permission from the linkedin-j library https://code.google.com/p/linkedin-j/ -->
+	<globalBindings localScoping="toplevel" generateValueClass="true">
+		<xjc:javaType name="Double" xmlType="xs:double"
+		    adapter="org.apache.camel.component.linkedin.api.DoubleAdapter"/>
+		<xjc:javaType name="Long" xmlType="xs:integer"
+		    adapter="org.apache.camel.component.linkedin.api.LongAdapter"/>
+		<!-- <xjc:superInterface name="SchemaEntity"/> -->
+		<!-- <xjc:superClass name="BaseSchemaEntity"/> -->
+		<!-- <xjc:serializable uid="1L"/> -->
+		<!-- <xjc:serializable uid="6877416375268387499L"/> -->
+	</globalBindings>
+
+    <schemaBindings>
+      <package name="org.apache.camel.component.linkedin.api.model" />
+    </schemaBindings>
+
+	<bindings node="//xs:element[@name='content-type']/xs:simpleType">
+		<typesafeEnumClass name="NetworkUpdateContentType">
+			<typesafeEnumMember name="LINKED_IN_HTML" value="linkedin-html"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='connect-type']/xs:simpleType">
+		<typesafeEnumClass name="InviteConnectType" >
+			<typesafeEnumMember name="FRIEND" value="friend"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='update-type']/xs:simpleType">
+		<typesafeEnumClass name="NetworkUpdateReturnType">
+			<typesafeEnumMember name="ANSWER_UPDATE" value="ANSW"/>
+			<typesafeEnumMember name="APPLICATION_CONNECTION_UPDATE" value="APPM"/>
+			<typesafeEnumMember name="APPLICATION_TO_MEMBER_UPDATE" value="APPS"/>
+			<typesafeEnumMember name="CONNECTION_ADDED_CONNECTIONS" value="CONN"/>
+			<typesafeEnumMember name="NEW_CONNECTIONS" value="NCON"/>
+			<typesafeEnumMember name="CONTACT_JOINED" value="CCEM"/>
+			<typesafeEnumMember name="JOB_POSTED" value="JOBP"/>
+			<typesafeEnumMember name="CONNECTION_JOINED_GROUP" value="JGRP"/>
+			<typesafeEnumMember name="CONNECTION_UPDATED_PICTURE" value="PICU"/>
+			<typesafeEnumMember name="CONNECTION_RECOMMENDED" value="PREC"/>
+			<typesafeEnumMember name="CONNECTION_UPDATED_PROFILE" value="PROF"/>
+			<typesafeEnumMember name="QUESTION_UPDATED" value="QSTN"/>
+			<typesafeEnumMember name="STATUS_UPDATED" value="STAT"/>
+			<typesafeEnumMember name="SHARED_ITEM" value="SHAR"/>
+			<typesafeEnumMember name="EXTENDED_PROFILE_UPDATED" value="PRFX"/>
+			<typesafeEnumMember name="COMPANY_UPDATED" value="CMPY"/>
+			<typesafeEnumMember name="VIRAL_UPDATE" value="VIRL"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='recommendation-type']/xs:complexType/xs:sequence/xs:element[@name='code']/xs:simpleType">
+		<typesafeEnumClass name="RecommendationCode">
+			<typesafeEnumMember name="COLLEAGUE" value="colleague"/>
+			<typesafeEnumMember name="BUSINESS_PARTNER" value="business-partner"/>
+			<typesafeEnumMember name="SERVICE_PROVIDER" value="service-provider"/>
+			<typesafeEnumMember name="EDUCATION" value="education"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='im-account-type']/xs:simpleType">
+		<typesafeEnumClass name="ImAccountType">
+			<typesafeEnumMember name="AIM" value="aim"/>
+			<typesafeEnumMember name="GTALK" value="gtalk"/>
+			<typesafeEnumMember name="ICQ" value="icq"/>
+			<typesafeEnumMember name="MSN" value="msn"/>
+			<typesafeEnumMember name="SKYPE" value="skype"/>
+			<typesafeEnumMember name="YAHOO" value="yahoo"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='phone-type']/xs:simpleType">
+		<typesafeEnumClass name="PhoneType">
+			<typesafeEnumMember name="HOME" value="home"/>
+			<typesafeEnumMember name="WORK" value="work"/>
+			<typesafeEnumMember name="MOBILE" value="mobile"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='level']/xs:simpleType">
+		<typesafeEnumClass name="ProficiencyLevelType">
+			<typesafeEnumMember name="ELEMENTARY" value="elementary"/>
+			<typesafeEnumMember name="LIMITED_WORKING" value="limited_working"/>
+			<typesafeEnumMember name="PROFESSIONAL_WORKING" value="professional_working"/>
+			<typesafeEnumMember name="FULL_PROFESSIONAL" value="full_professional"/>
+			<typesafeEnumMember name="NATIVE_BILINGUAL" value="native_or_bilingual"/>
+			<typesafeEnumMember name="BEGINNER" value="beginner"/>
+			<typesafeEnumMember name="INTERMEDIATE" value="intermediate"/>
+			<typesafeEnumMember name="ADVANCED" value="advanced"/>
+			<typesafeEnumMember name="EXPERT" value="expert"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='facet']/xs:complexType/xs:sequence/xs:element[@name='code']/xs:simpleType">
+		<typesafeEnumClass name="FacetType">
+			<typesafeEnumMember name="LOCATION" value="location"/>
+			<typesafeEnumMember name="INDUSTRY" value="industry"/>
+			<typesafeEnumMember name="NETWORK" value="network"/>
+			<typesafeEnumMember name="LANGUAGE" value="language"/>
+			<typesafeEnumMember name="CURRENT_COMPANY" value="current-company"/>
+			<typesafeEnumMember name="PAST_COMPANY" value="past-company"/>
+			<typesafeEnumMember name="SCHOOL" value="school"/>
+			<typesafeEnumMember name="COMPANY_SIZE" value="company-size"/>
+			<typesafeEnumMember name="NUM_FOLLOWERS_RANGE" value="num-followers-range"/>
+			<typesafeEnumMember name="FORTUNE" value="fortune"/>
+			<typesafeEnumMember name="COMPANY" value="company"/>
+			<typesafeEnumMember name="DATE_POSTED" value="date-posted"/>
+			<typesafeEnumMember name="JOB_FUNCTION" value="job-function"/>
+			<typesafeEnumMember name="EXPERIENCE_LEVEL" value="experience-level"/>
+			<typesafeEnumMember name="SALARY" value="salary"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='visibility']/xs:complexType/xs:sequence/xs:element[@name='code']/xs:simpleType">
+		<typesafeEnumClass name="VisibilityType">
+			<typesafeEnumMember name="ANYONE" value="anyone"/>
+			<typesafeEnumMember name="ALL_MEMBERS" value="all-members"/>
+			<typesafeEnumMember name="CONNECTIONS_ONLY" value="connections-only"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='role']/xs:complexType/xs:sequence/xs:element[@name='code']/xs:simpleType">
+		<typesafeEnumClass name="RoleCode">
+			<typesafeEnumMember name="HIRING_MANAGER" value="H"/>
+			<typesafeEnumMember name="COMPANY_RECRUITER" value="R"/>
+			<typesafeEnumMember name="STAFFING_FIRM" value="S"/>
+			<typesafeEnumMember name="COMPANY_EMPLOYEE" value="W"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='profile-field']/xs:complexType/xs:sequence/xs:element[@name='code']/xs:simpleType">
+		<typesafeEnumClass name="ProfileFieldCode">
+			<typesafeEnumMember name="DESCRIPTION" value="description"/>
+			<typesafeEnumMember name="SPECIALITY" value="speciality"/>
+			<typesafeEnumMember name="LOGO" value="logo"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='job-type']/xs:complexType/xs:sequence/xs:element[@name='code']/xs:simpleType">
+		<typesafeEnumClass name="JobTypeCode">
+			<typesafeEnumMember name="FULL_TIME" value="F"/>
+			<typesafeEnumMember name="PART_TIME" value="P"/>
+			<typesafeEnumMember name="CONTRACT" value="C"/>
+			<typesafeEnumMember name="TEMPORARY" value="T"/>
+			<typesafeEnumMember name="OTHER" value="O"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='experience-level']/xs:complexType/xs:sequence/xs:element[@name='code']/xs:simpleType">
+		<typesafeEnumClass name="ExperienceLevelCode">
+			<typesafeEnumMember name="NOT_APPLICABLE" value="0"/>
+			<typesafeEnumMember name="INTERNSHIP" value="1"/>
+			<typesafeEnumMember name="ENTRY_LEVEL" value="2"/>
+			<typesafeEnumMember name="ASSOCIATE" value="3"/>
+			<typesafeEnumMember name="MID_SENIOR_LEVEL" value="4"/>
+			<typesafeEnumMember name="DIRECTOR" value="5"/>
+			<typesafeEnumMember name="EXECUTIVE" value="6"/>			
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:complexType[@name='company-status']/xs:sequence/xs:element[@name='code']/xs:simpleType">
+		<typesafeEnumClass name="CompanyStatusCode">
+			<typesafeEnumMember name="OPERATING" value="OPR"/>
+			<typesafeEnumMember name="OPERATING_SUBSIDIARY" value="OPS"/>
+			<typesafeEnumMember name="REORGANIZING" value="RRG"/>
+			<typesafeEnumMember name="OUT_OF_BUSINESS" value="OOB"/>
+			<typesafeEnumMember name="ACQUIRED" value="ACQ"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='company-type']/xs:complexType/xs:sequence/xs:element[@name='code']/xs:simpleType">
+		<typesafeEnumClass name="CompanyTypeCode">
+			<typesafeEnumMember name="PUBLIC_COMPANY" value="C"/>
+			<typesafeEnumMember name="EDUCATIONAL" value="D"/>
+			<typesafeEnumMember name="SELF_EMPLOYED" value="E"/>
+			<typesafeEnumMember name="GOVT_AGENCY" value="G"/>
+			<typesafeEnumMember name="NON_PROFIT" value="N"/>
+			<typesafeEnumMember name="SELF_OWNED" value="O"/>
+			<typesafeEnumMember name="PRIVATELY_HELD" value="P"/>
+			<typesafeEnumMember name="PARTNERSHIP" value="S"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='stock-exchange']/xs:complexType/xs:sequence/xs:element[@name='code']/xs:simpleType">
+		<typesafeEnumClass name="StockExchangeCode">
+			<typesafeEnumMember name="AMERICAN_STOCK_EXCHANGE" value="ASE"/>
+			<typesafeEnumMember name="NEWYORK_STOCK_EXCHANGE" value="NYS"/>
+			<typesafeEnumMember name="NASDAQ" value="NMS"/>
+			<typesafeEnumMember name="LONDON_STOCK_EXCHANGE" value="LSE"/>
+			<typesafeEnumMember name="FRANKFURT_STOCK_EXCHANGE" value="FRA"/>
+			<typesafeEnumMember name="XETRA_TRADING_PLATFORM" value="GER"/>
+			<typesafeEnumMember name="EURONEXT_PARIS" value="PAR"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='job-function']/xs:complexType/xs:sequence/xs:element[@name='code']/xs:simpleType">
+		<typesafeEnumClass name="JobFunctionCode">
+			<typesafeEnumMember name="ACCOUNTING_AUDITING" value="acct"/>
+			<typesafeEnumMember name="ADMINISTRATIVE" value="adm"/>
+			<typesafeEnumMember name="ADVERTISING" value="advr"/>
+			<typesafeEnumMember name="ANALYST" value="anls"/>
+			<typesafeEnumMember name="ART_CREATIVE" value="art"/>
+			<typesafeEnumMember name="BUSINESS_DEVELOPMENT" value="bd"/>
+			<typesafeEnumMember name="CONSULTING" value="cnsl"/>
+			<typesafeEnumMember name="CUSTOMER_SERVICE" value="cust"/>
+			<typesafeEnumMember name="DISTRIBUTION" value="dist"/>
+			<typesafeEnumMember name="DESIGN" value="dsgn"/>
+			<typesafeEnumMember name="EDUCATION" value="edu"/>
+			<typesafeEnumMember name="ENGINEERING" value="eng"/>
+			<typesafeEnumMember name="FINANCE" value="fin"/>
+			<typesafeEnumMember name="GENERAL_BUSINESS" value="genb"/>
+			<typesafeEnumMember name="HUMAN_RESOURCES" value="hr"/>
+			<typesafeEnumMember name="INFORMATION_TECHNOLOGY" value="it"/>
+			<typesafeEnumMember name="LEGAL" value="lgl"/>
+			<typesafeEnumMember name="MANAGEMENT" value="mgmt"/>
+			<typesafeEnumMember name="MANUFACTURING" value="mnfc"/>
+			<typesafeEnumMember name="MARKETING" value="mrkt"/>
+			<typesafeEnumMember name="OTHER" value="othr"/>
+			<typesafeEnumMember name="PUBLIC_RELATIONS" value="pr"/>
+			<typesafeEnumMember name="PURCHASING" value="prch"/>
+			<typesafeEnumMember name="PRODUCT_MANAGEMENT" value="prdm"/>
+			<typesafeEnumMember name="PROJECT_MANAGEMENT" value="prjm"/>
+			<typesafeEnumMember name="PRODUCTION" value="prod"/>
+			<typesafeEnumMember name="QUALITY_ASSURANCE" value="qa"/>
+			<typesafeEnumMember name="RESEARCH" value="rsch"/>
+			<typesafeEnumMember name="SALES" value="sale"/>
+			<typesafeEnumMember name="SCIENCE" value="sci"/>
+			<typesafeEnumMember name="STRATEGY_PLANNING" value="stra"/>
+			<typesafeEnumMember name="SUPPLY_CHAIN" value="supl"/>
+			<typesafeEnumMember name="TRAINING" value="trng"/>
+			<typesafeEnumMember name="WRITING_EDITING" value="wrt"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='membership-state']/xs:complexType/xs:sequence/xs:element[@name='code']/xs:simpleType">
+		<typesafeEnumClass name="MembershipStateCode">
+			<typesafeEnumMember name="BLOCKED" value="blocked"/>
+			<typesafeEnumMember name="NON_MEMBER" value="non-member"/>
+			<typesafeEnumMember name="AWAITING_CONFIRMATION" value="awaiting-confirmation"/>
+			<typesafeEnumMember name="AWAITING_PARENT_GROUP_CONFIRMATION" value="awaiting-parent-group-confirmation"/>
+			<typesafeEnumMember name="MEMBER" value="member"/>
+			<typesafeEnumMember name="MODERATOR" value="moderator"/>
+			<typesafeEnumMember name="MANAGER" value="manager"/>
+			<typesafeEnumMember name="OWNER" value="owner"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='email-digest-frequency']/xs:complexType/xs:sequence/xs:element[@name='code']/xs:simpleType">
+		<typesafeEnumClass name="EmailDigestFrequencyCode">
+			<typesafeEnumMember name="NONE" value="none"/>
+			<typesafeEnumMember name="DAILY" value="daily"/>
+			<typesafeEnumMember name="WEEKLY" value="weekly"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='category']/xs:complexType/xs:sequence/xs:element[@name='code']/xs:simpleType">
+		<typesafeEnumClass name="PostCategoryCode">
+			<typesafeEnumMember name="DISCUSSION" value="discussion"/>
+			<typesafeEnumMember name="JOB" value="job"/>
+			<typesafeEnumMember name="PROMOTION" value="promotion"/>
+			<typesafeEnumMember name="LINKEDIN_JOB" value="linkedin-job"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:complexType[@name='GroupCategory']/xs:sequence/xs:element[@name='code']/xs:simpleType">
+		<typesafeEnumClass name="GroupCategoryCode">
+			<typesafeEnumMember name="ALUMNI" value="alumni"/>
+			<typesafeEnumMember name="CORPORATE" value="corporate"/>
+			<typesafeEnumMember name="CONFERENCE" value="conference"/>
+			<typesafeEnumMember name="NETWORK" value="network"/>
+			<typesafeEnumMember name="PHILANTHROPIC" value="philanthropic"/>
+			<typesafeEnumMember name="PROFESSIONAL" value="professional"/>
+			<typesafeEnumMember name="OTHER" value="other"/>
+		</typesafeEnumClass>
+	</bindings>
+	<bindings node="//xs:element[@name='post']/xs:complexType/xs:sequence/xs:element[@name='type']/xs:complexType/xs:sequence/xs:element[@name='code']/xs:simpleType">
+		<typesafeEnumClass name="PostTypeCode">
+			<typesafeEnumMember name="STANDARD" value="standard"/>
+			<typesafeEnumMember name="NEWS" value="news"/>
+		</typesafeEnumClass>
+	</bindings>
+
+	<bindings node="//xs:element[@name='updates']/xs:complexType/xs:sequence/xs:element[@ref='update']">
+		<property name="updateList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='recipients']/xs:complexType/xs:sequence/xs:element[@ref='recipient']">
+		<property name="recipientList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='network-stats']/xs:complexType/xs:sequence/xs:element[@ref='property']">
+		<property name="propertyList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='question-categories']/xs:complexType/xs:sequence/xs:element[@ref='question-category']">
+		<property name="questionCategoryList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='answers']/xs:complexType/xs:sequence/xs:element[@ref='answer']">
+		<property name="answerList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='update-comments']/xs:complexType/xs:sequence/xs:element[@ref='update-comment']">
+		<property name="updateCommentList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='people']/xs:complexType/xs:sequence/xs:element[@ref='person']">
+		<property name="personList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='positions']/xs:complexType/xs:sequence/xs:element[@ref='position']">
+		<property name="positionList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='three-current-positions']/xs:complexType/xs:sequence/xs:element[@ref='position']">
+		<property name="positionList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='three-past-positions']/xs:complexType/xs:sequence/xs:element[@ref='position']">
+		<property name="positionList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='educations']/xs:complexType/xs:sequence/xs:element[@ref='education']">
+		<property name="educationList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='member-groups']/xs:complexType/xs:sequence/xs:element[@ref='member-group']">
+		<property name="memberGroupList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='person-activities']/xs:complexType/xs:sequence/xs:element[@ref='activity']">
+		<property name="activityList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='recommendations-given']/xs:complexType/xs:sequence/xs:element[@ref='recommendation']">
+		<property name="recommendationList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='recommendations-received']/xs:complexType/xs:sequence/xs:element[@ref='recommendation']">
+		<property name="recommendationList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='connections']/xs:complexType/xs:sequence/xs:element[@ref='person']">
+		<property name="personList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='headers']/xs:complexType/xs:sequence/xs:element[@ref='http-header']">
+		<property name="httpHeaderList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='im-accounts']/xs:complexType/xs:sequence/xs:element[@ref='im-account']">
+		<property name="imAccountList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='twitter-accounts']/xs:complexType/xs:sequence/xs:element[@ref='twitter-account']">
+		<property name="twitterAccountList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='phone-numbers']/xs:complexType/xs:sequence/xs:element[@ref='phone-number']">
+		<property name="phoneNumberList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='member-url-resources']/xs:complexType/xs:sequence/xs:element[@ref='member-url']">
+		<property name="memberUrlList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='facets']/xs:complexType/xs:sequence/xs:element[@ref='facet']">
+		<property name="facetList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='buckets']/xs:complexType/xs:sequence/xs:element[@ref='bucket']">
+		<property name="bucketList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='likes']/xs:complexType/xs:sequence/xs:element[@ref='like']">
+		<property name="likeList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='certifications']/xs:complexType/xs:sequence/xs:element[@ref='certification']">
+		<property name="certificationList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='patents']/xs:complexType/xs:sequence/xs:element[@ref='patent']">
+		<property name="patentList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='publications']/xs:complexType/xs:sequence/xs:element[@ref='publication']">
+		<property name="publicationList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='skills']/xs:complexType/xs:sequence/xs:element[@ref='skill']">
+		<property name="skillList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='languages']/xs:complexType/xs:sequence/xs:element[@ref='language']">
+		<property name="languageList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='inventors']/xs:complexType/xs:sequence/xs:element[@ref='inventor']">
+		<property name="inventorList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='authors']/xs:complexType/xs:sequence/xs:element[@name='author']">
+		<property name="authorList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='related-connections']/xs:complexType/xs:sequence/xs:element[@ref='person']">
+		<property name="personList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='companies']/xs:complexType/xs:sequence/xs:element[@ref='company']">
+		<property name="companyList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='products']/xs:complexType/xs:sequence/xs:element[@ref='product']">
+		<property name="productList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='job-bookmarks']/xs:complexType/xs:sequence/xs:element[@ref='job-bookmark']">
+		<property name="jobBookmarkList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='jobs']/xs:complexType/xs:sequence/xs:element[@ref='job']">
+		<property name="jobList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='email-domains']/xs:complexType/xs:sequence/xs:element[@ref='email-domain']">
+		<property name="emailDomainList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='locations']/xs:complexType/xs:sequence/xs:element[@ref='location']">
+		<property name="locationList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='recommendations']/xs:complexType/xs:sequence/xs:element[@ref='recommendation']">
+		<property name="recommendationList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='job-functions']/xs:complexType/xs:sequence/xs:element[@ref='job-function']">
+		<property name="jobFunctionList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='industries']/xs:complexType/xs:sequence/xs:element[@ref='industry']">
+		<property name="industryList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='specialties']/xs:complexType/xs:sequence/xs:element[@ref='specialty']">
+		<property name="specialtyList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='features']/xs:complexType/xs:sequence/xs:element[@ref='feature']">
+		<property name="featureList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='sales-persons']/xs:complexType/xs:sequence/xs:element[@ref='person']">
+		<property name="personList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='posts']/xs:complexType/xs:sequence/xs:element[@ref='post']">
+		<property name="postList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='comments']/xs:complexType/xs:sequence/xs:element[@ref='comment']">
+		<property name="commentList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='available-actions']/xs:complexType/xs:sequence/xs:element[@ref='action']">
+		<property name="actionList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='group-memberships']/xs:complexType/xs:sequence/xs:element[@ref='group-membership']">
+		<property name="groupMembershipList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='groups']/xs:complexType/xs:sequence/xs:element[@ref='group']">
+		<property name="groupList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='historical-follow-statistics']/xs:complexType/xs:sequence/xs:element[@name='statistic']">
+		<property name="statisticList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='historical-status-update-statistics']/xs:complexType/xs:sequence/xs:element[@name='statistic']">
+		<property name="statisticList"/>
+	</bindings>
+	<bindings node="//xs:element[@name='historical-follow-statistics']/xs:complexType/xs:sequence/xs:element[@name='statistic']/xs:complexType">
+		<class name="HistoricalFollowStatistic"/>
+	</bindings>
+	<bindings node="//xs:element[@name='historical-status-update-statistics']/xs:complexType/xs:sequence/xs:element[@name='statistic']/xs:complexType">
+		<class name="HistoricalStatusUpdateStatistic"/>
+	</bindings>
+	<bindings node="//xs:element[@name='share-target-reach']/xs:complexType/xs:sequence/xs:element[@name='share-targets']/xs:complexType/xs:sequence/xs:element[@name='share-target']">
+		<property name="shareTargetList"/>
+	</bindings>
+</bindings>
\ No newline at end of file


[13/23] camel git commit: CAMEL-6568: Initial version of LinkedIn component

Posted by dh...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/SearchResourceIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/SearchResourceIntegrationTest.java b/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/SearchResourceIntegrationTest.java
new file mode 100644
index 0000000..d3c9e5f
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/test/java/org/apache/camel/component/linkedin/SearchResourceIntegrationTest.java
@@ -0,0 +1,161 @@
+/*
+ * Camel Api Route test generated by camel-component-util-maven-plugin
+ * Generated on: Wed Jul 09 19:57:11 PDT 2014
+ */
+package org.apache.camel.component.linkedin;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.camel.component.linkedin.internal.LinkedInApiCollection;
+import org.apache.camel.component.linkedin.internal.SearchResourceApiMethod;
+
+/**
+ * Test class for {@link org.apache.camel.component.linkedin.api.SearchResource} APIs.
+ */
+public class SearchResourceIntegrationTest extends AbstractLinkedInTestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SearchResourceIntegrationTest.class);
+    private static final String PATH_PREFIX = LinkedInApiCollection.getCollection().getApiName(SearchResourceApiMethod.class).getName();
+
+    @Test
+    public void testSearchCompanies() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", "");
+        // parameter type is String
+        headers.put("CamelLinkedIn.keywords", "linkedin");
+        // all fields are nullable, and fields defaults to ""
+/*
+        // parameter type is String
+        headers.put("CamelLinkedIn.hq_only", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.facet", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.facets", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.start", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.count", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.sort", null);
+*/
+
+        final org.apache.camel.component.linkedin.api.model.CompanySearch result = requestBodyAndHeaders("direct://SEARCHCOMPANIES", null, headers);
+
+        assertNotNull("searchCompanies result", result);
+        LOG.debug("searchCompanies: " + result);
+    }
+
+    @Ignore("Requires vetted API Access Program")
+    @Test
+    public void testSearchJobs() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", "");
+/*
+        // parameter type is String
+        headers.put("CamelLinkedIn.keywords", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.company_name", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.job_title", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.country_code", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.postal_code", null);
+        // parameter type is org.apache.camel.component.linkedin.api.model.Distance
+        headers.put("CamelLinkedIn.distance", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.facet", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.facets", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.start", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.count", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.sort", null);
+*/
+
+        final org.apache.camel.component.linkedin.api.model.JobSearch result = requestBodyAndHeaders("direct://SEARCHJOBS", null, headers);
+
+        assertNotNull("searchJobs result", result);
+        LOG.debug("searchJobs: " + result);
+    }
+
+    @Ignore("Requires vetted API Access Program")
+    @Test
+    public void testSearchPeople() throws Exception {
+        final Map<String, Object> headers = new HashMap<String, Object>();
+        // parameter type is String
+        headers.put("CamelLinkedIn.fields", "");
+/*
+        // parameter type is String
+        headers.put("CamelLinkedIn.keywords", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.first_name", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.last_name", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.company_name", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.current_company", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.title", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.current_title", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.school_name", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.current_school", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.country_code", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.postal_code", null);
+        // parameter type is org.apache.camel.component.linkedin.api.model.Distance
+        headers.put("CamelLinkedIn.distance", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.facet", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.facets", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.start", null);
+        // parameter type is Long
+        headers.put("CamelLinkedIn.count", null);
+        // parameter type is String
+        headers.put("CamelLinkedIn.sort", null);
+*/
+
+        final org.apache.camel.component.linkedin.api.model.PeopleSearch result = requestBodyAndHeaders("direct://SEARCHPEOPLE", null, headers);
+
+        assertNotNull("searchPeople result", result);
+        LOG.debug("searchPeople: " + result);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                // test route for searchCompanies
+                from("direct://SEARCHCOMPANIES")
+                  .to("linkedin://" + PATH_PREFIX + "/searchCompanies");
+
+                // test route for searchJobs
+                from("direct://SEARCHJOBS")
+                  .to("linkedin://" + PATH_PREFIX + "/searchJobs");
+
+                // test route for searchPeople
+                from("direct://SEARCHPEOPLE")
+                  .to("linkedin://" + PATH_PREFIX + "/searchPeople");
+
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/test/resources/log4j.properties b/components/camel-linkedin/camel-linkedin-component/src/test/resources/log4j.properties
new file mode 100644
index 0000000..fb1d365
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/test/resources/log4j.properties
@@ -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.
+#
+
+#
+# The logging properties used for testing.
+#
+log4j.rootLogger=INFO, file
+
+# uncomment the following line to turn on component debug messages
+#log4j.logger.org.apache.camel.component.linkedin=DEBUG
+
+# CONSOLE appender not used by default
+log4j.appender.out=org.apache.log4j.ConsoleAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+#log4j.appender.out.layout.ConversionPattern=[%30.30t] %-30.30c{1} %-5p %m%n
+log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+# File appender
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+log4j.appender.file.file=target/camel-linkedin-test.log

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/camel-linkedin-component/src/test/resources/test-options.properties
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/camel-linkedin-component/src/test/resources/test-options.properties b/components/camel-linkedin/camel-linkedin-component/src/test/resources/test-options.properties
new file mode 100644
index 0000000..4bb03f0
--- /dev/null
+++ b/components/camel-linkedin/camel-linkedin-component/src/test/resources/test-options.properties
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+# LinkedIn user name
+userName=
+# LinkedIn user password
+userPassword=
+# LinkedIn App clientId
+clientId=
+# LinkedIn App clientSecret
+clientSecret=
+# LinkedIn App required scopes
+scope=r_basicprofile,r_fullprofile,r_emailaddress,r_network,r_contactinfo,rw_nus,rw_company_admin,rw_groups,w_messages
+# LinkedIn App redirect URI
+redirectUri=

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/camel-linkedin/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-linkedin/pom.xml b/components/camel-linkedin/pom.xml
new file mode 100644
index 0000000..7398fb7
--- /dev/null
+++ b/components/camel-linkedin/pom.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<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>
+    <artifactId>components</artifactId>
+    <groupId>org.apache.camel</groupId>
+    <version>2.14-SNAPSHOT</version>
+  </parent>
+
+  <groupId>org.apache.camel.component.linkedin</groupId>
+  <artifactId>camel-linkedin-parent</artifactId>
+  <packaging>pom</packaging>
+  <version>2.14-SNAPSHOT</version>
+
+  <name>Camel LinkedIn Component Parent</name>
+  <description>Parent project for Camel {LinkedIn} Component</description>
+
+  <modules>
+    <module>camel-linkedin-component</module>
+    <module>camel-linkedin-api</module>
+  </modules>
+
+  <profiles>
+    <profile>
+      <id>linkedin-test</id>
+      <build>
+        <plugins>
+          <plugin>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <configuration>
+              <childDelegation>false</childDelegation>
+              <useFile>true</useFile>
+              <forkMode>once</forkMode>
+              <forkedProcessTimeoutInSeconds>300</forkedProcessTimeoutInSeconds>
+              <excludes>
+                <exclude>**/*XXXTest.java</exclude>
+              </excludes>
+              <includes>
+                <include>**/*Test.java</include>
+              </includes>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/b490a90c/components/pom.xml
----------------------------------------------------------------------
diff --git a/components/pom.xml b/components/pom.xml
index 0d6c971..fb2bfa9 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -128,6 +128,7 @@
     <module>camel-krati</module>
     <module>camel-ldap</module>
     <module>camel-leveldb</module>
+    <module>camel-linkedin</module>
     <module>camel-lucene</module>
     <module>camel-mail</module>
     <module>camel-mina</module>


[23/23] camel git commit: CAMEL-8575: Applied patch to fix Salesforce security login retries, with thanks to Dmitry Lysai

Posted by dh...@apache.org.
CAMEL-8575: Applied patch to fix Salesforce security login retries, with thanks to Dmitry Lysai


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

Branch: refs/heads/camel-2.15.x
Commit: 6f3daa8ecd5b1a9e531d934281fd42eb1fff227c
Parents: 5399860
Author: Dhiraj Bokde <dh...@yahoo.com>
Authored: Mon Apr 6 13:28:01 2015 -0700
Committer: Dhiraj Bokde <dh...@yahoo.com>
Committed: Mon Apr 6 13:32:25 2015 -0700

----------------------------------------------------------------------
 .../internal/client/AbstractClientBase.java     | 26 ++++++++---------
 .../salesforce/RestApiIntegrationTest.java      | 30 ++++++++++++++++++++
 2 files changed, 43 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/6f3daa8e/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
index a00d289..b0c7442 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
@@ -103,19 +103,6 @@ public abstract class AbstractClientBase implements SalesforceSession.Salesforce
 
     protected void doHttpRequest(final ContentExchange request, final ClientResponseCallback callback) {
 
-        // use SalesforceSecurityListener for security login retries
-        try {
-            final boolean isHttps = HttpSchemes.HTTPS.equals(String.valueOf(request.getScheme()));
-            request.setEventListener(new SalesforceSecurityListener(
-                    httpClient.getDestination(request.getAddress(), isHttps),
-                    request, session, accessToken));
-        } catch (IOException e) {
-            // propagate exception
-            callback.onResponse(null, new SalesforceException(
-                    String.format("Error registering security listener: %s", e.getMessage()),
-                    e));
-        }
-
         // use HttpEventListener for lifecycle events
         request.setEventListener(new HttpEventListenerWrapper(request.getEventListener(), true) {
 
@@ -169,6 +156,19 @@ public abstract class AbstractClientBase implements SalesforceSession.Salesforce
             }
         });
 
+        // use SalesforceSecurityListener for security login retries
+        try {
+            final boolean isHttps = HttpSchemes.HTTPS.equals(String.valueOf(request.getScheme()));
+            request.setEventListener(new SalesforceSecurityListener(
+                    httpClient.getDestination(request.getAddress(), isHttps),
+                    request, session, accessToken));
+        } catch (IOException e) {
+            // propagate exception
+            callback.onResponse(null, new SalesforceException(
+                    String.format("Error registering security listener: %s", e.getMessage()),
+                    e));
+        }
+
         // execute the request
         try {
             httpClient.send(request);

http://git-wip-us.apache.org/repos/asf/camel/blob/6f3daa8e/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
index 9627cf3..e87a21f 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
@@ -44,7 +44,14 @@ import org.apache.camel.component.salesforce.dto.generated.Document;
 import org.apache.camel.component.salesforce.dto.generated.Line_Item__c;
 import org.apache.camel.component.salesforce.dto.generated.Merchandise__c;
 import org.apache.camel.component.salesforce.dto.generated.QueryRecordsLine_Item__c;
+import org.apache.camel.util.jsse.SSLContextParameters;
+import org.eclipse.jetty.client.ContentExchange;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.client.RedirectListener;
+import org.eclipse.jetty.http.HttpMethods;
 import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -59,6 +66,29 @@ public class RestApiIntegrationTest extends AbstractSalesforceTestBase {
     private static String testId;
 
     @Test
+    public void testRetry() throws Exception {
+        SalesforceComponent sf = context().getComponent("salesforce", SalesforceComponent.class);
+        String accessToken = sf.getSession().getAccessToken();
+
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        sslContextFactory.setSslContext(new SSLContextParameters().createSSLContext());
+        HttpClient httpClient = new HttpClient(sslContextFactory);
+        httpClient.setConnectTimeout(60000);
+        httpClient.setTimeout(60000);
+        httpClient.registerListener(RedirectListener.class.getName());
+        httpClient.start();
+
+        ContentExchange logoutGet = new ContentExchange(true);
+        logoutGet.setURL(sf.getLoginConfig().getLoginUrl() + "/services/oauth2/revoke?token=" + accessToken);
+        logoutGet.setMethod(HttpMethods.GET);
+        httpClient.send(logoutGet);
+        assertEquals(HttpExchange.STATUS_COMPLETED, logoutGet.waitForDone());
+        assertEquals(HttpStatus.OK_200, logoutGet.getResponseStatus());
+
+        doTestGetGlobalObjects("");
+    }
+
+    @Test
     public void testGetVersions() throws Exception {
         doTestGetVersions("");
         doTestGetVersions("Xml");