Archive

Posts Tagged ‘Spring’

Salesforce Canvas and Spring Boot App.

July 24, 2020 Leave a comment

Salesforce Lightning provides 2 ways to embed an external application in Salesforce. One could use a Canvas App, or, embed an iFrame in the Lightning Component. When using Canvas, there are a couple of ways the users could be authenticated in order to use the sdk (admin approved and self authorized users). The documentation is interleaved and did not provide a clear path of implementation. In this blog here, I have tried to cover one way to use Spring Boot and use a signed request from Canvas for the authentication.

The blog here creates a simple Spring Boot application with ssl enabled and Thymeleaf as the template. The focus will be on getting this application in the Canvas app and working our way through the signed request authentication (Thymeleaf could be replaced by other solutions. Similarly, Spring boot could be replaced by other frameworks if desired)

Here are the steps we will take to set this up.

  1. Create a Canvas App in Salesforce
  2. Create a basic Spring boot app sends a basic template back. (This will mimic a form but will not have the form wired to the application)
  3. Adding the application to the Canvas on a Lightning Component and page
  4. Refreshing a signed request.
  5. Decoding and verifying a signed request.
  6. Looking at the Canvas Request object
  7. Creating an event from the Application
  8. Consuming the event on the Lightning Component
  1. Creating the Canvas App in Salesforce
    Go to Setup | Apps | App Manager in Salesforce and click on the “New Connected App” button on the top right of the page.
    In the “New Connected App” page fill the following
    Connected App Name: My Spring Boot Canvas App
    API Name : (Will be filled automatically) My_Spring_Boot_Canvas_App
    Contact Email: Your-email-here
    Click on “Enable OAuth Settings”, add the callback URL as http://localhost:8080 and provide “Full Access (full)” in the “Available OAuth Scopes” (Note: In the production environment, you might want to restrict the privileges here)
    Skip to “Canvas App Settings” and check the checkbox “Canvas”
    Fill the following fields that show up in the “Canvas App Settings” section
    Canvas App Url: http://localhost:8080
    Access Method: Signed Request(POST)
    Locations: “Lightning Component” (We will put the Canvas app in the Lightning Component for now)

Once the App is created, locate your App in the App Manager and select “Manage” on the App. This will take you to a screen where you can provide your user permissions to access this App. In this page, go down to “Profiles” section, click on “Manage Profiles” and add your users Profile to the list. (Note: Permission Sets could be used here as an alternative)

  1. Creating a Spring Starter Project with Thymeleaf.
    In my example I use the Spring Starter from Spring STS IDE to create a base project for Spring Boot. The same could be done using Spring Initializr (https://start.spring.io/)
    We will create a Controller class as follows. This will have a request with method type as post and will accept a request parameter. This request parameter will have the signed request from Salesforce when the Canvas App loads.
package com.wordpress.codesilo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class HomeController {

	@RequestMapping(value = "/", method = RequestMethod.POST)
	public String index(@RequestBody String signedRequest) {
		System.out.println(signedRequest);
		return "index";
	}
	
}

For now, we will send a simple index page back – using thymeleaf template. For this the index.html will be in the “templates” folder in the “resources” of the project. Here is what our index.html page looks like. We will change this later.

<html>
<body>
	<h1>Main Index Page</h1>
	<p> Canvas Page Content</p>
	
	<input type="text"/>
	<button id="ctxlink" >Some button</button>
</body>
</html>

At this point if we start the server and call the following endpoint http://localhost:8080/ from the browser, we should get a method not supported error page. (405 status). But if we use Postman to call the same endpoint but as a “POST” request with some dummy body payload, we should get back the index.html content in the response.

  1. Adding the application to the Canvas on a Lightning Component and page
    Create a Lightning Component with the name “SpringBootCanvasApp” and add this on the cmp file.
<aura:component implements="flexipage:availableForAllPageTypes,flexipage:availableForRecordHome">
	<lightning:card>
    <force:canvasApp developerName="My_Spring_Boot_Canvas_App " maxHeight="200" maxWidth="200"/>
        </lightning:card>
</aura:component>

This creates the Lightning Component will we will place in a Lightning page next. This component contains the CanvasApp (My_Spring_Boot_Canvas_App) that points to the Spring Boot app we created earlier.

Go to Setup | Lightning App Builder and “Create a new Lightning Page”
Select “App Page” and give the label in the next screen as “My_Spring_Boot_Canvas_App”
Select “One region” in the next step and click “Finish”
This will take us to the screen where we can select out previously created Lightning Component “SpringBootCanvasApp”. Drop this app on the page and “Activate” the page after “Save”

Now add this Lighning page on the Navigation on one of your Apps in Salesforce. When we go to this page “My_Spring_Boot_Canvas_App” , we should be able to see the Spring boot application load within the Lightning Component in that page. (Make sure that your Spring Boot server is still running and not shutdown). On the Spring boot server, you should be able to see the signed_request logged on the console.

  1. Canvas SDK and Refreshing a signed request.
    Canvas provides a framework (Canvas SDK) that can be used to perform various operations on Salesforce. In our next step we will see how we can access the sdk and then use it to get the signed request within the UI (javascript) part of the application. We will, for now, provide inline javascript within our Thymeleaf teamplate. These could be replaced with your choice of frameworks/libraries/templates. The basics remain the same.

Canvas provides a framework (Canvas SDK) that can be used to perform various operations on Salesforce. In our next step we will see how we can access the sdk and then use it to get the signed request within the UI (javascript) part of the application. We will, for now, provide inline javascript within our Thymeleaf teamplate. These could be replaced with your choice of frameworks/libraries/templates. The basics remain the same.

Here is the final version of what our index.html template looks like now. We have done the following .. on the load of the page in the browser, we will add an onclick event on the button. The click of the button, calls the refreshSignedRequest on the Canvas SDK (this is the current way to get the signed request within the UI). On getting a successful response, it logs the signedRequest on the console else it logs the error status. Note: Replace the “your-salesforce-instance-name-here” with the instance name of your Salesforce and correct the version number as necessary.

<html>
<head>
	<script type="text/javascript" src="<your-salesforce-instance-name-here>/canvas/sdk/js/48.0/canvas-all.js"></script>
	<script type="text/javascript">
	window.onload = (event) => {
		var ctxlink = Sfdc.canvas.byId("ctxlink");
		ctxlink.onclick = function(){
			Sfdc.canvas.client.refreshSignedRequest(function(data) {
				if(data.status==200){
					var signedRequest = data.payload.response;
					console.log(signedRequest);
				}
				else{
					console.log('Status received != 200. Status is ' + data.status);
				}
			});
		}
	};
	
	</script>
	
</head>
<body>
	<h1>Main Index Page</h1>
	<p> Canvas Page Content</p>
	
	<input type="text"/>
	<button id="ctxlink" >Some button</button>
</body>
</html>
  1. Decoding and verifying a signed request.
    So, what does the signed request of Canvas consist of ? The details of what the signed request is can be found at the end of this documentation here (https://developer.salesforce.com/docs/atlas.en-us.platform_connect.meta/platform_connect/canvas_app_signed_req_authentication.htm). Verifying and decoding of the signed request can be done in this way : https://developer.salesforce.com/docs/atlas.en-us.platform_connect.meta/platform_connect/canvas_app_unsigning_code_example.htm

We will create a decoder class Decoder.class with the following code ..

package com.wordpress.codesilo.controller;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.springframework.stereotype.Component;

@Component
public class Decoder {

	public void decodeSignedRequest(String signedRequest) {
		try {
			String signedRequestVal = signedRequest.split("signed_request=")[1];
			
			String[] signedRequestArray = signedRequestVal.split("[.]");
			String clientSecret = "your-client-secret-from-canvas-connected-app-here";
			String encodedSignature = signedRequestArray[0];
			String endcodedEnvelope = signedRequestArray[1];

			Mac sha256HMAC = Mac.getInstance("HMACSHA256");
			SecretKey hmacKey = new SecretKeySpec(clientSecret.getBytes(), "HMACSHA256");
			sha256HMAC.init(hmacKey);

			byte[] digest = sha256HMAC.doFinal(endcodedEnvelope.getBytes("UTF-8"));
			byte[] decode_sig = new Base64(true).decode(encodedSignature);

			if (Arrays.equals(digest, decode_sig)) {
				System.out.println("Valid signed request found");
			} else {
				System.out.println("Invalid signed request found");
			}

			// The following is the CanvasRequest object generated from Salesforce
			String jsonEnvelope = new String(new Base64(true).decode(endcodedEnvelope));
			System.out.println(jsonEnvelope);

		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

Replace the client secret from the secret from your instance of Salesforce above.

We will then call this decoder.decodeSignedRequest method from our main controller class. We will change the controller class a bit to make sure the request body is URL decoded. This is what the class looks like..

@Controller
public class HomeController {

	@Autowired
	private Decoder decoder;
	
	@RequestMapping(value = "/", method = RequestMethod.POST)
	public String index(@RequestBody String signedRequest) {
		try {
			String signedRequestDecoded = URLDecoder.decode(signedRequest, StandardCharsets.UTF_8.name());
			System.out.println(signedRequestDecoded);
			decoder.decodeSignedRequest(signedRequestDecoded);
		}
		catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return "index";
	}
	
}

Note: The code shown does not cover areas like error handling or other best practices. That is left for the reader to add.

  1. Looking at the Canvas Request object
    In the Decoder class above, we log a jsonEnvelope string. This is the String version of the CanvasRequest object. (https://developer.salesforce.com/docs/atlas.en-us.platform_connect.meta/platform_connect/canvas_request_object.htm). Something like Jackson can be used to parse this into an Object.
  1. Creating an event from the Application
    Now we will take a look at a simple case of rasing an event from the Spring boot application and consuming that on the Lightning component allowing a client – client communication between the Canvas App and the parent (the Lightning component).
    We will change the index.html file to parse the signedRequest to an Object, get a “client” from it and then use the “publish” method on the sdk to publish a message. Here is what the final “onclick” method will look like.
ctxlink.onclick = function(){
			Sfdc.canvas.client.refreshSignedRequest(function(data) {
				if(data.status==200){
					var signedRequestResponse = data.payload.response;
					console.log(signedRequestResponse);
					
					var signedReqObj = JSON.parse(Sfdc.canvas.decode(signedRequestResponse.split('.')[1]));
		    	    var client = signedReqObj.client;

					Sfdc.canvas.client.publish(
		    	            client,
		    	            {name : "mynamespace.statusChanged", payload : {status : 'Message Sent'}});
					
				}
				else{
					console.log('Status received != 200. Status is ' + data.status);
				}
			});
		};
  1. Consuming the event on the Lightning Component
    Now on the Lightning Component on Salesforce we will make a couple of changes to listen to the Message. We will first add onCanvasAppLoad attribute to the component canvasApp. The component will now look as follows:
<aura:component implements="flexipage:availableForAllPageTypes,flexipage:availableForRecordHome">
	<lightning:card>
    <force:canvasApp developerName="My_Spring_Boot_Canvas_App" maxHeight="200" maxWidth="200" onCanvasAppLoad="{!c.onCanvasLoad}"/>
        </lightning:card>
</aura:component>

Now, we will add a controller and add the following code to the controller.

({
	onCanvasLoad : function(component, event, helper) {
		console.log('Canvas Loaded');
        window.addEventListener('message', function (event) {
            var data = JSON.parse(event.data);
            if (data.targetModule === 'Canvas' && 
                data.body && 
                data.body.event && 
                data.body.event.name === 'mynamespace.statusChanged')
            console.log('payload from canvas app', data.body.event.payload);
        }, false);
	}
})

Now, when we go to the Canvas App and click on the button, the console should log the messages from the Lightning App.

Update: Posting messages using iFrame instead of Canvas can be found in this blog here: (https://codesilo.wordpress.com/2020/07/24/salesforce-consuming-messages-on-iframe-from-spring-boot-app/)

References:

https://salesforce.stackexchange.com/questions/131245/how-to-fire-an-event-from-a-canvas-app-to-a-lightning-component

https://salesforce.stackexchange.com/questions/106538/canvas-app-signedrequest-is-null-on-postback

https://salesforce.stackexchange.com/questions/76869/canvas-signed-request-sr-in-visualforce

Swagger 2 /Open API Specification on Spring Boot

January 24, 2018 Leave a comment

Swagger 2 ,or, Open API Specification is a definition used for REST APIs. (https://swagger.io/specification/). We will in this blog see how to implement the Open API Specification on a Spring Boot application. The Open API spec allows us not only to provide human/machine readable mapping but allow us to use tools on it for creating other implementations (stubs for the services for example)

Here are some reasons how this can be helpful
1. Guiding principles for the API
2. Allows us to create the API from top-down or bottom-up approach
3. Can be easily understood by developers and non-developers
4. Machine readable as well – can be used for tooling and automation

In addition to above Google Cloud Platform Endpoints requires that the API implement this spec. We will see Endpoints in the next blog.

Before we get to the specifics of implementing the Open API spec on our application, we will create a simple Spring Boot Application (See the “Creating the Spring Boot Applicaton” section in this blog https://codesilo.wordpress.com/2017/12/26/spring-boot-rest-api-integration-with-salesforce/ )

There are various libraries that implement the Open API specification. We will use SpringFox (http://springfox.github.io/springfox/). We will add the following dependencies on the pom.xml file

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.6.1</version>
    <scope>compile</scope>
</dependency>

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.7.0</version>
    <scope>compile</scope>
</dependency>

Next we add the config class for Open API in the main package.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class OpenAPIConfig {

    @Bean
    public Docket productApi(){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select().apis(RequestHandlerSelectors.basePackage("com.wordpress.codesilo"))
                .paths(PathSelectors.ant("/root/*"))
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("My Open API Implementation")
                .description("Application for Open API implementation")
                .version("2.0")
                .build();
    }
}

The package name and the PathSelectors can vary depending on the project. Also, the other values are configurable and will display on Swagger UI page.

Next we will implement a simple controller class in our Spring Boot application. Our controller class has a request mapping for /root and returns back a simple message.

package com.wordpress.codesilo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MainController {

	@RequestMapping(value ="/root", response = MainMessage.class)
	public MainMessage getMessage(){
		return new MainMessage("This is the root controller !!");
	}

}

The MainMessage is a simple POJO with a greeting attribute of type String.

We now will annotate the controllers and methods. Here is an example of annotating the class

@Api(tags={"Root Controller"}, value="Open API for testing", consumes="null")

Annotation of the method can be done in the following way

@ApiOperation(value = "Returns a message", response = MainMessage.class)
@ApiResponses(value = {
            @ApiResponse(code = 200, message = "Greeting is successfully sent"),
            @ApiResponse(code = 401, message = "You are not authorized to view the resource"),
            @ApiResponse(code = 403, message = "Accessing the resource you were trying to reach is forbidden"),
            @ApiResponse(code = 404, message = "The resource you were trying to reach is not found")
            }
    )

Annotations are also added on the model class. After the annotations, the classes look as shown below.

package com.wordpress.codesilo.model;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

@ApiModel(value="Main Response", description="Sample model")
public class MainMessage {

	@ApiModelProperty(value = "Greeting/Message", required=true)
	private String greeting;

	public MainMessage(){
	}

	public MainMessage(String greeting){
		this.greeting = greeting;
	}
	public String getGreeting() {
		return greeting;
	}

	public void setGreeting(String greeting) {
		this.greeting = greeting;
	}
}
package com.wordpress.codesilo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.wordpress.codesilo.model.MainMessage;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;

@RestController
@RequestMapping("/root")
@Api(tags={"Root Controller"}, value="Open API for testing", consumes="null")
public class MainController {

	@ApiOperation(value = "Returns a message", response = MainMessage.class)
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "Greeting is successfully sent"),
            @ApiResponse(code = 401, message = "You are not authorized to view the resource"),
            @ApiResponse(code = 403, message = "Accessing the resource you were trying to reach is forbidden"),
            @ApiResponse(code = 404, message = "The resource you were trying to reach is not found")
            }
    )
	@RequestMapping(value="/",method = RequestMethod.GET)
	public MainMessage getMessage(){
		return new MainMessage("This is the root controller !!");
	}
}

The last step is to add the @EnableSwagger2 annotation on the Application class.
Now, to view the Swagger UI go to the following url http://localhost:8080/swagger-ui.html#/ (assuming it deployed on your localhost), and to get the docs go to the url http://localhost:8080/v2/api-docs

Note: If you miss this annotation @EnableSwagger2 you get the following error..

Screen Shot 2018-01-23 at 6.26.20 PM

Creating a Spring Boot application on Google App Engine Standard

January 23, 2018 Leave a comment

In our last blog we saw how to create a simple application and deploy in Google App Engine Flex. In this write up we will see how to do the same but in the Google App Engine standard environment.
Last year the Standard App Engine was lagging behind specifically with the java runtime version that was supported but the recent updates have removed that issue. You can read more about the releases here https://cloud.google.com/appengine/docs/standard/java/release-notes

We will follow the steps from our previous blog up to the point where we add the appengine-maven-plugin. We do not use the app.yaml file in the App Engine standard. Instead we use the appengine-web.xml config file. The following steps need to be followed next.

1. Appengine-web.xml file
Create a new source folder : /src/main/webapp/WEB-INF. In this folder add a new file with the name appengine-web.xml. The following is the content of the file.

<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Google Inc.
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.
-->
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <threadsafe>true</threadsafe>
    <runtime>java8</runtime>
</appengine-web-app>

2. Change the packaging
Change the packaging in the pom file from jar to war

<packaging>war</packaging>

3. Add web.xml file
Add a web.xml file in the WEB-INF folder created aboove. The content of the file is as below.

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
</web-app>

4. Add a logging.properties file in the same location with the following config for now

.level = WARNING
handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=FINEST
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format = [%1$tc] %4$s: %2$s - %5$s %6$s%n

5. Change the main application class.
In our case the Application name is GoogleStandard and the SpringBootApplication class is called GoogleStandardApplication. We will extend the class to implement SpringBootServletInitializer. The class will look like the following

@SpringBootApplication
public class GoogleStandardApplication extends SpringBootServletInitializer{

	@Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(GoogleStandardApplication.class);
    }
	
	public static void main(String[] args) {
		SpringApplication.run(GoogleStandardApplication.class, args);
	}
}

Deploy the application using the following command

mvn appengine:deploy

If a new project was created for the deployment, make sure to use the following commands to use the new project and create the appengine instance.

gcloud config set project PROJECT-NAME
gcloud app create

Creating a Spring Boot application on Google App Engine Flex

January 22, 2018 Leave a comment

Google provides the infrastructure to build web applications on the cloud. There are different ways in which this can be done. App Engine provides a way where the scale up is provided automatically with other features. Within the App Engine offering there are 2 options – Flex and Standard. Flex App Engine allows us to use a Docker container for the application. In addition it is built on Compute Engine VM instances. Differences in Flex and Standard can be found here : https://cloud.google.com/appengine/docs/the-appengine-environments

We will see how to build and deploy a simple Spring Boot application on a Google App Engine Flex environment.
The initial setup of the Google Cloud Platform project and the SDK can be found here. (https://codesilo.wordpress.com/2018/01/18/gcloud-sdk-setup-for-app-engine-java-for-mac/)

We will create a simple Spring Boot application as described in the “Creating the Spring Boot Application” section here (https://codesilo.wordpress.com/2017/12/26/spring-boot-rest-api-integration-with-salesforce/)

After creating the project the billing needs to be enabled for the project –
https://console.developers.google.com/billing
For the free limits, the billing will not be enabled but it will need to be verified anyways

Once the Spring boot application is created we will add the appengine maven plugin to the pom file of the project. The latest version available currently is 1.3.2. It can be found here https://mvnrepository.com/artifact/com.google.cloud.tools/appengine-maven-plugin/1.3.2. The following needs to be added under in the pom.xml file

<!-- https://mvnrepository.com/artifact/com.google.cloud.tools/appengine-maven-plugin -->
<plugin>
    <groupId>com.google.cloud.tools</groupId>
    <artifactId>appengine-maven-plugin</artifactId>
    <version>1.3.2</version>
</plugin>

There is another plugin that is available with the group id com.google.appengine. But this is the older plugin available for the sdk. Additional information of the difference in the 2 plugins can be found here: https://stackoverflow.com/questions/40627278/which-app-engine-maven-plugin-to-use

In the next step, create a folder under the “main” folder with the name “appengine”. We will create a file app.yaml in this folder with the following contents for now. Details on the app.yaml configuration can be found here https://cloud.google.com/appengine/docs/flexible/java/configuring-your-app-with-app-yaml

# [START appyaml]
runtime: java
env: flex
runtime_config:
   jdk: openjdk8
manual_scaling:
  instances: 1
handlers:
- url: /.*
  script: this field is required, but ignored
# [END appyaml]

In order to run the application locally, use the following command

mvn spring-boot:run

To deploy the application to the App Engine on Google Cloud use the following command

mvn appengine:deploy

Once the deployment is successful, you should be able to goto the cloud console at https://console.cloud.google.com/ and see the services deployed on the app engine instance (you can see this on the app engine dashboard). In our configuration above, it is going to be a default service. Clicking on the service will take you to the root context of our deployed application.

Screen Shot 2018-01-22 at 1.56.24 PM

Screen Shot 2018-01-22 at 1.57.08 PM

Spring Boot REST API integration with Salesforce

December 26, 2017 3 comments

This blog covers ways to integrate with Salesforce using REST API.
We will use Spring Boot to authenticate (get access_token and instance_url from Salesforce). Although this can be done using a plain Java Application, we will assume that a real world use case requires a web application to call the services.

The Spring Boot application we create will have have a service exposed through a plain HTTP GET call. The application will call the authentication on Salesforce and use the response from the authentication to make a call to get some data from an Object in Salesforce. In an actual implementation the authentication can be cached and need not be called each time before making an API call to Salesforce. The cache can be refreshed more frequently than the timeout on the session, or, it can be refreshed after the authentication failure exception because of the timeout.

1. Creating the Spring Boot Application

The easiest way to create a starter project is to use Spring STS (https://spring.io/tools). You could also follow the steps here if you don’t want to use STS and want to use some other IDE. (https://spring.io/guides/gs/spring-boot/)

To create the Project in STS, run the install of STS and create a new workspace for yourself. Click on File | New | Spring Starter Project
In the new Window, provide the name of the Project (for this example we give the name SalesforceRESTAPI), group name (com.wordpress.codesilo.salesforce), Artifcat (keep it as is – should have autofilled the name of the Project above), package (com.wordpress.codesilo.salesforce). These can be changed according to your namespace.

Screen Shot 2017-12-22 at 3.53.54 PM

In the next step select “Web” from the dependencies and proceed to create the project. To start the instance, right click on the project and to to Run As | Spring Boot App. This should start the server and you should be able to see the progress in the console. On the browser, go to http://localhost:8080 and you should be presented with a page with a “Whitelabel Error Page” header

Screen Shot 2017-12-22 at 6.08.34 PM

So far, we have created a default Spring Boot Application with “Web” added as a dependency (spring-boot-starter-web dependency). The next step is to add a simple Controller and a class to call the Salesforce API. But before we do that, we will create an object and create an “App” on a Salesforce instance that we want to connect to.

2. Setting up Salesforce Connected App

We will use a new Salesforce Developer Edition Org. Sign up for on here (https://developer.salesforce.com/signup)
Once logged in, go to the Classic mode in Salesforce and then to Setup | Create | Apps

Click “New” on Connected Apps and fill the form in the next page. Add the Connected App Name, API Name and email as required. We don’t need these fields for the integration however. Click on “Enable OAuth Settings” and add the following as the Callback Url “http://localhost&#8221;. For selected OAuth Scopes, choose Full Access for now. Change these settings as required later. Save the changes – it should take a few minutes for this to take effect.
In order to create Connected App in Salesforce Lightning see here https://help.salesforce.com/articleView?id=connected_app_create.htm&type=5

You should now be able to get the following information from the Connected App created – Consumer Key, Consumer Secret. If you don’t have a Security Token for your account yet (had you created the Developer Edition instance earlier), go to, “My Profile” and in the Quick Find look for “Reset Security Token”. This should send you a security token to your email. Note: If the “Login IP” ranges for your Profile has been set appropriately, you might not require the security token.

3. Create the Controller on Spring Boot App

We will create a new Class for the controller in the following package. com.wordpress.codesilo.salesforce.controller. The class will take a simple GET request and return the text “home” in the body.

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SalesforceAPIController {

@RequestMapping("/home")
public String getSalesforceObject(){
return "home";
}

}

4. Create the class to make the API call to Salesforce

Create the model class to store the response from the authentication on Salesforce

package com.wordpress.codesilo.salesforce.model;

public class AuthenticationResponse {

private String access_token;
private String instance_url;
private String token_type;
private String issued_at;

public String getAccess_token() {
return access_token;
}
public void setAccess_token(String access_token) {
this.access_token = access_token;
}
public String getInstance_url() {
return instance_url;
}
public void setInstance_url(String instance_url) {
this.instance_url = instance_url;
}
public String getToken_type() {
return token_type;
}
public void setToken_type(String token_type) {
this.token_type = token_type;
}
public String getIssued_at() {
return issued_at;
}
public void setIssued_at(String issued_at) {
this.issued_at = issued_at;
}

@Override
public String toString() {
return "AuthenticationResponse [access_token=" + access_token + ", instance_url=" + instance_url
+ ", token_type=" + token_type + ", issued_at=" + issued_at + "]";
}
}

We now create a class (SalesforceAPIService) to make the REST API calls to Salesforce. We first have to make a call to authenticate with Salesforce. (Replace the parameters marked between ** below with appropriate values of your instance/Org)

public AuthenticationResponse login(){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> params= new LinkedMultiValueMap<String, String>();

params.add("username", ** USERNAME HERE **);
params.add("password", ** CONCATENATION OF PASSWORD AND SECURITY TOKEN HERE ** );
params.add("client_secret", ** CONSUMER SECRET FROM CONNECTED APP HERE ** );
params.add("client_id", ** CONSUMER KEY FROM CONNECTED APP HERE **);
params.add("grant_type","password");

HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(params, headers);

RestTemplate restTemplate = new RestTemplate();
ResponseEntity response = restTemplate.postForEntity("https://login.salesforce.com/services/oauth2/token", request, AuthenticationResponse.class);
return response.getBody();;
}

The response from the call above has the token and the instance url that we use in the next call to get the data from an Object.

In the next API call, we will query the Account object to get the Id and Name from the object. We will assume that we will get a specific object by querying based on an Id. Use an Id from your Developer Edition to query and get a result. The response is going to be in json in the following format. Here is the sample:

{
"totalSize": 1,
"done": true,
"records": [
{
"attributes": {
"type": "Account",
"url": "/services/data/v22.0/sobjects/Account/001f4000005WEvpAAG"
},
"Id": "001f4000005WEvpAAG",
"Name": "Burlington Textiles Corp of America"
}
]
}

We need to create the Java Objects to store the response. In order to create the POJO, we can use http://www.jsonschema2pojo.org/

The following classes are to be created for the POJOs

public class AccountResponse {

private int totalSize;
private boolean done;
private List records;

public int getTotalSize() {
return totalSize;
}
public void setTotalSize(int totalSize) {
this.totalSize = totalSize;
}
public boolean isDone() {
return done;
}
public void setDone(boolean done) {
this.done = done;
}
public List getRecords() {
return records;
}
public void setRecords(List records) {
this.records = records;
}

}
public class Attribute{
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;
}
}

public class Account {
@JsonProperty("attributes")
private Attribute attributes;
@JsonProperty("Id")
private String id;
@JsonProperty("Name")
private String name;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("attributes")
public Attribute getAttributes() {
return attributes;
}

@JsonProperty("attributes")
public void setAttributes(Attribute attributes) {
this.attributes = attributes;
}

@JsonProperty("Id")
public String getId() {
return id;
}

@JsonProperty("Id")
public void setId(String id) {
this.id = id;
}

@JsonProperty("Name")
public String getName() {
return name;
}

@JsonProperty("Name")
public void setName(String name) {
this.name = name;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}

In the class we use to call the API to Salesforce add the following method to get the data from the Account Object.

public AccountResponse getAccountData(String accessToken, String instanceUrl){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + accessToken);
MultiValueMap<String, String> params= new LinkedMultiValueMap<String, String>();

HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(params, headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity salesforceTestData = restTemplate.exchange(instanceUrl+ "/services/data/v22.0/query?q=select Id, Name from Account where Id = '001f4000005WEvp'", HttpMethod.GET, request, AccountResponse.class);
log.info(salesforceTestData.getBody().getRecords().get(0).getName());
return salesforceTestData.getBody();
}

The accessToken and instanceUrl parameters are the values from the AuthenticationResponse above.

5. Remap the Controller class to call the service

We will mark the SalesforceAPIService class with the @Component annotation so that it is available for autowiring in the controller.
We now call the SalesforceAPIService from the controller and pass the response to the service on Spring.

@RequestMapping("/account")
public AccountResponse getSalesforceAccount(){
AuthenticationResponse authenticationResponse = salesforceAPIService.login();
AccountResponse accountResponse = salesforceAPIService.getAccountData(authenticationResponse.getAccess_token(), authenticationResponse.getInstance_url());
return accountResponse;
}

Once we start the server and call go the following url (GET request) http://localhost:8080/account , we get the response from the service call to Salesforce.

Screen Shot 2017-12-25 at 10.45.50 PM.png

Drools 6 Decision Table with Spring MVC

June 8, 2015 Leave a comment

Drools is the Java Rules engine from Jboss. This article covers on how to use the Drools Decision Table using excel sheets with a Spring MVC project.

To start with, create a basic Spring MVC project using Spring STS. Add the following dependencies for drools on the pom file generated by the template in STS.


<dependency>
 <groupId>org.drools</groupId>
 <artifactId>drools-core</artifactId>
 <version>6.2.0.Final</version> 
 </dependency>
 <dependency>
 <groupId>org.drools</groupId>
 <artifactId>drools-compiler</artifactId>
 <version>6.2.0.Final</version> 
 </dependency>
 <dependency>
 <groupId>org.kie</groupId>
 <artifactId>kie-spring</artifactId>
 <version>6.2.0.Final</version> 
 </dependency>
 <dependency>
 <groupId>org.kie</groupId>
 <artifactId>kie-api</artifactId>
 <version>6.2.0.Final</version> 
 </dependency>
 <dependency>
 <groupId>org.kie</groupId>
 <artifactId>kie-internal</artifactId>
 <version>6.2.0.Final</version> 
 </dependency>

Create a spring-context.xml file in the following location /WEB-INF/spring with the following content


<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:kie="http://drools.org/schema/kie-spring"
 xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://drools.org/schema/kie-spring http://drools.org/schema/kie-spring.xsd">

<kie:kmodule id="kmodule1">
 <kie:kbase name="kbase1" packages="com.codesilo.wordpress.rules">
 <kie:ksession name="ksession1" type="stateless" />
 </kie:kbase>
 </kie:kmodule>

<beans:bean id="kiePostProcessor"
 class="org.kie.spring.KModuleBeanFactoryPostProcessor" />

</beans:beans>

The package here “com.codesilo.wordpress.rules” denotes the location where the decision tables are located. We will create that one we have created the POJO.

Add the /WEB-INF/spring/spring-context.xml on the contextConfigLocation in web.xml. The contextConfigLocation should now look like


<context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>/WEB-INF/spring/root-context.xml
 /WEB-INF/spring/root-context.xml</param-value>
 </context-param>

We create the POJO named as RouteAttribute in the following package com.wordpress.codesilo.model. This object will be used as the fact for the rules defined,


package com.wordpress.codesilo.model;

public class RouteAttribute {

private String country;
 private String state;
 private boolean newEntry;
 
 //Result
 private String ansOnRule;

public String getCountry() {
 return country;
 }

public void setCountry(String country) {
 this.country = country;
 }

public String getState() {
 return state;
 }

public void setState(String state) {
 this.state = state;
 }

public boolean isNewEntry() {
 return newEntry;
 }

public void setNewEntry(boolean newEntry) {
 this.newEntry = newEntry;
 }

public String getAnsOnRule() {
 return ansOnRule;
 }

public void setAnsOnRule(String ansOnRule) {
 this.ansOnRule = ansOnRule;
 }
 
}


Now we create the decision table (Rules.xls) on the following location com.codesilo.wordpress.rules

Rules

The file can also be downloaded from here.

As a last step, we change HomeController.java to fire the rules. This can be later moved to any controller/MVC flow. We inject the KieBase object by the following..

@Autowired
private KieBase kieBase;

Add the following in the default method on the HomeController class.


RouteAttribute routingComponent = new RouteAttribute();

routingComponent.setCountry("US");

StatelessKieSession statelessKieSession =  kbase.newStatelessKieSession();

statelessKieSession.execute(routingComponent);

Now, if we bring up the server, the default method is going to run and call the rules from above.

MongoDB Spring Data and Spring Security with custom UserDetailsService

July 8, 2012 12 comments

In a earlier write up we saw how we can setup basic spring security. In this one we will see how to make a custom UserDetailsService instead of using the credentials in the configuration file. We will use MongoDB as a datasource.

We will use the project from the Spring Security project we created earlier and add the MongoDB config details and user service to provide the capability. See my previous blog for setting up MongoDB Spring Data.

Add the following to the mongo-config.xml file in the location WEB-INF/mongo/

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mongo="http://www.springframework.org/schema/data/mongo"
 xsi:schemaLocation="http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.1.xsd
 http://www.springframework.org/schema/data/mongo
 http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
 http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

 <!-- Default bean name is 'mongo' -->
 <mongo:mongo host="localhost" port="27017" />

 <bean id="mongoTemplate"
 class="org.springframework.data.mongodb.core.MongoTemplate">
 <constructor-arg ref="mongo" />
 <constructor-arg name="databaseName" value="codesilo" />

 </bean>

 <!-- To translate any MongoExceptions thrown in @Repository annotated classes -->
 <context:annotation-config />

</beans>

Add the Spring Data dependencies in the pom.xml file

<dependency>
 <groupId>org.mongodb</groupId>
 <artifactId>mongo-java-driver</artifactId>
 <version>2.7.2</version>
 </dependency>
 <dependency>
 <groupId>org.springframework.data</groupId>
 <artifactId>spring-data-mongodb</artifactId>
 <version>1.1.0.M1</version>
 </dependency>
 <dependency>
 <groupId>cglib</groupId>
 <artifactId>cglib</artifactId>
 <version>2.2</version>
 </dependency>

Add the mongo-config.xml file to the contextConfigLocation on web.xml. The context param will look like this

<context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>/WEB-INF/spring/root-context.xml
 /WEB-INF/spring/security-app-context.xml
 /WEB-INF/mongo/mongo-config.xml
 </param-value>
 </context-param>

We will now create a CustomUserDetailsService class that implements UserDetailsService. We will add the implementation of loadUserByUsername method. The CustomUserDetailsService is as follows. The getUserDetail method queries to get the user object from MongoDB (it is assumed that the data is already there).

package com.wordpress.codesilo.model;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

public class CustomUserDetailsService implements UserDetailsService {

private MongoTemplate mongoTemplate;

 public UserDetails loadUserByUsername(String username)
 throws UsernameNotFoundException {
 User user = getUserDetail(username);
 System.out.println(username);
 org.springframework.security.core.userdetails.User userDetail = new org.springframework.security.core.userdetails.User(user.getUsername(),user.getPassword(),true,true,true,true,getAuthorities(user.getRole()));
 return userDetail;
 }

@Autowired
 public void setMongoTemplate(MongoTemplate mongoTemplate) {
 this.mongoTemplate = mongoTemplate;
 }

 public List<GrantedAuthority> getAuthorities(Integer role) {
 List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>();
 if (role.intValue() == 1) {
 authList.add(new SimpleGrantedAuthority("ROLE_USER"));
 authList.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
 } else if (role.intValue() == 2) {
 authList.add(new SimpleGrantedAuthority("ROLE_USER"));
 }
 return authList;
 }

 public User getUserDetail(String username){
 MongoOperations mongoOperation = (MongoOperations)mongoTemplate;
 User user = mongoOperation.findOne(
 new Query(Criteria.where("username").is(username)),
 User.class);
 System.out.println(user.toString());
 return user;
 }

}

We will also create a user POJO which is as follows.

package com.wordpress.codesilo.model;

public class User {

public String username;
 public String password;
 public String firstName;
 public String lastName;
 public String email;
 public int role;

public User() {
 }

public int getRole() {
 return role;
 }

public void setRole(int role) {
 this.role = role;
 }

public User(String username, String password, String firstName,
 String lastName) {
 this.username = username;
 this.password = password;
 this.firstName = firstName;
 this.lastName = lastName;
 }

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 String getFirstName() {
 return firstName;
 }

public void setFirstName(String firstName) {
 this.firstName = firstName;
 }

public String getLastName() {
 return lastName;
 }

public void setLastName(String lastName) {
 this.lastName = lastName;
 }

public String getEmail() {
 return email;
 }

public void setEmail(String email) {
 this.email = email;
 }

@Override
 public String toString(){
 return "First Name:" + this.firstName + " Last Name:" + this.lastName + " Username:" + this.username ;
 }

}

As a last step we will change the security-app-context.xml to have the customUserDetailsService bean and user-service-ref in the authentication provider.

<beans:bean id="customUserDetailsService" class="com.wordpress.codesilo.model.CustomUserDetailsService"/>

 <authentication-manager>
 <authentication-provider user-service-ref="customUserDetailsService"/>
 </authentication-manager>

Now when we try to login to the application it will use the MongoDB to get the credentials.

We can also use the Security Context to get the principal and display the username and roles on home.jsp.
Add this to the pom dependencies.

<dependency>
 <groupId>org.springframework.security</groupId>
 <artifactId>spring-security-taglibs</artifactId>
 <version>${org.springframework-version}</version>
 </dependency>

Add the following taglib to the home.jsp page

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

and the following content on the jsp page to display the data.

<sec:authorize access="isAuthenticated()">
 Username: <sec:authentication property="principal.username" />
 Role: <sec:authentication property="principal.authorities"/>
 </sec:authorize>

Setting up a project with Spring Data and MongoDB

July 2, 2012 4 comments

From springsource : “The goal of the Spring Data Document (or DATADOC) framework is to provide an extension to the Spring programming model that supports writing applications that use Document databases”.
This blog will cover on how to use Spring Data with MongoDB. We will start with creating a simple Spring MVC application. See my previous blog to see how to setup a basic Spring MVC app using STS.

We will first add the dependencies on the pom file of the project.

<!-- Spring Data Mongo Driver -->

 <dependency>
 <groupId>org.mongodb</groupId>
 <artifactId>mongo-java-driver</artifactId>
 <version>2.7.2</version>
 </dependency>

 <dependency>
 <groupId>org.springframework.data</groupId>
 <artifactId>spring-data-mongodb</artifactId>
 <version>1.1.0.M1</version>
 </dependency>
 <dependency>
 <groupId>cglib</groupId>
 <artifactId>cglib</artifactId>
 <version>2.2</version>
 </dependency>

We will also need to add the Spring Milestone repo to the pom

<repositories>
 <repository>
 <id>spring-milestone</id>
 <name>Spring Maven MILESTONE Repository</name>
 <url>http://maven.springframework.org/milestone</url>
 </repository>
</repositories>

CONFIGURING MONGO TEMPLATE USING SPRING XML
We will now create a mongo-config.xml in the WEB-INF directory of the project. Add this as the content of the xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mongo="http://www.springframework.org/schema/data/mongo"
 xsi:schemaLocation="http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.1.xsd
 http://www.springframework.org/schema/data/mongo
 http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
 http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

 <!-- Default bean name is 'mongo' -->
 <mongo:mongo host="localhost" port="27017" />

 <bean id="mongoTemplate"
 class="org.springframework.data.mongodb.core.MongoTemplate">
 <constructor-arg ref="mongo" />
 <constructor-arg name="databaseName" value="codesilo" />

 </bean>

 <!-- To translate any MongoExceptions thrown in @Repository annotated classes -->
 <context:annotation-config />

</beans>

Add this to the web.xml configLocation

<context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>/WEB-INF/spring/root-context.xml
 /WEB-INF/mongo-config.xml
 </param-value>
 </context-param>

We will keep things simple. Create a user model and refactor the homeController class to use that model. The HomeController class will create a User object, insert it in the database, query and return the first result to the view.
The following is the model User class.

public class User {

 public String username;
 public String password;
 public String firstName;
 public String lastName;

 public User(){

 }

 public User(String username, String password, String firstName, String lastName){
 this.username = username;
 this.password = password;
 this.firstName = firstName;
 this.lastName = lastName;
 }

 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 String getFirstName() {
 return firstName;
 }
 public void setFirstName(String firstName) {
 this.firstName = firstName;
 }
 public String getLastName() {
 return lastName;
 }
 public void setLastName(String lastName) {
 this.lastName = lastName;
 }

 @Override
 public String toString(){
 return "User [username=" + username + ", passowrd= ****" + ", firstName=" + firstName + "lastName" + lastName + "]";
 }
}

Change the HomeController class to look like the following

@Controller
public class HomeController {

 @Autowired
 private MongoTemplate mongoTemplate;

 private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

 /**
 * Simply selects the home view to render by returning its name.
 */
 @RequestMapping(value = "/", method = RequestMethod.GET)
 public String home(Locale locale, Model model) {

 logger.info("Welcome home! the client locale is "+ locale.toString());

 MongoOperations mongoOperation = (MongoOperations)mongoTemplate;
 User user = new User("codesilo", "Password", "Code", "Silo");
 mongoOperation.save(user);
 List<User> users = mongoOperation.find(
 new Query(Criteria.where("username").is("codesilo")),
 User.class);

 model.addAttribute("user", users.get(0).toString());

 return "home";
 }

}

Change the body of home.jsp to the following

<body>
<h1>
 Hello world!
</h1>

<P> Getting user from MongoDB: ${user} </P>
</body>

Now when we go to the application, we will see the following

and when we use the mongo shell to query the database, we get..

> db.user.find();
{ "_id" : ObjectId("4fef96227e27ff2b7a81331f"), "_class" : "com.wordpress.codesilo.model.User", "username" : "codesilo", "password" : "Password", "firstName" :
"Code", "lastName" : "Silo" }

References:
MongoTemplate- SpringSource Documentation

Scheduling using Quartz

June 8, 2010 2 comments

Many times we need to perform repetitive jobs in our applications. One common way is to use Thread.sleep method but if you need to synchronize the start of the job based on clock cycles , using a Quartz scheduler is way simpler. Cron triggers can be used to schedule the time that the job starts. We will take a look at how to use Quartz in the non-spring and spring way.

Without Spring…
Get the Quartz 1.8.0 download from here. Add the slf4j jars to the classpath.
My main class looks like this…

public class Main {

 public static void main(String[] args) throws SchedulerException, ParseException {
 Main main = new Main();
 main.scheduleJobs();
 }

 public void scheduleJobs() throws SchedulerException, ParseException {
 SchedulerFactory factory = new StdSchedulerFactory();
 Scheduler sch = factory.getScheduler();
 JobDetail jobDetail = new JobDetail("testJob", null, MyTestJob.class);
 CronTrigger cron = new CronTrigger("testCron", null , "* * * * * ?");
 sch.scheduleJob(jobDetail, cron);
 sch.start();
 }
}

What we have done here is that we have created a scheduler by using SchedulerFactory. JobDetail is the definition of the job that will be run once the trigger fires. “testJob” is the name we give to the job detail, its group is “null” and the class that implements Job is MyTestJob. Similarly, the CronTrigger has the name “testCron”, belongs to group “null” and has a cron expression that fires every second.

The MyTestJob class is as follows…

public class MyTestJob implements Job {

 @Override
 public void execute(JobExecutionContext arg0) throws JobExecutionException {
 System.out.println("In my job.");
 }
}

If we run the program we will see some log messages and then the following output will be printed on the console.. one line every second…
In my job.
In my job.
In my job.
In my job.

Using Spring..
We first create a basic Spring project with Maven… see my older post to get an idea.
The dependencies on my pom.xml file are as follows…

<dependencies>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-core</artifactId>
 <version>2.5.6</version>
 <scope>compile</scope>
 </dependency>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-jdbc</artifactId>
 <version>2.5.6</version>
 <scope>compile</scope>
 </dependency>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-context</artifactId>
 <version>2.5.6</version>
 <scope>compile</scope>
 </dependency>
 <dependency>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 <version>3.8.1</version>
 <scope>test</scope>
 </dependency>
 <dependency>
 <groupId>org.quartz-scheduler</groupId>
 <artifactId>quartz</artifactId>
 <version>1.8.0</version>
 </dependency>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-context-support</artifactId>
 <version>2.5.6</version>
 <scope>compile</scope>
 </dependency>
 </dependencies>

We will create the beans.xml file in the resources dir. It looks like this….

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

 <bean name="exampleJob">
 <property name="jobClass" value="com.wordpress.codesilo.ExampleJob" />
 </bean>

 <bean id="cronTrigger">
 <property name="jobDetail" ref="exampleJob" />
 <property name="cronExpression" value="* * * * * ?" />
 </bean>

 <bean id="scheduleFactory">
 <property name="triggers">
 <list>
 <ref bean="cronTrigger" />
 </list>
 </property>
 </bean>
</beans>

The ExampleJob class if the class that will run once the trigger fires. It looks like this..

public class ExampleJob extends QuartzJobBean {
 @Override
 protected void executeInternal(JobExecutionContext arg0)
 throws JobExecutionException {
 System.out.println("In the job");
 }
}

Our main class will have this only..

 public static void main(String[] args) throws SchedulerException {
 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
 }

If we run main , we will see the following …
log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
In the job
In the job
……..

We will initialize log4j by adding the following log4j.xml file in the resources dir.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
 <appender name="console">
 <param name="Target" value="System.out"/>
 <layout>
 <param name="ConversionPattern" value="%-5p %c{1} - %m%n"/>
 </layout>
 </appender>

 <root>
 <priority value ="debug" />
 <appender-ref ref="console" />
 </root>

</log4j:configuration>

Now, we will see all the debug messages along with out System.out message …”In the job”

In order to inject a bean in the job class we change the exampleJob declaration in beans.xml to the following and declare the “injectedBean” …

<bean name="exampleJob">
 <property name="jobClass" value="com.wordpress.codesilo.ExampleJob" />
 <property name="jobDataAsMap">
 <map>
 <entry key="injectedBean" value-ref="injectedBean" />
 </map>
 </property>
 </bean>

 <bean id="injectedBean"/>

We will have a simple method that displays a message in the InjectedBean class

 public void execute(){
 System.out.println("In injected bean execute method");
 }

and call this method from the ExampleJob class.
Now, if we run main we should see the following output (after removing the debug logs)
In the job
In injected bean execute method
In the job
In injected bean execute method

Stateful Job and Concurrency

In order that the job is not fired concurrently we can have two approaches …

a) Make the job stateful.  All we need here is to implement StatefulJob when creating the ExampleJob class. So, the ExampleJob class declaration now looks like this..

 public class ExampleJob extends QuartzJobBean implements StatefulJob {
 ......
 ......
 }

Read more about it here.

b) Use “MethodInvokingJobDetailFactoryBean” and set the concurrent flag to false. Here is a section from the docs

By default, Quartz Jobs are stateless, resulting in the possibility of jobs interfering with each other. If you specify two triggers for the same JobDetail, it might be possible that before the first job has finished, the second one will start. If JobDetail classes implement the Stateful interface, this won’t happen. The second job will not start before the first one has finished. To make jobs resulting from the MethodInvokingJobDetailFactoryBean non-concurrent, set the concurrent flag to false.

 <bean id="jobDetail">
 <property name="targetObject" ref="exampleBusinessObject" />
 <property name="targetMethod" value="doIt" />
 <property name="concurrent" value="false" />
 </bean>