This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-spring-boot-examples.git


The following commit(s) were added to refs/heads/main by this push:
     new 53eba73  CAMEL-21910: Add Salesforce example (#155)
53eba73 is described below

commit 53eba73afcfbeb813a306dcdc205b3b294bad2c7
Author: Stanislav Deviatov <devya...@gmail.com>
AuthorDate: Fri Mar 28 20:15:20 2025 +0100

    CAMEL-21910: Add Salesforce example (#155)
    
    * Initial version
    
    * Add Salesforce example with REST API and CDC monitoring
    
    * CAMEL-21910: Add route IDs for Salesforce contact queries and updates
---
 README.adoc                                        |  13 ++-
 pom.xml                                            |   1 +
 salesforce/.gitignore                              |   1 +
 salesforce/README.adoc                             | 101 ++++++++++++++++++
 salesforce/pom.xml                                 | 115 ++++++++++++++++++++
 .../camel/example/salesforce/SalesforceApp.java    |  29 +++++
 .../camel/example/salesforce/SalesforceRouter.java | 117 +++++++++++++++++++++
 .../main/resources/application.properties.example  |   8 ++
 8 files changed, 380 insertions(+), 5 deletions(-)

diff --git a/README.adoc b/README.adoc
index d42734a..8c7faa9 100644
--- a/README.adoc
+++ b/README.adoc
@@ -27,7 +27,7 @@ readme's instructions.
 === Examples
 
 // examples: START
-Number of Examples: 61 (0 deprecated)
+Number of Examples: 62 (0 deprecated)
 
 [width="100%",cols="4,2,4",options="header"]
 |===
@@ -98,7 +98,7 @@ Number of Examples: 61 (0 deprecated)
 | link:fhir/readme.adoc[Fhir] (fhir) | Health Care | An example showing how to 
work with Camel, FHIR and Spring Boot
 
 | link:fhir-auth-tx/readme.adoc[Fhir Auth Tx] (fhir-auth-tx) | Health Care | 
An example showing how to work with Camel, FHIR Authorization, FHIR Transaction 
and Spring Boot
-
+    
 
 | link:validator/readme.adoc[Validator Spring Boot] (validator) | Input/Output 
Type Contract | An example showing how to work with declarative validation and 
Spring Boot
 
@@ -114,7 +114,7 @@ Number of Examples: 61 (0 deprecated)
 | link:metrics/README.adoc[Metrics] (metrics) | Management and Monitoring | An 
example showing how to work with Camel and Spring Boot and report metrics to 
Graphite
 
 | link:observation/README.adoc[Micrometer Observation] (observation) | 
Management and Monitoring | An example showing how to trace incoming and 
outgoing messages from Camel with Micrometer Observation
-
+    
 
 | link:opentelemetry/README.adoc[OpenTelemetry] (opentelemetry) | Management 
and Monitoring | An example showing how to use Camel with OpenTelemetry
 
@@ -128,7 +128,7 @@ Number of Examples: 61 (0 deprecated)
 
 | link:kafka-avro/README.adoc[Kafka Avro] (kafka-avro) | Messaging | An 
example for Kafka avro
 
-| link:kafka-oauth/README.adoc[Kafka OAuth] (kafka-oauth) | Messaging | An 
example for Kafka authentication using OAuth
+| link:kafka-oauth/README.adoc[Kafka Oauth] (kafka-oauth) | Messaging | An 
example of Kafka authentication using OAuth.
 
 | link:kafka-offsetrepository/README.adoc[Kafka Offsetrepository] 
(kafka-offsetrepository) | Messaging | An example for Kafka offsetrepository
 
@@ -141,7 +141,7 @@ Number of Examples: 61 (0 deprecated)
 | link:widget-gadget/README.adoc[Widget Gadget] (widget-gadget) | Messaging | 
The widget and gadget example from EIP book, running on Spring Boot
 
 | link:reactive-streams/readme.adoc[Reactive Streams] (reactive-streams) | 
Reactive | An example that shows how Camel can exchange data using reactive 
streams with Spring Boot reactor
-
+    
 
 | link:http-ssl/README.adoc[Http Ssl] (http-ssl) | Rest | An example showing 
the Camel HTTP component with Spring Boot and SSL
 
@@ -160,6 +160,9 @@ Number of Examples: 61 (0 deprecated)
 | link:jira/README.adoc[Jira] (jira) | SaaS | An example that uses Jira Camel 
API
 
 | link:twitter-salesforce/README.adoc[Twitter Salesforce] (twitter-salesforce) 
| SaaS | Twitter mentions is created as contacts in Salesforce
+
+| link:salesforce/README.adoc[Salesforce] (salesforce) | SaaS | How to work 
with Salesforce contacts using REST endpoints and Streaming API
+
 |===
 // examples: END
 
diff --git a/pom.xml b/pom.xml
index 530dd40..cacb117 100644
--- a/pom.xml
+++ b/pom.xml
@@ -79,6 +79,7 @@
                <module>routetemplate-xml</module>
                <module>route-reload</module>
                <module>routes-configuration</module>
+               <module>salesforce</module>
                <module>saga</module>
                <module>soap-cxf</module>
                <module>supervising-route-controller</module>
diff --git a/salesforce/.gitignore b/salesforce/.gitignore
new file mode 100644
index 0000000..e75f8ad
--- /dev/null
+++ b/salesforce/.gitignore
@@ -0,0 +1 @@
+src/main/resources/application.properties
\ No newline at end of file
diff --git a/salesforce/README.adoc b/salesforce/README.adoc
new file mode 100644
index 0000000..1181cd9
--- /dev/null
+++ b/salesforce/README.adoc
@@ -0,0 +1,101 @@
+= Camel Salesforce Example
+
+The example provides REST API endpoints for managing Salesforce contacts (list 
all, get by ID, update) and implements real-time monitoring of Contact changes 
through Change Data Capture (CDC) events.
+
+== Features
+
+* REST API endpoints to fetch all Salesforce contacts, get contact by ID and 
update a contact by ID
+* Listens continuously for Change Data Capture events (CDC)
+* Salesforce authentication using client credentials flow
+
+== Prerequisites
+
+* Java 17 or higher
+* Maven 3.6+
+* Salesforce developer account
+* Salesforce Connected App credentials
+
+== Configuration
+
+1. Create a Connected App in your Salesforce org:
+   * Go to Setup > Apps > App Manager > New Connected App
+   * Enable OAuth Settings
+   * Set Callback URL (can be http://localhost:8080)
+   * Add 'Perform requests at any time' to Selected OAuth Scopes
+   * Save and wait for activation
+
+2. Enable CDC events for Contact object:
+   * Go to Setup > Integrations > Change Data Capture
+   * Add `Contact (Contact)` to Selected Entities
+   * Save
+
+3. Copy `src/main/resources/application.properties.example` to 
`src/main/resources/application.properties`
+
+4. Update the properties with your Connected App credentials:
+[source,properties]
+----
+camel.component.salesforce.client-id=<YOUR_CLIENT_ID>         # Consumer Key 
from Connected App
+camel.component.salesforce.client-secret=<YOUR_CLIENT_SECRET> # Consumer 
Secret from Connected App
+camel.component.salesforce.instance-url=<YOUR_DOMAIN>         # e.g. 
https://your-org.my.salesforce.com
+camel.component.salesforce.login-url=<YOUR_DOMAIN>            # Same as 
instance-url
+----
+
+== Building
+
+[source,bash]
+----
+mvn clean install
+----
+
+== Running
+
+[source,bash]
+----
+mvn spring-boot:run
+----
+
+The application will start on port 8080.
+
+== Testing
+
+=== REST Endpoints
+
+1. Fetch all contacts:
+[source,bash]
+----
+curl -X GET http://localhost:8080/camel/contacts | jq
+----
+
+2. Fetch a specific contact:
+[source,bash]
+----
+curl -X GET http://localhost:8080/camel/contacts/003XXXXXXXXXXXXXXX | jq
+----
+Replace `003XXXXXXXXXXXXXXX` with an actual Salesforce Contact ID.
+
+3. Update a specific contact:
+[source,bash]
+----
+curl --location --request PUT 
'http://localhost:8080/camel/contacts/003XXXXXXXXXXXXXXX' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+    "LastName": "Smith",
+    "FirstName": "John",
+    "Salutation": "Mr.",
+    "Email": "jsm...@gmail.com",
+    "Description": "Test description"
+}'
+----
+Replace `003XXXXXXXXXXXXXXX` with an actual Salesforce Contact ID.
+
+== Monitor CDC events
+Listens continuously for Contact Change Events (CDC):
+
+   * Make changes to contacts in Salesforce or update a specific contact
+   * Watch the application logs for real-time change events
+
+== Project Structure
+
+* `SalesforceRouter.java`: Contains Camel route definitions
+* `SalesforceApp.java`: Spring Boot application entry point
+* `application.properties`: Configuration properties
diff --git a/salesforce/pom.xml b/salesforce/pom.xml
new file mode 100644
index 0000000..e3f1d35
--- /dev/null
+++ b/salesforce/pom.xml
@@ -0,0 +1,115 @@
+<?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.springboot.example</groupId>
+        <artifactId>examples</artifactId>
+        <version>4.11.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-example-spring-boot-salesforce</artifactId>
+    <packaging>jar</packaging>
+    <name>Camel SB Examples :: Salesforce</name>
+    <description>How to work with Salesforce contacts using REST endpoints and 
Streaming API</description>
+
+       <properties>
+        <category>SaaS</category>
+
+               <camelSalesforce.clientId></camelSalesforce.clientId>
+               <camelSalesforce.clientSecret></camelSalesforce.clientSecret>
+               
<camelSalesforce.sslContextParameters.secureSocketProtocol>TLSv1.3</camelSalesforce.sslContextParameters.secureSocketProtocol>
+               
<camelSalesforce.loginUrl>https://login.salesforce.com</camelSalesforce.loginUrl>
+       </properties>
+
+    <dependencyManagement>
+        <dependencies>
+                   <dependency>
+                <groupId>org.apache.camel.springboot</groupId>
+                <artifactId>camel-spring-boot-bom</artifactId>
+                <version>${project.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring-boot-version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+
+        <!-- Camel -->
+        <dependency>
+            <groupId>org.apache.camel.springboot</groupId>
+            <artifactId>camel-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.springboot</groupId>
+            <artifactId>camel-salesforce-starter</artifactId>
+        </dependency>
+                       <dependency>
+                       <groupId>org.apache.camel.springboot</groupId>
+                       <artifactId>camel-rest-starter</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.camel.springboot</groupId>
+                       <artifactId>camel-servlet-starter</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.camel.springboot</groupId>
+                       <artifactId>camel-jackson-starter</artifactId>
+               </dependency>
+
+        <!-- Spring Boot -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+
+        <!-- testing -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.springframework.boot</groupId>
+                               
<artifactId>spring-boot-maven-plugin</artifactId>
+                       </plugin>
+               </plugins>
+       </build>
+
+
+</project>
diff --git 
a/salesforce/src/main/java/org/apache/camel/example/salesforce/SalesforceApp.java
 
b/salesforce/src/main/java/org/apache/camel/example/salesforce/SalesforceApp.java
new file mode 100644
index 0000000..3fd0342
--- /dev/null
+++ 
b/salesforce/src/main/java/org/apache/camel/example/salesforce/SalesforceApp.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.example.salesforce;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SalesforceApp {
+
+       public static void main(String[] args) {
+               SpringApplication.run(SalesforceApp.class, args);
+       }
+
+}
diff --git 
a/salesforce/src/main/java/org/apache/camel/example/salesforce/SalesforceRouter.java
 
b/salesforce/src/main/java/org/apache/camel/example/salesforce/SalesforceRouter.java
new file mode 100644
index 0000000..02e96ee
--- /dev/null
+++ 
b/salesforce/src/main/java/org/apache/camel/example/salesforce/SalesforceRouter.java
@@ -0,0 +1,117 @@
+/*
+ * 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.example.salesforce;
+
+import org.apache.camel.LoggingLevel;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.model.dataformat.JsonLibrary;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.springframework.stereotype.Component;
+
+/**
+ * A Camel router class that integrates with Salesforce to manage contact 
information.
+ * This router implements five main routes:
+ * 1. REST GET endpoint to fetch all contacts
+ * 2. REST GET endpoint to retrieve a specific contact by ID
+ * 3. REST PUT endpoint to update a specific contact by ID
+ * 4. Salesforce CDC event listener for Contact changes
+ *
+ * Key features:
+ * - REST API: Servlet-based REST endpoints with JSON binding
+ * - CRUD Operations: Support for reading and updating Salesforce contacts
+ * - Real-time Updates: CDC (Change Data Capture) event monitoring
+ *
+ * Endpoints:
+ * - GET /contacts: Retrieves all contacts
+ * - GET /contacts/{id}: Retrieves a specific contact
+ * - PUT /contacts/{id}: Updates a specific contact
+ *
+ * Technical details:
+ * - Uses Spring @Component for dependency injection
+ * - Implements RestBindingMode.json for automatic JSON serialization
+ * - Leverages direct endpoints for synchronous route execution
+ * - Integrates with Salesforce using SOQL queries and CDC events
+ * - Employs Jackson for JSON data transformation
+ *
+ * @see org.apache.camel.builder.RouteBuilder
+ * @see org.springframework.stereotype.Component
+ */
+@Component
+public class SalesforceRouter extends RouteBuilder {
+
+    @Override
+    public void configure() throws Exception {
+        // Configure REST endpoint using servlet component and JSON binding
+        restConfiguration()
+            .component("servlet")        // Use servlet as the HTTP server
+            .bindingMode(RestBindingMode.json);      // Enable automatic JSON 
data binding
+
+        // Define REST endpoint that responds to GET requests
+        rest("/contacts")
+            .get()
+                .id("Rest-based route: all contacts")       // Create GET 
endpoint at /contacts path
+                .to("direct:getContacts?synchronous=true") // Route requests 
to direct:getContacts endpoint
+            .get("/{id}")
+                .id("Rest-based route: contact by id")          // Create GET 
endpoint with path parameter
+                .to("direct:getContactById?synchronous=true") // Route 
requests to direct:getContactById endpoint
+            .put("/{id}")
+                .id("Rest-based route: update contact by id")  // Create PUT 
endpoint with path parameter
+                .to("direct:updateContactById?synchronous=true"); // Route 
requests to direct:updateContactById endpoint
+        
+        // Define route that queries Salesforce contacts
+        from("direct:getContacts")
+            .id("getContacts")
+            // Execute SOQL query to get Contact objects from Salesforce
+            .to("salesforce:queryAll?sObjectQuery=SELECT Id, Name, Email FROM 
Contact")
+            // Uncommented debug logging line
+            // .to("log:debug?showAll=true&multiline=true")
+            // Convert Salesforce response to JSON using Jackson library
+            .unmarshal().json(JsonLibrary.Jackson);
+
+        // Define route that queries Salesforce contacts
+        from("direct:getContactById")
+            .id("getContactById")
+            // Execute SOQL query to get Contact objects from Salesforce
+            
.toD("salesforce:getSObject?sObjectName=Contact&sObjectId=${header.id}")
+            // Uncommented debug logging line
+            // .to("log:debug?showAll=true&multiline=true");
+            // Convert Salesforce response to JSON using Jackson library
+            .unmarshal().json(JsonLibrary.Jackson);
+        
+        // Define route that updates a Salesforce contact by ID
+        from("direct:updateContactById")
+            .id("updateContactById")
+            // Convert the input body to JSON format using Jackson library
+            .marshal().json(JsonLibrary.Jackson)
+            // Convert the JSON to String format for Salesforce update
+            .convertBodyTo(String.class)
+            // Uncommented debug logging line for troubleshooting
+            // .to("log:debug?showAll=true&multiline=true")
+            // Update the Contact object in Salesforce using the ID from the 
header
+            
.toD("salesforce:updateSObject?sObjectName=Contact&sObjectId=${header.id}");
+
+        // Define route that listens for Salesforce CDC events for Contact 
objects
+        from("salesforce:subscribe:data/ContactChangeEvent")
+            .id("Listener Salesforce CDC events") // Set route ID for 
monitoring
+            // Uncommented debug logging line
+            // .to("log:debug?showAll=true&multiline=true");
+            // Convert Salesforce response to JSON using Jackson library
+            .unmarshal().json(JsonLibrary.Jackson)
+            // Log the CDC event at INFO level
+            .log(LoggingLevel.INFO, "A new event: ${body}"); 
+    }
+}
diff --git a/salesforce/src/main/resources/application.properties.example 
b/salesforce/src/main/resources/application.properties.example
new file mode 100644
index 0000000..9c4492d
--- /dev/null
+++ b/salesforce/src/main/resources/application.properties.example
@@ -0,0 +1,8 @@
+spring.application.name=Salesforce Example
+camel.component.salesforce.config.raw-payload=true
+camel.component.salesforce.authentication-type=CLIENT_CREDENTIALS
+camel.component.salesforce.client-id=<YOUR_CLIENT_ID>
+camel.component.salesforce.client-secret=<YOUR_CLIENT_SECRET>
+camel.component.salesforce.instance-url=<YOUR_DOMAIN>
+camel.component.salesforce.login-url=<YOUR_DOMAIN>
+

Reply via email to