Search This Blog

Tuesday, 8 November 2016

Declarative REST Client Feign with Spring Boot

Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders.

In this example I show how to use Spring Cloud / Spring Boot application with Feign. The source code for this is as follows

https://github.com/papicella/SpringBootEmployeeFeignClient

1. Include the required maven dependency for Feign as shown below

  
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>

2. Assuming your going to lookup a service using Service Discovery with Spring Cloud then include this dependency as well, the example below is doing this using Spring Cloud Service Discovery.


<dependency>
  <groupId>io.pivotal.spring.cloud</groupId>
  <artifactId>spring-cloud-services-starter-service-registry</artifactId>
</dependency>


See the Spring Cloud Project page for details on setting up your build system with the current Spring Cloud Release Train

3. To enable Feign we simple add the annotation @EnableFeignClients as shown below


package pas.au.scs.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class SpringBootEmployeeFeignClientApplication {

 public static void main(String[] args) {
  SpringApplication.run(SpringBootEmployeeFeignClientApplication.class, args);
 }
}

4. Next we have to create an interface to call our service methods. The interface methods must match the service method signatures as shown below. In this example we use Spring Cloud service discovery to find our service and invoke the right implementation method, Feign can do more then just call registered services through spring cloud service discovery BUT this example does that.

EmployeeServiceClient Interface
 
package pas.au.scs.demo.employee;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.List;

@FeignClient("SPRINGBOOT-EMPLOYEE-SERVICE")
public interface EmployeeServiceClient
{
    @RequestMapping(method = RequestMethod.GET, value = "/emps")
    List<Employee> listEmployees();
}

So what does the actual service method look like?


@RestController
public class EmployeeRest
{
    private static Log logger = LogFactory.getLog(EmployeeRest.class);
    private EmployeeRepository employeeRepository;

    @Autowired
    public EmployeeRest(EmployeeRepository employeeRepository)
    {
        this.employeeRepository = employeeRepository;
    }

    @RequestMapping(value = "/emps",
                    method = RequestMethod.GET,
                    produces = MediaType.APPLICATION_JSON_VALUE)
    public List<Employee> listEmployees()
    {
        logger.info("REST request to get all Employees");
        List<Employee> emps = employeeRepository.findAll();

        return emps;
    }

    ..... 


5. It's important to note that the Feign client is calling a service method using Spring Cloud service discovery , the screen shot below shows how it looks inside Pivotal Cloud Foundry when we select out service registry instance and click on Manage






6. Finally we just need to call our service using the Feign client interface and do do that with Autowire as required. In this example below we use a class annotated with @Controller as shown below which then using the returned data to display the results to a web page using Thymeleaf

package pas.au.scs.demo.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import pas.au.scs.demo.employee.EmployeeServiceClient;

@Controller
public class EmployeeFeignController
{
    Logger logger = LoggerFactory.getLogger(EmployeeFeignController.class);

    @Autowired
    private EmployeeServiceClient employeeServiceClient;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String homePage(Model model) throws Exception
    {
        model.addAttribute("employees", employeeServiceClient.listEmployees());

        return "employees";
    }

}

7. The Web page "employees.html" fragment accessing the returned List of employees is as follows.

<div class="col-xs-12">
    <table id="example" class="table table-hover table-bordered table-striped table-condensed">
        <thead>
        <tr>
            <th>Id</th>
            <th>Name</th>
            <th>Job</th>
            <th>Mgr</th>
            <th>Salary</th>
        </tr>
        </thead>
        <tbody>
        <tr th:each="employee : ${employees}">
            <td th:text="${employee.id}"></td>
            <td th:text="${employee.name}"></td>
            <td th:text="${employee.job}"></td>
            <td th:text="${employee.mgr}"></td>
            <td th:text="${employee.salary}"></td>
        </tr>
        </tbody>
    </table>
</div>  

More Information

1. Spring Cloud
http://projects.spring.io/spring-cloud/

2. Declarative REST Client: Feign
http://cloud.spring.io/spring-cloud-netflix/spring-cloud-netflix.html#spring-cloud-feign

Tuesday, 11 October 2016

Pushing a Docker image using Docker Hub on Pivotal Cloud Foundry

In this example I will show how to push a Docker image to Pivotal Cloud Foundry (PCF) using Docker Hub. You can use your own private Docker Registry BUT here I am using Docker Hub in this example.

The example spring boot application which can easily created as a Docker Image is per this spring guide below.

https://spring.io/guides/gs/spring-boot-docker/

1. First we need to ensure the docker is enabled on Diego as shown below.

pasapicella@pas-macbook:~$ cf feature-flag diego_docker
Retrieving status of diego_docker as admin...
OK

Features           State
diego_docker   enabled

Note: If it's not enabled you would need ADMIN rights to set it as follows

$ cf enable-feature-flag diego_docker

2. Login to Docker Hub from the command line

pasapicella@pas-macbook:~/pivotal/software/docker$ docker login -u pasapples -p ******
Login Succeeded

3. Push your local Docker image to your public Docker Hub Repository as follows

This assumes you have an IMAGE to push as per below.

pasapicella@pas-macbook:~/pivotal/software/docker$ docker images
REPOSITORY                            TAG                 IMAGE ID            CREATED             SIZE
pasapples/cf                                 0.0.1                b25e9b214774       3 days ago              881.4 MB
pasapples/gs-spring-boot-docker latest               5fc76927eca2        3 days ago              195.5 MB
gregturn/gs-spring-boot-docker   latest               a813439710d3       3 days ago              195.4 MB
ubuntu                                          14.04               f2d8ce9fa988        2 weeks ago            187.9 MB
frolvlad/alpine-oraclejdk8            slim                f8103909759b       2 weeks ago            167.1 MB
springio/gs-spring-boot-docker    latest              688d6c4ab4d3       18 months ago         609.9 MB

** Push to Docker Hub **

$ docker push pasapples/gs-spring-boot-docker
The push refers to a repository [docker.io/pasapples/gs-spring-boot-docker]
1a701a998f45: Layer already exists
0d4e0b525d4f: Layer already exists
a27c88827076: Pushed
58f7b9930e4f: Layer already exists
9007f5987db3: Layer already exists
latest: digest: sha256:6b3ccae43e096b1fa4d288900c6d2328e34f11e286996ffa582961bad599aee9 size: 1375

4. Login to Docker Hub and verify it's loaded as shown below

https://hub.docker.com/


At this point we are ready to Deploy to our PCF instance and it's assumed you have already logged into the instance prior to running this next step

5. Push as shown below to PCF

pasapicella@pas-macbook:~$ cf push springboot-docker --docker-image pasapples/gs-spring-boot-docker --random-route -i 1 -m 512M -t 180
Creating app springboot-docker in org apples-org / space development as papicella@pivotal.io...
OK

Creating route springboot-docker-oological-superseniority.apps.pcfdemo.net...
OK

Binding springboot-docker-oological-superseniority.apps.pcfdemo.net to springboot-docker...
OK


Starting app springboot-docker in org apples-org / space development as papicella@pivotal.io...
Creating container
Successfully created container
Staging...
Staging process started ...
Staging process finished
Exit status 0
Staging Complete
Destroying container
Successfully destroyed container

0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
1 of 1 instances running

App started


OK

App springboot-docker was started using this command `java -Djava.security.egd=file:/dev/./urandom -jar /app.jar `

Showing health and status for app springboot-docker in org apples-org / space development as papicella@pivotal.io...
OK

requested state: started
instances: 1/1
usage: 512M x 1 instances
urls: springboot-docker-oological-superseniority.apps.pcfdemo.net
last uploaded: Tue Oct 11 02:04:42 UTC 2016
stack: unknown
buildpack: unknown

     state     since                    cpu      memory           disk         details
#0   running   2016-10-11 01:07:34 PM   104.3%   309.3M of 512M   1.4M of 1G



You can generate an application.yml as shown below

pasapicella@pas-macbook:~$ cf create-app-manifest springboot-docker
Creating an app manifest from current settings of app springboot-docker ...

OK
Manifest file created successfully at ./springboot-docker_manifest.yml

pasapicella@pas-macbook:~$ cat springboot-docker_manifest.yml
applications:
- name: springboot-docker
  instances: 1
  memory: 512M
  disk_quota: 1024M
  host: springboot-docker-oological-superseniority
  domain: apps.pcfdemo.net
  stack: cflinuxfs2
  timeout: 180

More Information

http://docs.pivotal.io/pivotalcf/1-8/adminguide/docker.html

Monday, 10 October 2016

Displaying Pivotal Cloud Foundry application Instances Buildpacks or Docker Images using CF CLI

I was recently asked how you could display all PCF application instances detected buildpack OR docker image being used from the command line. The CF REST API gives you all of this information and more as per the documentation below to list all applications.

https://apidocs.cloudfoundry.org/244/apps/list_all_apps.html

This API call gives you lots of information so to filter that a fellow work college created this script to get just the output we want. You need to be logged into your PCF instance with "cf login" prior to running this script because it's using "CF CURL" rather then calling the REST API directly

guids=$(cf curl /v2/apps?q=space_guid:`cf space development --guid` | jq -r ".resources[].metadata.guid")
echo -e "App Name, Buildpack, Docker"
for guid in $guids; do
appName=$(cf curl /v2/apps/$guid/summary | jq -r ".name")
buildpack=$(cf curl /v2/apps/$guid/summary | jq -r ".detected_buildpack")
docker_image=$(cf curl /v2/apps/$guid/summary | jq -r ".docker_image")
echo -e "$appName," "$buildpack," "$docker_image"
done

Output:

App Name, Buildpack, Docker
guestbook-backend, null, jamesclonk/guestbook-backend:latest
springboot-docker, null, pasapples/gs-spring-boot-docker:latest
pas-albums, java-buildpack=v3.8.1-offline-https://github.com/cloudfoundry/java-buildpack.git#29c79f2 java-main java-opts open-jdk-like-jre=1.8.0_91-unlimited-crypto open-jdk-like-memory-calculator=2.0.2_RELEASE spring-auto-reconfiguration=1.10.0_RELEASE, null

To use the REST API directly replace

guids=$(cf curl /v2/apps?q=space_guid:`cf space development --guid` | jq -r ".resources[].metadata.guid")

WITH

guids=$(curl -k https://api.run.pivotal.io/v2/apps?q=space_guid:`cf space development --guid` -X GET -H "Authorization: `cf oauth-token`" | jq -r ".resources[].metadata.guid")

Thursday, 6 October 2016

Reading VCAP_SERVICES and VCAP_APPLICATION from a Spring Boot Rest Controller in PCF

Note for myself: Reading PCF System and ENV variables
  
package com.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
public class DemoRest
{
    private static final Logger logger = LoggerFactory.getLogger(DemoRest.class);

    @RequestMapping(value = "/version", method = RequestMethod.GET)
    public String version()
    {
        return "1.0";
    }

    @RequestMapping(value = "/vcapapplication", method = RequestMethod.GET)
    public Map vcapApplication() throws Exception
    {
        return Utils.getEnvMap("VCAP_APPLICATION");
    }

    @RequestMapping(value = "/vcapservices", method = RequestMethod.GET)
    public Map vcapServices() throws Exception
    {
        return Utils.getEnvMap("VCAP_SERVICES");
    }

    @RequestMapping(value = "/vcapservices_json", method = RequestMethod.GET)
    public String vcapServicesJSON() throws Exception
    {
        return System.getenv().get("VCAP_SERVICES");
    }


    @RequestMapping(value = "/appindex", method = RequestMethod.GET)
    public String appIndex() throws Exception
    {
        String instanceIndex = "N/A";

        try
        {
            instanceIndex =
                    Utils.getEnvMap("VCAP_APPLICATION").getOrDefault("instance_index", "N/A").toString();
        }
        catch (Exception ex)
        {
           logger.info("Exception getting application index : " + ex.getMessage());
        }

        return instanceIndex;
    }

    @RequestMapping(value = "/getEnvVariable/{env_var}", method = RequestMethod.GET)
    public String getEnvVariable(@PathVariable String env_var)
    {
        return System.getenv().get(env_var);
    }

} 

Utils.java (Referenced in Code above)
  
package com.example;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.HashMap;
import java.util.Map;

public class Utils
{
    public static Map getEnvMap(String vcap) throws Exception
    {
        String vcapEnv = System.getenv(vcap);
        ObjectMapper mapper = new ObjectMapper();

        if (vcapEnv != null) {
            Map<String, ?> vcapMap = mapper.readValue(vcapEnv, Map.class);
            return vcapMap;
        }

        return new HashMap<String, String>();
    }
} 

Friday, 23 September 2016

Using Oracle 12c with Pivotal Cloud Foundry Applications and Spring Boot

In this post I walk through what it would take to access Oracle 12c using a spring boot application deployed to Pivotal Cloud Foundry PCF all from my Macbook Pro. Of course this can be done outside of an isolated laptop like my Macbook Pro but handy while doing DEV/TEST and still being able to use Oracle 12c.

Requirements
  • Oracle 12c instance
  • PCFDev 
  • Git Client

1. First you will need a 12c Database and the best way to do that is to use this Oracle VM image below. I use VirtualBox to start that up and it gives me a working 12c database out of the box.

  http://www.oracle.com/technetwork/community/developer-vm/index.html#dbapp

Once imported into VirtualPort you will want to configure the Network to allow port forwarding on the database listener port of 1521 and perhaps SSH into port 22 if you need that. The 1521 Port Forward rule is vital to ensure your Macbook localhost can access the database VM using the listener port. It's setup as follows.



2. This isn't required but installing the Oracle 12c instant client will give you SQL*Plus and to me that's vital. You could use a GUI tool if that's what you like but for me SQL*Plus is more then good enough. Here is the link for Mac Os X install.

  http://www.oracle.com/technetwork/topics/intel-macsoft-096467.html

Verify Setup:

Note: I am using the IP address of my local Macbook pro. I could use "localhost" as I have setup a Port Forward rule to enable that BUT given I am using PCFDev it will need the IP address of my local Macbook pro to ensure it's talking to the right host to get to the Oracle 12c instance VM.

pasapicella@pas-macbook:~/pivotal/software/oracle$ sqlplus scott/tiger@10.47.253.3/orcl

SQL*Plus: Release 12.1.0.2.0 Production on Fri Sep 23 15:57:11 2016

Copyright (c) 1982, 2016, Oracle.  All rights reserved.

Last Successful login time: Fri Sep 23 2016 15:48:26 +10:00

Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options

SCOTT@10.47.253.3/orcl>

3. I use PCFDev and the reason is it's local to my MacBook Pro and I can get it to talk to the Oracle 12c instance easily. You can use any PCF as long as you have network access to your Oracle 12c instance.

Download from here : https://network.pivotal.io/products/pcfdev
Docs are here : https://docs.pivotal.io/pcf-dev/

At this point your ready to go , so follow these steps to test your setup

4. Clone Spring Music as follows

$ git clone https://github.com/cloudfoundry-samples/spring-music.git

5. Download the Oracle 12c JDBC driver from the location below and place it into "src/main/webapp/WEB-INF/lib" folder

  http://www.oracle.com/technetwork/database/features/jdbc/jdbc-drivers-12c-download-1958347.html

6. Package as follows

$ ./gradlew assemble

7. Now lets create a CUPS service to enable our application to bind to Oracle 12c we do that as follows

Note: It's vital we use the IP address of your local Macbook Pro as PCFDev itself is a VM which referencing "localhost" will not find the Oracle Database instance

pasapicella@pas-macbook:~/apps/pcf-dev/demos/spring-music$ cf create-user-provided-service oracle-db -p '{"uri":"oracle://scott:tiger@10.47.253.3:1521/orcl"}'
Creating user provided service oracle-db in org pcfdev-org / space pcfdev-space as admin...
OK

8. Now lets create a file called manifest-oracle.yml to use the CUPS service as shown below

---
applications:
- name: spring-music
  memory: 512M
  instances: 1
  random-route: true
  path: build/libs/spring-music.war
  services:
    - oracle-db

9. Push as follows

$ cf push -f manifest-oracle.yml

Output:

pasapicella@pas-macbook:~/apps/pcf-dev/demos/spring-music$ cf push -f manifest-oracle.yml
Using manifest file manifest-oracle.yml

Creating app spring-music in org pcfdev-org / space pcfdev-space as admin...
OK

Creating route spring-music-apiaceous-interviewer.local.pcfdev.io...
OK

Binding spring-music-apiaceous-interviewer.local.pcfdev.io to spring-music...
OK

Uploading spring-music...
Uploading app files from: /var/folders/c3/27vscm613fjb6g8f5jmc2x_w0000gp/T/unzipped-app274683538
Uploading 457K, 88 files
Done uploading
OK
Binding service oracle-db to app spring-music in org pcfdev-org / space pcfdev-space as admin...
OK

Starting app spring-music in org pcfdev-org / space pcfdev-space as admin...
Downloading binary_buildpack...
Downloading java_buildpack...
Downloading ruby_buildpack...
Downloading staticfile_buildpack...
Downloading nodejs_buildpack...
Downloading go_buildpack...
Downloading python_buildpack...
Downloading php_buildpack...
Downloaded java_buildpack
Downloaded binary_buildpack
Downloaded python_buildpack
Downloaded nodejs_buildpack
Downloaded ruby_buildpack
Downloaded go_buildpack
Downloaded staticfile_buildpack
Downloaded php_buildpack
Creating container
Successfully created container
Downloading app package...
Downloaded app package (27.5M)
Staging...
-----> Java Buildpack Version: v3.6 (offline) | https://github.com/cloudfoundry/java-buildpack.git#5194155
-----> Downloading Open Jdk JRE 1.8.0_71 from https://download.run.pivotal.io/openjdk/trusty/x86_64/openjdk-1.8.0_71.tar.gz (found in cache)
       Expanding Open Jdk JRE to .java-buildpack/open_jdk_jre (1.2s)
-----> Downloading Open JDK Like Memory Calculator 2.0.1_RELEASE from https://download.run.pivotal.io/memory-calculator/trusty/x86_64/memory-calculator-2.0.1_RELEASE.tar.gz (found in cache)
       Memory Settings: -Xmx382293K -XX:MaxMetaspaceSize=64M -Xss995K -Xms382293K -XX:MetaspaceSize=64M
-----> Downloading Spring Auto Reconfiguration 1.10.0_RELEASE from https://download.run.pivotal.io/auto-reconfiguration/auto-reconfiguration-1.10.0_RELEASE.jar (found in cache)
-----> Downloading Tomcat Instance 8.0.30 from https://download.run.pivotal.io/tomcat/tomcat-8.0.30.tar.gz (found in cache)
       Expanding Tomcat Instance to .java-buildpack/tomcat (0.1s)
-----> Downloading Tomcat Lifecycle Support 2.5.0_RELEASE from https://download.run.pivotal.io/tomcat-lifecycle-support/tomcat-lifecycle-support-2.5.0_RELEASE.jar (found in cache)
-----> Downloading Tomcat Logging Support 2.5.0_RELEASE from https://download.run.pivotal.io/tomcat-logging-support/tomcat-logging-support-2.5.0_RELEASE.jar (found in cache)
-----> Downloading Tomcat Access Logging Support 2.5.0_RELEASE from https://download.run.pivotal.io/tomcat-access-logging-support/tomcat-access-logging-support-2.5.0_RELEASE.jar (found in cache)
Exit status 0
Staging complete
Uploading droplet, build artifacts cache...
Uploading build artifacts cache...
Uploading droplet...
Uploaded build artifacts cache (108B)
Uploaded droplet (79.8M)
Uploading complete

0 of 1 instances running, 1 starting
1 of 1 instances running

App started


OK

App spring-music was started using this command `CALCULATED_MEMORY=$($PWD/.java-buildpack/open_jdk_jre/bin/java-buildpack-memory-calculator-2.0.1_RELEASE -memorySizes=metaspace:64m.. -memoryWeights=heap:75,metaspace:10,native:10,stack:5 -memoryInitials=heap:100%,metaspace:100% -totMemory=$MEMORY_LIMIT) &&  JAVA_HOME=$PWD/.java-buildpack/open_jdk_jre JAVA_OPTS="-Djava.io.tmpdir=$TMPDIR -XX:OnOutOfMemoryError=$PWD/.java-buildpack/open_jdk_jre/bin/killjava.sh $CALCULATED_MEMORY -Daccess.logging.enabled=false -Dhttp.port=$PORT" exec $PWD/.java-buildpack/tomcat/bin/catalina.sh run`

Showing health and status for app spring-music in org pcfdev-org / space pcfdev-space as admin...
OK

requested state: started
instances: 1/1
usage: 512M x 1 instances
urls: spring-music-apiaceous-interviewer.local.pcfdev.io
last uploaded: Fri Sep 23 06:14:54 UTC 2016
stack: unknown
buildpack: java-buildpack=v3.6-offline-https://github.com/cloudfoundry/java-buildpack.git#5194155 open-jdk-like-jre=1.8.0_71 open-jdk-like-memory-calculator=2.0.1_RELEASE spring-auto-reconfiguration=1.10.0_RELEASE tomcat-access-logging-support=2.5.0_RELEASE tomca...

     state     since                    cpu    memory         disk           details
#0   running   2016-09-23 04:15:22 PM   0.0%   844K of 512M   452K of 512M

10. Verify from SQL*Plus it has created the table ALBUM in the SCOTT schema as shown below
  
SCOTT@10.47.253.3:1521/orcl> describe album;
 Name           Null?    Type
 ----------------------------------------------------------------- -------- --------------------------------------------
 ID           NOT NULL VARCHAR2(40 CHAR)
 ALBUMID            VARCHAR2(255 CHAR)
 ARTIST             VARCHAR2(255 CHAR)
 GENRE             VARCHAR2(255 CHAR)
 RELEASEYEAR            VARCHAR2(255 CHAR)
 TITLE             VARCHAR2(255 CHAR)
 TRACKCOUNT          NOT NULL NUMBER(10)

SCOTT@10.47.253.3:1521/orcl>  

11. Test application in a browser




Thursday, 22 September 2016

Using H2 Console in development with Spring Boot then NOT when deployed to Pivotal Cloud Foundry

Frequently when developing Spring based applications, I will use the H2 in memory database during your development process. H2 ships with a web based database console, which you can use while your application is under development. It is a convenient way to view the tables created by Hibernate and run queries against the in memory database. In this post I show what is required to set this up as well as what it means to then deploy your Spring Boot applications to Pivotal Cloud Foundry and rely on a database service and hence your application becomes cloud aware.

1. First ensure you have included the H2 maven dependency as shown below. I also use DevTools BUT thats not needed to enable the H2 web console
  
  <dependency>
   <groupId>com.h2database</groupId>
   <artifactId>h2</artifactId>
  </dependency>
2. Then create an specific application.yml file while in development mode only and enable the H2 web console. Using the default name "application.yml"will ensure while your in DEV mode it will use that file. Notice how I give the database a name rather then use the default and also specify a datasource you don't need to go to that effort BUT to me it's good practice to define a datasource because it is what you will do for an application itself when not in DEV mode.

application.yml

server:
  error:
    whitelabel:
      enabled: false

spring:
  h2:
    console:
      enabled: true
  jpa:
    hibernate:
      ddl-auto: create
  datasource:
    url: jdbc:h2:mem:apples;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
    username: sa
    password:
    driver-class-name: org.h2.Driver
    platform: h2

3. Run your spring boot application

....
2016-09-22 21:30:26.771  INFO 18929 --- [  restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2016-09-22 21:30:26.778  INFO 18929 --- [  restartedMain] gBootJpaBootstrapEmployeeDemoApplication : Started SpringBootJpaBootstrapEmployeeDemoApplication in 6.021 seconds (JVM running for 6.553)

4. Connect to the H2 we console as follows

http://localhost:8080/h2-console/

The JDBC Url now becomes what you set in the dialog above, inshort the DB name I set was "apples"



When it comes to deployment in Pivotal Cloud Foundry (PCF) you most likely will not want to use H2 and instead bind to a database service like MySQL for example. To do that we would alter our project as follows.

5. Add the following maven dependancies. I add MySQL dependency and you can leave H2 as it will use that if it doesn't finda MySQL service instance to bind to. I also add "spring-boot-starter-cloud-connectors" as it's this which automatically creates and configures a DataSource which injects the service details at Runtime for me.
  
  <dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-cloud-connectors</artifactId>
  </dependency>

6. Add a specific cloud application YML file named "application-cloud.yml" as follows. I have left out a datasource and Spring Boot will create that for me when bound to the database service, BUT generally I always set the datasource with the correct properties required to meet my application requirements.

application-cloud.yml

spring:
  jpa:
    hibernate:
      ddl-auto: create

server:
  error:
    whitelabel:
      enabled: false

7. When creating a manifest.yml file to deploy your application to PCF all you need to do is add a MySQL database service and specify the active profile as CLOUD as shown below which will ensure we use the "application-cloud.yml" file we created above.

manifest.yml

---
applications:
- name: springboot-bootstrap-employee
  memory: 512M
  instances: 1
  random-route: true
  timeout: 180
  path: ./target/springbootjpabootstrapemployeedemo-0.0.1-SNAPSHOT.jar
  services:
    - pas-mysql
  env:
    JAVA_OPTS: -Djava.security.egd=file:///dev/urando
    SPRING_PROFILES_ACTIVE: cloud

The project in IntelliJ is as follows


GitHub URL as follows:

https://github.com/papicella/SpringBootJPABootstrapEmployeeDemo

Tuesday, 20 September 2016

Spring Boot on Google Cloud Platform (GCP)

I recently created a demo which can be used to deploy a basic Spring Boot application on Google Cloud Platform (GCP). There isn't really anything specific in the code to make this work on GCP BUT the maven pom.xml has what is required to make it one simple command to send this app to GCP.

$ mvn gcloud:deploy

You can run an App Engine application in two environments, the standard environment and the flexible environment. This is an example of Java with Spring Boot in the App Engine [Flexible Environment]. The following table summarizes some of the differences between the two environments.


Feature                     Standard environment        Flexible environment
---------------------------------------------------------------------------------------------------------
Instance startup time       Milliseconds                Minutes
Scaling                     Manual, Basic, Automatic    Manual, Automatic
Writing to local disk       No                          Yes, ephemeral (disk initialized on each VM startup)
Customizable serving stack  No                          Yes (built by customizing a Dockerfile)
First time deployment may take several minutes. This is because App Engine Flexible environment will automatically provision a Google Compute Engine virtual machine for you behind the scenes to run this application.

GitHub URL:

https://github.com/papicella/PivotalSpringBoot


Monday, 12 September 2016

Pivotal MySQL*Web - Web Based Spring Boot / Bootstrap Application for Pivotal MySQL tile (p-mysql)

I have been recently working on a web based interface to Pivotal MySQL Tile which can be deployed to Pivotal Cloud Foundry and bound to a p-mysql service instance for instant access to the MySQL DB. Known as PivotalMySQL*Web this is a browser based SQL tool rendered using Bootstrap UI for MySQL PCF service instances which allows you to run SQL commands and view schema objects from a browser based interface. It includes the following capabilities

  • Multiple Command SQL worksheet for DDL and DML
  • Run Explain Plan across SQL Statements
  • View/Run DDL command against Tables/Views/Indexes/Constraints
  • Command History
  • Auto Bind to Pivotal MySQL Services bound to the Application within Pivotal Cloud Foundry (PCF)
  • Manage JDBC Connections
  • Load SQL File into SQL Worksheet from Local File System
  • SQL Worksheet with syntax highlighting support
You can read more about it as the GitHub project as follows and of course clone or fork the code if you wish and deploy it your Pivotal Cloud Foundry instance. When bound to a p-mysql service instance it will automatically connect to the instance without promoting for connect details.

I would welcome feedback here as this is a WIP which I am adding features to as often as I can


Some screen shots below








JHipster, Spring Boot, AngularJS and finally deployed to Pivotal Cloud Foundry

I have known about JHipster for a while and thought I would finally give it a test drive and deploy a simple scaffolded app to Pivotal Cloud Foundry. In this post I will use the p-mysql (Pivotal MySQL) rather then the ClearDB instance.



1. I created a very basic "Monolithic" application as shown below.

pasapicella@pas-macbook:~/pivotal/software/jhipster/apps/employee-mysql-jhipster$ yo jhipster

.....

                            http://jhipster.github.io

Welcome to the JHipster Generator v3.6.1
Documentation for creating an application: https://jhipster.github.io/creating-an-app/
Application files will be generated in folder: /Users/pasapicella/pivotal/software/jhipster/apps/employee-mysql-jhipster
? (1/16) Which *type* of application would you like to create? Monolithic application (recommended for simple projects)
? (2/16) What is the base name of your application? employee_mysql_jhipster
? (3/16) What is your default Java package name? pas.pivotal.jhipster.employee
? (4/16) Which *type* of authentication would you like to use? HTTP Session Authentication (stateful, default Spring Security mechanism)
? (5/16) Do you want to use social login (Google, Facebook, Twitter)? Warning, this doesn't work with Cassandra! No
? (6/16) Which *type* of database would you like to use? SQL (H2, MySQL, MariaDB, PostgreSQL, Oracle)
? (7/16) Which *production* database would you like to use? MySQL
? (8/16) Which *development* database would you like to use? MySQL
? (9/16) Do you want to use Hibernate 2nd level cache? No
? (10/16) Do you want to use a search engine in your application? No
? (11/16) Do you want to use clustered HTTP sessions? No
? (12/16) Do you want to use WebSockets? No
? (13/16) Would you like to use Maven or Gradle for building the backend? Maven
? (14/16) Would you like to use the LibSass stylesheet preprocessor for your CSS? No
? (15/16) Would you like to enable internationalization support? Yes
? Please choose the native language of the application? English
? Please choose additional languages to install Italian
? (16/16) Which testing frameworks would you like to use? (Press to select)Gatling

Installing languages: en, it

....

2. This creates a lot of scaffold code and I have intentionally said I want to use MySQL so I can then bind to a p-mysql instance when I use the PROD profile shortly. For now lets add a single entity as shown below.

pasapicella@pas-macbook:~/pivotal/software/jhipster/apps/employee-mysql-jhipster$ yo jhipster:entity dept

The entity dept is being created.


Generating field #1

? Do you want to add a field to your entity? Yes
? What is the name of your field? deptno
? What is the type of your field? Long
? Do you want to add validation rules to your field? No

================= Dept =================
Fields
deptno (Long)


Generating field #2

? Do you want to add a field to your entity? Yes
? What is the name of your field? dname
? What is the type of your field? String
? Do you want to add validation rules to your field? No

================= Dept =================
Fields
deptno (Long)
dname (String)


Generating field #3

? Do you want to add a field to your entity? Yes
? What is the name of your field? loc
? What is the type of your field? String
? Do you want to add validation rules to your field? No

================= Dept =================
Fields
deptno (Long)
dname (String)
loc (String)


Generating field #4

? Do you want to add a field to your entity? No

================= Dept =================
Fields
deptno (Long)
dname (String)
loc (String)


Generating relationships to other entities

? Do you want to add a relationship to another entity? No

================= Dept =================
Fields
deptno (Long)
dname (String)
loc (String)



? Do you want to use a Data Transfer Object (DTO)? No, use the entity directly
? Do you want to use separate service class for your business logic? No, the REST controller should use the repository directly
? Do you want pagination on your entity? Yes, with a simple pager

Everything is configured, generating the entity...

....

3. Before you can run this have to do a few things, as shown below.

3.1. Create a database for the application

mysql> create database employee_mysql_jhipster;
Query OK, 1 row affected (0.00 sec)

3.2. Set the password / username you wish to use for me I used my local MYSQL database root user as it's just dev. The file is "./src/main/resources/config" where the application specific profiles exist, in this case all you need to do is edit the "application-dev.yml"

....

datasource:
    type: com.zaxxer.hikari.HikariDataSource
    url: jdbc:mysql://localhost:3306/employee_mysql_jhipster?useUnicode=true&characterEncoding=utf8&useSSL=false
    name:
    username: root
    password: welcome1
    hikari:
        data-source-properties:
            cachePrepStmts: true
            prepStmtCacheSize: 250
            prepStmtCacheSqlLimit: 2048
            useServerPrepStmts: true

....

3.2 You can now run in DEV mode the default profile if you don't select anything and test locally.

/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/bin/java -Dspring.output.ansi.enabled=always -Didea.launcher.port=7533 "-Didea.launcher.bin.path=/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath 

....

:: JHipster 🤓  :: Running Spring Boot 1.4.0.RELEASE ::
:: http://jhipster.github.io ::

2016-09-12 11:47:12.327  INFO 5450 --- [           main] p.p.j.employee.EmployeeMysqlJhipsterApp  : Starting EmployeeMysqlJhipsterApp on pas-macbook with PID 5450 (/Users/pasapicella/pivotal/software/jhipster/apps/employee-mysql-jhipster/target/classes started by pasapicella in /Users/pasapicella/pivotal/software/jhipster/apps/employee-mysql-jhipster)
 :

...

----------------------------------------------------------
Application 'employee_mysql_jhipster' is running! Access URLs:
Local: http://127.0.0.1:8080
External: http://127.0.0.1:8080
----------------------------------------------------------

4. At this point we can deploy out application to Pivotal Cloud Foundry BUT before we do that lets ensure we have what we need



4.1. Ensure a p-mysql service exists as shown below.



4.2. Package the PROD profile as shown below

pasapicella@pas-macbook:~/pivotal/software/jhipster/apps/employee-mysql-jhipster$ ./mvnw package -DskipTests=true -B -Pprod
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Employee Mysql Jhipster 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:3.0.1:copy-resources (default-resources) @ employee-mysql-jhipster ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 8 resources
[INFO] Copying 12 resources
[INFO]
[INFO] --- maven-resources-plugin:3.0.1:resources (default-resources) @ employee-mysql-jhipster ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 8 resources
[INFO] Copying 12 resources
[INFO]
[INFO] --- maven-enforcer-plugin:1.4.1:enforce (enforce-versions) @ employee-mysql-jhipster ---
[INFO]
[INFO] --- jacoco-maven-plugin:0.7.7.201606060606:prepare-agent (pre-unit-tests) @ employee-mysql-jhipster ---
[INFO] surefireArgLine set to -javaagent:/Users/pasapicella/.m2/repository/org/jacoco/org.jacoco.agent/0.7.7.201606060606/org.jacoco.agent-0.7.7.201606060606-runtime.jar=destfile=/Users/pasapicella/pivotal/software/jhipster/apps/employee-mysql-jhipster/target/test-results/coverage/jacoco/jacoco.exec
[INFO]
[INFO] --- maven-processor-plugin:2.2.4:process (process) @ employee-mysql-jhipster ---
[INFO]
[INFO] --- frontend-maven-plugin:1.0:install-node-and-npm (install node and npm) @ employee-mysql-jhipster ---
[INFO] Node v4.4.7 is already installed.
[INFO] NPM 3.10.5 is already installed.
[INFO]
[INFO] --- frontend-maven-plugin:1.0:npm (npm install) @ employee-mysql-jhipster ---
[INFO] Running 'npm install' in /Users/pasapicella/pivotal/software/jhipster/apps/employee-mysql-jhipster
[INFO]
[INFO] --- frontend-maven-plugin:1.0:bower (bower install) @ employee-mysql-jhipster ---
[INFO] Running 'bower install --no-color' in /Users/pasapicella/pivotal/software/jhipster/apps/employee-mysql-jhipster
[INFO]
[INFO] --- frontend-maven-plugin:1.0:gulp (gulp build) @ employee-mysql-jhipster ---
[INFO] Running 'gulp.js build --no-notification' in /Users/pasapicella/pivotal/software/jhipster/apps/employee-mysql-jhipster
[INFO] [14:51:23] Using gulpfile ~/pivotal/software/jhipster/apps/employee-mysql-jhipster/gulpfile.js
[INFO] [14:51:23] Starting 'clean'...
[INFO] [14:51:23] Finished 'clean' after 22 ms
[INFO] [14:51:23] Starting 'build'...
[INFO] [14:51:23] Starting 'copy:i18n'...
[INFO] [14:51:23] Starting 'copy:fonts'...
[INFO] [14:51:23] Starting 'copy:common'...
[INFO] [14:51:23] Starting 'inject:vendor'...
[INFO] [14:51:23] Starting 'ngconstant:prod'...
[INFO] [14:51:23] Starting 'copy:languages'...
[INFO] [14:51:23] Finished 'ngconstant:prod' after 69 ms
[INFO] [14:51:23] gulp-inject 23 files into index.html.
[INFO] [14:51:23] Finished 'copy:languages' after 61 ms
[INFO] [14:51:23] Finished 'copy:common' after 142 ms
[INFO] [14:51:23] Finished 'inject:vendor' after 140 ms
[INFO] [14:51:23] Finished 'copy:fonts' after 193 ms
[INFO] [14:51:23] Finished 'copy:i18n' after 409 ms
[INFO] [14:51:23] Starting 'copy'...
[INFO] [14:51:23] Finished 'copy' after 8 μs
[INFO] [14:51:23] Starting 'inject:app'...
[INFO] [14:51:23] gulp-inject 108 files into index.html.
[INFO] [14:51:23] Finished 'inject:app' after 245 ms
[INFO] [14:51:23] Starting 'inject:troubleshoot'...
[INFO] [14:51:23] gulp-inject Nothing to inject into index.html.
[INFO] [14:51:23] Finished 'inject:troubleshoot' after 2.49 ms
[INFO] [14:51:23] Starting 'images'...
[INFO] [14:51:23] Starting 'styles'...
[INFO] [14:51:23] Starting 'html'...
[INFO] [14:51:23] Starting 'copy:swagger'...
[INFO] [14:51:23] Starting 'copy:images'...
[INFO] [14:51:23] Finished 'copy:images' after 10 ms
[INFO] [14:51:23] Finished 'styles' after 23 ms
[INFO] [14:51:24] Finished 'html' after 470 ms
[INFO] [14:51:24] Finished 'copy:swagger' after 560 ms
[INFO] [14:51:24] gulp-imagemin: Minified 3 images (saved 0 B - 0%)
[INFO] [14:51:24] Finished 'images' after 718 ms
[INFO] [14:51:24] Starting 'assets:prod'...
[INFO] [14:51:35] Finished 'assets:prod' after 11 s
[INFO] [14:51:35] Finished 'build' after 12 s
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ employee-mysql-jhipster ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 91 source files to /Users/pasapicella/pivotal/software/jhipster/apps/employee-mysql-jhipster/target/classes
[INFO]
[INFO] --- maven-resources-plugin:3.0.1:testResources (default-testResources) @ employee-mysql-jhipster ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ employee-mysql-jhipster ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.18.1:test (default-test) @ employee-mysql-jhipster ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- jacoco-maven-plugin:0.7.7.201606060606:report (post-unit-test) @ employee-mysql-jhipster ---
[INFO] Loading execution data file /Users/pasapicella/pivotal/software/jhipster/apps/employee-mysql-jhipster/target/test-results/coverage/jacoco/jacoco.exec
[INFO] Analyzed bundle 'Employee Mysql Jhipster' with 100 classes
[INFO]
[INFO] --- frontend-maven-plugin:1.0:gulp (gulp test) @ employee-mysql-jhipster ---
[INFO] Skipping test phase.
[INFO]
[INFO] --- maven-war-plugin:2.6:war (default-war) @ employee-mysql-jhipster ---
[INFO] Packaging webapp
[INFO] Assembling webapp [employee-mysql-jhipster] in [/Users/pasapicella/pivotal/software/jhipster/apps/employee-mysql-jhipster/target/employee-mysql-jhipster-0.0.1-SNAPSHOT]
[INFO] Processing war project
[INFO] Copying webapp resources [/Users/pasapicella/pivotal/software/jhipster/apps/employee-mysql-jhipster/target/www]
[INFO] Webapp assembled in [663 msecs]
[INFO] Building war: /Users/pasapicella/pivotal/software/jhipster/apps/employee-mysql-jhipster/target/employee-mysql-jhipster-0.0.1-SNAPSHOT.war
[INFO]
[INFO] --- spring-boot-maven-plugin:1.4.0.RELEASE:repackage (default) @ employee-mysql-jhipster ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 56.889 s
[INFO] Finished at: 2016-09-12T14:51:48+10:00
[INFO] Final Memory: 52M/441M
[INFO] ------------------------------------------------------------------------

5. Lets create a manifest.yml file to deploy our application in the root directory of the project

manifest-cf.yml

---
path: ./target/employee-mysql-jhipster-0.0.1-SNAPSHOT.war
instances: 1
buildpack: https://github.com/cloudfoundry/java-buildpack
services:
- pas-mysql
applications:
- name: employeemysqljhipster
  env:
    SPRING_PROFILES_ACTIVE: prod, cloudfoundry

6. Deploy as follows

pasapicella@pas-macbook:~/pivotal/software/jhipster/apps/employee-mysql-jhipster$ cf push -f manifest-cf.yml
Using manifest file manifest-cf.yml

Creating app employeemysqljhipster in org pivot-papicella / space development as papicella@pivotal.io...
OK

Creating route employeemysqljhipster.cfapps.pez.pivotal.io...
OK

Binding employeemysqljhipster.cfapps.pez.pivotal.io to employeemysqljhipster...
OK

Uploading employeemysqljhipster...
Uploading app files from: /var/folders/c3/27vscm613fjb6g8f5jmc2x_w0000gp/T/unzipped-app797077453
Uploading 25.1M, 3361 files
Done uploading
OK
Binding service pas-mysql to app employeemysqljhipster in org pivot-papicella / space development as papicella@pivotal.io...
OK

Starting app employeemysqljhipster in org pivot-papicella / space development as papicella@pivotal.io...
Creating container
Successfully created container
Downloading app package...
Downloaded app package (47.5M)
Staging...
-----> Java Buildpack Version: 1447aa9 | https://github.com/cloudfoundry/java-buildpack#1447aa9
-----> Downloading Open Jdk JRE 1.8.0_101 from https://java-buildpack.cloudfoundry.org/openjdk/trusty/x86_64/openjdk-1.8.0_101.tar.gz (4.6s)
       Expanding Open Jdk JRE to .java-buildpack/open_jdk_jre (1.3s)
-----> Downloading Open JDK Like Memory Calculator 2.0.2_RELEASE from https://java-buildpack.cloudfoundry.org/memory-calculator/trusty/x86_64/memory-calculator-2.0.2_RELEASE.tar.gz (0.6s)
       Memory Settings: -Xms681574K -XX:MetaspaceSize=104857K -Xmx681574K -XX:MaxMetaspaceSize=104857K -Xss349K
-----> Downloading Container Customizer 1.0.0_RELEASE from https://java-buildpack.cloudfoundry.org/container-customizer/container-customizer-1.0.0_RELEASE.jar (0.3s)
-----> Downloading Spring Auto Reconfiguration 1.10.0_RELEASE from https://java-buildpack.cloudfoundry.org/auto-reconfiguration/auto-reconfiguration-1.10.0_RELEASE.jar (0.7s)
Exit status 0
Staging complete
Uploading droplet, build artifacts cache...
Uploading build artifacts cache...
Uploading droplet...
Uploaded build artifacts cache (44.9M)
Uploaded droplet (91.3M)
Uploading complete
Destroying container
Successfully destroyed container

0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
1 of 1 instances running

App started


OK

App employeemysqljhipster was started using this command `CALCULATED_MEMORY=$($PWD/.java-buildpack/open_jdk_jre/bin/java-buildpack-memory-calculator-2.0.2_RELEASE -memorySizes=metaspace:64m..,stack:228k.. -memoryWeights=heap:65,metaspace:10,native:15,stack:10 -memoryInitials=heap:100%,metaspace:100% -stackThreads=300 -totMemory=$MEMORY_LIMIT) && JAVA_OPTS="-Djava.io.tmpdir=$TMPDIR -XX:OnOutOfMemoryError=$PWD/.java-buildpack/open_jdk_jre/bin/killjava.sh $CALCULATED_MEMORY" && SERVER_PORT=$PORT eval exec $PWD/.java-buildpack/open_jdk_jre/bin/java $JAVA_OPTS -cp $PWD/. org.springframework.boot.loader.WarLauncher`

Showing health and status for app employeemysqljhipster in org pivot-papicella / space development as papicella@pivotal.io...
OK

requested state: started
instances: 1/1
usage: 1G x 1 instances
urls: employeemysqljhipster.cfapps.pez.pivotal.io
last uploaded: Mon Sep 12 03:07:29 UTC 2016
stack: unknown
buildpack: https://github.com/cloudfoundry/java-buildpack

     state     since                    cpu      memory         disk           details
#0   running   2016-09-12 01:09:09 PM   126.5%   546.4M of 1G   200.7M of 1G

Some screen shots of what a JHipster basic application looks like, it has alot for very little effort and a great starting point for a full stack development project. 


How about Italian?


Basic View departments CRUD page





More Information