Archive

Posts Tagged ‘Java’

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

GCloud SDK Setup for App Engine Java for Mac

January 18, 2018 Leave a comment

Google Cloud Platform (https://cloud.google.com/) is a cloud infrastructure solution from Google. In the next blog we will build and deploy a simple Spring Boot application on Google Flex App Engine. This writeup covers the setup of the gcloud sdk on Mac OS X for the purpose above.

First check if Python is installed in the OS using one of the following commands

python -V
python --version

 

Download the Google Cloud SDK from this location for your OS https://cloud.google.com/sdk/ .In my case I downloaded the 64bit version for Mac: google-cloud-sdk-157.0.0-darwin-x86_64.tar.gz

Extract the files and then run the command ./install.sh in the directory created. This will install the sdk.
Once installed the output will show the components installed and give some commands that can be run to update the components.

┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                                  Components                                                 │
├───────────────┬──────────────────────────────────────────────────────┬──────────────────────────┬───────────┤
│     Status    │                         Name                         │            ID            │    Size   │
├───────────────┼──────────────────────────────────────────────────────┼──────────────────────────┼───────────┤
│ Not Installed │ App Engine Go Extensions                             │ app-engine-go            │  96.7 MiB │
│ Not Installed │ Cloud Bigtable Command Line Tool                     │ cbt                      │   4.0 MiB │
│ Not Installed │ Cloud Bigtable Emulator                              │ bigtable                 │   3.3 MiB │
│ Not Installed │ Cloud Datalab Command Line Tool                      │ datalab                  │   < 1 MiB │
│ Not Installed │ Cloud Datastore Emulator                             │ cloud-datastore-emulator │  15.4 MiB │
│ Not Installed │ Cloud Datastore Emulator (Legacy)                    │ gcd-emulator             │  38.1 MiB │
│ Not Installed │ Cloud Pub/Sub Emulator                               │ pubsub-emulator          │  21.0 MiB │
│ Not Installed │ Emulator Reverse Proxy                               │ emulator-reverse-proxy   │  14.5 MiB │
│ Not Installed │ Google Container Registry's Docker credential helper │ docker-credential-gcr    │   2.3 MiB │
│ Not Installed │ gcloud Alpha Commands                                │ alpha                    │   < 1 MiB │
│ Not Installed │ gcloud Beta Commands                                 │ beta                     │   < 1 MiB │
│ Not Installed │ gcloud app Java Extensions                           │ app-engine-java          │ 132.2 MiB │
│ Not Installed │ gcloud app PHP Extensions (Mac OS X)                 │ app-engine-php-darwin    │  21.9 MiB │
│ Not Installed │ gcloud app Python Extensions                         │ app-engine-python        │   6.4 MiB │
│ Not Installed │ kubectl                                              │ kubectl                  │  14.8 MiB │
│ Installed     │ BigQuery Command Line Tool                           │ bq                       │   < 1 MiB │
│ Installed     │ Cloud SDK Core Libraries                             │ core                     │   6.1 MiB │
│ Installed     │ Cloud Storage Command Line Tool                      │ gsutil                   │   2.9 MiB │
│ Installed     │ Default set of gcloud commands                       │ gcloud                   │           │
└───────────────┴──────────────────────────────────────────────────────┴──────────────────────────┴───────────┘

 
Based on the input provided by you, the bash_profile will be updated and the PATH will be set for gcloud.
Once this is done run the following command

gcloud init

This will prompt you to login to your account. This along with some more input will provide the initial setup for the components. Once done the process will also give an option to use an existing project on Google Cloud, or , create a new one. Select a new project and proceed.

In order to develop a Java application on Google App Engine we require the app engine components. We will install those components now by running the following command.

gcloud components install app-engine-java

This should complete the setup for the sdk. The rest of the information/steps is optional.

Eclipse Plugin for Development
I tried to use the Eclipse plugin but was outdated at the time and works only for the standard App Engine (not for the Flex app engine). Have been using the command line for the push since then.

Misc Commands
Here are some other commands that might be useful in future development.

Used to set a Project for the SDK

gcloud config set project PROJECT_NAME 

List of configuration parameters that have been set(includes account, usage reporting flag and project name)

gcloud config list

List of authorized accounts and the one being used actively

gcloud auth list

Used to update the components in the sdk that was installed.

gcloud components update

Reference: https://cloud.google.com/sdk/

Multiple versions of Java on Mac OS X

January 18, 2018 Leave a comment

I was working on the Google Cloud platform a couple of months back when Java 8 was not supported on the Standard App Engine. However, the Flex engine had Java 8 support (currently even the standard has support for it). When trying out Standard Vs Flex, I had to find something to switch between the Java versions. Jenv came to the rescue (http://www.jenv.be/)

The following steps show how to work with jenv on Mac OS X. (Java 8 was already installed on my OS.)

Use Homebrew to install some packages. Brew is the command for Homebrew (https://brew.sh/) and Homebrew is the package manager for Mac.

Update Homebrew and install Cask if it is not installed already(Cask is an extension of brew for graphical applications)

brew update && brew cask 

Update the repositories in brew to use caskroom/versions

brew tap caskroom/versions

Install Java7 from Caskroom versions

brew cask install java7

Use brew to install jenv

brew install jenv

The following command gives the list of versions of Java installed. The one with the * is the one being used globally

jenv versions 

To install a new version, first we need to make the versions dir

mkdir /Users/codesilo/.jenv/versions

Then add the Java (installed by cask earlier) to the versions of jenv by using the following command

jenv add /Library/Java/JavaVirtualMachines/jdk1.7.0_80.jdk/Contents/Home/
jenv add /Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/

Use the following command to set the selected install as the global jenv version to be used

jenv global oracle64-1.7.0.80

The versions command will give the following result now

$ jenv versions
  system
  1.7
  1.7.0.80
  1.8
  1.8.0.101
* oracle64-1.7.0.80 (set by /Users/codesilo/.jenv/version)
  oracle64-1.8.0.101

You can also configure directory level version (local version) or shell instance version by using the following commands

$ jenv local oracle64-1.7.0.80
$ jenv shell oracle64-1.7.0.80

 

Categories: Java, Shell Tags: , , , , , , ,

Dynamic Forms with Map-backed ActionForms in Struts 1

September 14, 2010 4 comments

A project that I work on uses Struts 1 and I came across a problem where I intended to create a page that could have any number of text fields (number of fields would be increased by a button click). The idea was to have a way to have name – value text input boxes whose content would be saved in a properties database table when the form was submitted. After some blind google searches I came across “Map-backed” and “List-backed” properties in struts. This write-up is a summary of using Map-backed properties to achieve that goal. This article does not show how to save the values in the database however… it just logs the values received on the server.

As a first step we will create a blank Struts application with maven. Look at this article to create a blank application.
The next step is to create a page that will have our dynamic form. Here is the page(dynamicTextEntry.jsp)..

<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>

<html:html>
<head>
<script type="text/javascript">
	function add(){
		var element1 = document.createElement("input");
		var element2 = document.createElement("input");
		var elementCount = parseInt(document.getElementById("count").value);

		element1.setAttribute("type","text");
		element1.setAttribute("value","Enter Name");
		element1.setAttribute("name","value(name"+ elementCount +")");

		element2.setAttribute("type","text");
		element2.setAttribute("value","Enter Value");
		element2.setAttribute("name","value(value"+ elementCount +")");

		var spanBody = document.getElementById("textBoxes");
		spanBody.appendChild(element1);
		spanBody.appendChild(element2);
		var breakElement = document.createElement('br');
		spanBody.appendChild(breakElement);
		
		document.getElementById("count").value = elementCount + parseInt(1);
	}
</script>
<title>Dynamic Entry Form</title>
<html:base/>
</head>
<body bgcolor="white">

<html:form action="setDynamicTextEntry.do" >
<html:hidden property="count" styleId="count" value="0"/>
<input type="button" value="Add Field (+)" onclick="add()"/>
</br>
<span id="textBoxes"></span>

<html:submit property="submit"> Submit</html:submit>

</html:form>
</body>
</html:html>

We will create two actions in struts-config.xml as follows… the action class is shown later…

	<action
            path="/dynamicInputs"
            forward="/pages/dynamicTextEntry.jsp"/>
		
	<action
            path="/setDynamicTextEntry"
            type="com.wordpress.codesilo.controller.SetDynamicTextEntryAction"
            name="dyamicTextEntryForm"
            scope="request"
            validate="true"
            input="/pages/dynamicTextEntry.jsp">
            <forward name="success" path="/pages/success.jsp"/>
        </action>

We will also add form bean to struts-config.xml

<form-bean name="dyamicTextEntryForm" type="com.wordpress.codesilo.model.DyamicTextEntryForm"></form-bean>

The action class is as follows…

public class SetDynamicTextEntryAction extends Action {

	
	@Override
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		
		DyamicTextEntryForm dynform = (DyamicTextEntryForm)form;
		Map dynformValues = dynform.getValues();
		int count = dynformValues.size()/2;
		
		System.out.println("Map Size: " + dynformValues.size());
		for(int i =0; i<count ; i++){
			String name = (String)dynformValues.get("name"+i);
			String value = (String)dynformValues.get("value"+i);
			System.out.println("Name:" + name + " Value:" + value);
		}
		return mapping.findForward("success");
	}
}

The form is as follows…

public class DyamicTextEntryForm extends ActionForm {

	private final Map values = new HashMap();
	private int count;
	
	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}

	public Map getValues(){
		return values;
	}
	
	public void setValue(String key, Object value){
		values.put(key, value);
	}
	
	public Object getValue(String key){
		return values.get(key);
	}
	
}

Add a success page that is forwarded to once the form is submitted and we are ready to try out the code.
The page looks as follows… (Every time to click the add button a new pair of text boxes are added)
When we add/change text in the boxes and click submit, the values entered in the text boxes are displayed in the console.


Explanation:
The javascript in the jsp adds text boxes to the existing dom in pairs. The elements added would look like the following when rendered in HTML

<input type="text" value="Enter Name" name="value(name0)">
<input type="text" value="Enter Value" name="value(value0)">

Every time the button is clicked the count increments and new text boxes are added. So, on the second click the following elements are added…

<input type="text" value="Enter Name" name="value(name1)">
<input type="text" value="Enter Value" name="value(value1)">

Once the form is submitted, the setValue(String key, Object value) on the form is called for each of these text boxes. The key will be the names we provide (name0, value0, name1, value1 etc) and the value is the value from the text boxes.

Rest is self explanatory. 🙂

References:
http://struts.apache.org/1.x/userGuide/building_controller.html
http://www.manning-sandbox.com/message.jspa?messageID=26953

Sun JDK6 on Lucid

June 20, 2010 1 comment

In one of my earlier posts I had shown how to install Sun Java6 on Ubuntu(Karmic). When I upgraded to Lucid recently, that version of JDK was removed and Open JDK was the only one that was present. I had to google a bit to realize that sun-java6 was no longer present in the repositories. The release notes on Ubuntu’s wiki state the same. However, following the instructions on the release notes did not help me. Two reasons… First, the link is incorrect and secondly, the sources.list needs to have two entries one for deb and another for deb-src. The command on the wiki just adds the line with deb on the sources.list.
I found this blog that has a better explanation of the steps to be followed to fix the problem.

Summary,
Edit /etc/apt/sources.list
Uncomment the following two lines.
deb http://archive.canonical.com/ubuntu lucid partner
deb-src http://archive.canonical.com/ubuntu lucid partner

Run the following commands

sudo aptitude update
sudo apt-get install sun-java6-bin sun-java6-jre sun-java6-jdk
sudo update-java-alternatives -s java-6-sun