Creating a Java Application Using the Caching REST API in Oracle Application Container Cloud Service


Options



Before You Begin

Purpose

This tutorial shows you how to develop a standalone web service with Jersey and Grizzly, and how to integrate the caching feature of Oracle Application Container Cloud Service using the REST API.

Time to Complete

30 minutes approximately

Background

The new caching capability of Oracle Application Container Cloud Service allows applications to accelerate access to data, share data among applications, and off-load state management.

The caching feature of Oracle Application Container Cloud Service can be accessed from your application through the REST API.  The REST API defines the following endpoints: 

Method URL Description
GET /ccs/{cacheName}/{key} Retrieves the value associated with the specified key
PUT /ccs/{cacheName}/{key} Stores the value and associates it with the specified key
POST /ccs/{cacheName}/{key} Issues one of the following: putIfAbsent, replace, or removeValue
DELETE /ccs/{cacheName}/{key} Deletes a key/value pair from a cache
GET /ccs/{cacheName} Returns the server-side metrics for the specified cache.
DELETE /ccs/{cacheName} Clears the specified cache.

The caching REST API uses JSON as data the exchange format.

Scenario

In this tutorial, you create a self-contained application using Jersey and Grizzly. The application implements the CRUD (Create, Read, Update, and Delete) operations on an employee object. Each operation implements the caching feature of Oracle Application Container Cloud Service. You use Maven to resolve the application dependencies and create the archive to deploy the application on Oracle Application Container Cloud Service. You test the REST service by using an HTML client developed with Angular and Bootstrap. This tutorial doesn't cover how to implement the client. The client project is provided in the "What do You Need?" section.

What Do You Need?

Creating a Caching Service

  1. In a web browser, go to https://cloud.oracle.com/home and click Sign In.
  2. From the Cloud Account menu, select Traditional Cloud Account, select your data center, and click My Services.
  3. Enter your identity domain and click Go.
  4. Enter your cloud account credentials and click Sign In.
  5. In the Oracle Cloud My Services dashboard, click Action Action menu icon, click Services, and select Application Container.
  6. Click Menu and select Application Cache.
  7. Click Create Instance.
  8. In the Service Name field enter MyCachingService, keep the default values, and then click Next:
    Create Application Cache page
    Description of this image
  9. In the Confirmation page, click Create.

Creating the Web Service

  1. Open a command-line window (or a terminal in Linux).

  2. Go to the directory where the new project will reside.

  3. Create the Jersey application:

    mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-grizzly2 -DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false -DgroupId=com.example.caching -DartifactId=jersey-service-caching -Dpackage=com.example.caching -DarchetypeVersion=2.25
  4. Open the pom.xml file located in the root directory (jersey-service-caching) in a text editor.

  5. Update the Maven Compiler Plugin to use the JDK 1.8.

    <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <version>2.5.1</version>
         <inherited>true</inherited>
         <configuration>
                <source>1.8</source>
                <target>1.8</target>
         </configuration>
    </plugin>
  6. Add the jersey-media-json-jackson dependency inside the <dependencies> tags, and then save and close the file.

    <dependency>
    	<groupId>org.glassfish.jersey.media</groupId>
    	<artifactId>jersey-media-json-jackson</artifactId>
    </dependency> 
  7. In the com.example.accs.caching package, create the Employee class.

    The Employee class is a Plain Old Java Object (POJO) that contains the employee properties and their getters and setters methods to access to the properties.

    /* Copyright © 2018 Oracle and/or its affiliates. All rights reserved. */
    package com.example.caching;
    
    import com.fasterxml.jackson.annotation.JsonProperty;
    
    public class Employee {
    
        private long id;
        private String firstName;
        private String lastName;
        private String birthDate;
        private String title;
        private String dept;
        private String email;
        private String phone;
    
        private static int countId = 0;
        
        public Employee() {
        }   
    
        public Employee(String firstName, String lastName, String birthDate,
                String title, String dept, String email, String phone) {
            countId++;
            this.id = countId;
            this.firstName = firstName;
            this.lastName = lastName;
            this.birthDate = birthDate;
            this.title = title;
            this.dept = dept;
            this.email = email;
            this.phone = phone;
        }
    
        public Employee(long id, String firstName, String lastName, String birthDate,
                String title, String dept, String email, String phone) {
            this(firstName, lastName, birthDate, title, dept, email, phone);
            this.id = id;
        }
    
        @JsonProperty
        public long getId() {
            return id;
        }
    
        public void setId(long id) {
            this.id = id;
        }
    
        @JsonProperty
        public String getFirstName() {
            return firstName;
        }
    
        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }
    
        @JsonProperty
        public String getLastName() {
            return lastName;
        }
    
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
    
        @JsonProperty
        public String getBirthDate() {
            return birthDate;
        }
    
        public void setBirthDate(String birthDate) {
            this.birthDate = birthDate;
        }
    
        @JsonProperty
        public String getTitle() {
            return title;
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        @JsonProperty
        public String getDept() {
            return dept;
        }
    
        public void setDept(String dept) {
            this.dept = dept;
        }
    
        @JsonProperty
        public String getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    
        @JsonProperty
        public String getPhone() {
            return phone;
        }
    
        public void setPhone(String phone) {
            this.phone = phone;
        }
    }
    
  8. Create the EmployeeList class.

    The EmployeeList class is a helper class designed to store the employee records in memory and preload a few records.

    /* Copyright © 2017 Oracle and/or its affiliates. All rights reserved. */
    package com.example.caching;
    
    import java.util.concurrent.CopyOnWriteArrayList;
    
    
    public class EmployeeList {
        private static final CopyOnWriteArrayList<Employee> employeeList = new CopyOnWriteArrayList<>();
        
        private EmployeeList(){
        }
        
        static{
            employeeList.add(new Employee("John","Smith","12-12-1980","Manager","Sales","john.smith@example.com","923-814-0502"));
            employeeList.add(new Employee("Laura","Adams","02-11-1979","Manager","IT","laura.adams@example.com","293-596-3547"));
            employeeList.add(new Employee("Peter","Williams","22-10-1966","Coordinator","HR","peter.williams@example.com","923-814-0502"));
            employeeList.add(new Employee("Joana","Sanders","11-11-1976","Manager","Marketing","joana.sanders@example.com","730-715-4446"));
            employeeList.add(new Employee("John","Drake","18-08-1988","Coordinator","Finance","john.drake@example.com","769-569-1789"));
            employeeList.add(new Employee("Samuel","Williams","22-03-1985","Coordinator","Finance","samuel.williams@example.com","429-071-2018"));
        }
        
        public static CopyOnWriteArrayList <Employee> getInstance(){
            return employeeList;
        }
    }
  9. Create the EmployeeDAO class.

    The EmployeeDAO class isn't a real DAO, it simulates the persistence layer in the application. It contains the basic methods found in a DAO. However, instead of using a database, it stores data in memory to keep the example simple.

    /* Copyright © 2017 Oracle and/or its affiliates. All rights reserved. */
    package com.example.caching;
    
    import java.util.List;
    import java.util.Optional;
    import java.util.concurrent.CopyOnWriteArrayList;
    import java.util.function.Predicate;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import java.util.stream.Collectors;
    import javax.ws.rs.core.Response;
    
    public class EmployeeDAO {
    
        private final CopyOnWriteArrayList<Employee> employeeList = EmployeeList.getInstance();
        private final static Logger LOGGER = Logger.getLogger(EmployeeDAO.class.getName());
    
        public Employee[] getAll() {
            LOGGER.log(Level.INFO, "EmployeeDao getAll method");
            return employeeList.toArray(new Employee[0]);
        }
    
        public Employee findById(long id) {
            LOGGER.log(Level.INFO, "EmployeeDao getById method");
            Optional<Employee> match
                    = employeeList.stream()
                    .filter(e -> e.getId() == id)
                    .findFirst();
            if (match.isPresent()) {
                return match.get();
            } else {
                return null;
            }
        }
    
        public List<Employee> findByLastName(String lastName) {
            LOGGER.log(Level.INFO, "EmployeeDao findByLastName method");
            List<Employee> employees
                    = employeeList.stream()
                    .filter(e -> e.getLastName().equals(lastName))
                    .collect(Collectors.toList());
            return employees;
        }
    
        public List<Employee> findByDepartment(String department) {
            LOGGER.log(Level.INFO, "EmployeeDao findByLastName method");
            List<Employee> employees
                    = employeeList.stream()
                    .filter(e -> e.getDept().equals(department))
                    .collect(Collectors.toList());
            return employees;
        }
    
        public List<Employee> findByTitle(String title) {
            LOGGER.log(Level.INFO, "EmployeeDao findByTitle method");
            List<Employee> employees = employeeList.stream()
                    .filter(e -> e.getTitle().equals(title)).collect(Collectors.toList());
            return employees;
        }
    
        public Response insert(Employee employee) {
            LOGGER.log(Level.INFO, "EmployeeDao insert method");
            employeeList.add(employee);
            return Response.status(201).build();
        }
    
        public boolean update(long id, Employee employee) {
            LOGGER.log(Level.INFO, "EmployeeDao update method");
            int matchIdx = 0;
            Optional<Employee> match = employeeList.stream()
                    .filter(e -> e.getId() == id)
                    .findFirst();
            if (match.isPresent()) {
                matchIdx = employeeList.indexOf(match.get());
                employeeList.set(matchIdx, employee);
                return true;
            } else {
                return false;
            }
        }
    
        public boolean delete(long id) {
            LOGGER.log(Level.INFO, "EmployeeDao delete method " + id);
            Predicate<Employee> employee = e -> e.getId() == id;
            if (!employeeList.removeIf(employee)) {
                LOGGER.log(Level.INFO,"Employee removed");
                return false;
            } else {
                return true;
            }
        }
    }
    
    
  10. Create the EmployeeResource class.

    The EmployeeResource class defines the endpoint /employees and responds to the GET, POST, DELETE, and PUT HTTP methods.

    /* Copyright © 2017 Oracle and/or its affiliates. All rights reserved. */
    package com.example.caching;
    
    import java.util.List;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.ws.rs.DELETE;
    import javax.ws.rs.GET;
    import javax.ws.rs.NotFoundException;
    import javax.ws.rs.POST;
    import javax.ws.rs.PUT;
    import javax.ws.rs.Path;
    import javax.ws.rs.PathParam;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;
    
    @Path("/employees")
    public class EmployeeResource {
        private final static Logger LOGGER = Logger.getLogger(EmployeeResource.class.getName());
        private final EmployeeDAO employeeDao = new EmployeeDAO();
    
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public Response getAllEmployees() {
            LOGGER.log(Level.INFO, "GET Method");        
            return Response.ok(employeeDao.getAll()) //200
                    .build();
        }
    
        @GET
        @Path("{id}")
        @Produces(MediaType.APPLICATION_JSON)
        public Response getEmployee(@PathParam("id") long id) {
            LOGGER.log(Level.INFO, "GET Method by ID");      
            Employee employee = employeeDao.findById(id);
                  
            return Response.ok(employee) //200
                    .build();
        }
        
        @GET
        @Path("{searchCriteria}/{searchValue}")
        public Response searchEmployees(@PathParam("searchCriteria") String searchCriteria, @PathParam("searchValue") String searchValue) throws Exception {
            List<Employee> employees = null;
            if (searchCriteria.equals("title")) {
                employees = employeeDao.findByTitle(searchValue);
            } else if (searchCriteria.equals("lastname")) {
                employees = employeeDao.findByLastName(searchValue);
            } else if (searchCriteria.equals("department")) {
                employees = employeeDao.findByDepartment(searchValue);
            } else {
                throw new Exception("Filter criteria not valid");
            }
    
            return Response.ok() //200
                    .entity(employees.toArray(new Employee[0]))
                    .build();
        }
    
        @POST
        @Produces(MediaType.APPLICATION_JSON)
        public Response addEmployee(Employee employee) {
            LOGGER.log(Level.INFO, "POST Method");
            employeeDao.insert(employee);
            return Response.status(201)
                    .build();
        }
    
        @PUT
        @Path("{id}")
        @Produces(MediaType.APPLICATION_JSON)
        public Response updateEmployee(@PathParam("id") long id, Employee employee) {
            LOGGER.log(Level.INFO, "PUT Method {0}", id);
            boolean response = employeeDao.update(id, employee);
            if (response) {
                return Response.status(Response.Status.OK)
                        .build();
            } else {
                return Response.status(Response.Status.NOT_FOUND).build();
            }
        }
    
        @DELETE
        @Path("{id}")
        public void deleteEmployee(@PathParam("id") long id) {
            LOGGER.log(Level.INFO, "DELETE Method {0}", id);
            boolean response = employeeDao.delete(id);      
            if (!response) {
                throw new NotFoundException("Error Employee " + id + " not found");
            } 
        }
    }
    
    
  11. Create the CrossOriginEmployeeFilter class.

    Browsers and applications usually prevent calling REST services from different sources. Thus, if you run the client on Server A and the REST services on Server B, then you must provide a list of known clients in Server B by using the Access-Control headers. Clients check these headers to allow invocation of a service. This is used to prevent cross-site scripting attacks (XSS). To allow external clients to make calls to our application, we create a filter to add the headers to the response.

    /* Copyright © 2017 Oracle and/or its affiliates. All rights reserved. */
    package com.example.caching;
    
    import java.io.IOException;
    import javax.ws.rs.container.ContainerRequestContext;
    import javax.ws.rs.container.ContainerResponseContext;
    import javax.ws.rs.container.ContainerResponseFilter;
    import javax.ws.rs.ext.Provider;
    
    @Provider
    public class CrossOriginEmployeeFilter implements ContainerResponseFilter{
    
        @Override
        public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
            responseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
            responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS");
            responseContext.getHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
            responseContext.getHeaders().add("Access-Control-Allow-Credentials", "true");
        } 
    }
  12. Open the Main class, and in the startServer method, register the CrossOriginEmployeeFilter class filter.

    public static HttpServer startServer() {
            final ResourceConfig rc = new ResourceConfig().packages("com.example.caching ");      
            rc.register(CrossOriginEmployeeFilter.class); //Registering the new filter
            return GrizzlyHttpServerFactory.createHttpServer(URI.create(new Main().BASE_URI), rc);
        }

Implementing the Caching Feature in Your Application

  1. Create the CacheClient class.

    The CacheClient class contains the delete, get, put, and replace. Each method implements the HTTP request to the caching API.

    When you add a cache cluster to your application on Oracle Application Container Cloud Service, the CACHING_INTERNAL_CACHE_URL environment variable is generated. This environment variable contains the host name of the cache. In your code you must read this environment variable to generate the URL of the caching API. By default, the port is 8080. The complete path of the Caching REST API is:

    http://CACHING_INTERNAL_CACHE_URL:8080/ccs
    /* Copyright © 2017 Oracle and/or its affiliates. All rights reserved. */
    package com.example.caching;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.ws.rs.client.ClientBuilder;
    import javax.ws.rs.client.Entity;
    import javax.ws.rs.client.WebTarget;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;
    
    public class CacheClient {
        private final static Logger LOGGER = Logger.getLogger(CacheClient.class.getName());
        // Environment variable that holds CCS service name
        private static final String CCS_ENV_NAME = "CACHING_INTERNAL_CACHE_URL";
    
        private static final String CACHE_HOST = System.getenv(CCS_ENV_NAME);
    
        // REST port is 8080
        private static final String REST_PORT = "8080";
    
        // Cache name to use for the test
        /*
        For our example application, we will name our cache 'testcache'. 
        Note that a single caching service can support multiple, individual named caches.
        */
        private static final String CACHE_NAME = "testcache";
    
        private static final String CACHE_URL = "http://" + CACHE_HOST + ":" + REST_PORT + "/ccs";
    
        private static final WebTarget target = ClientBuilder.newClient().target(CACHE_URL);
    
        ;
    
        public Employee get(long id) {
            LOGGER.log(Level.INFO,"CacheClient get method");
            Employee employee = null;
            try {
                Response getResponse = target
                        .path(CACHE_NAME + "/" + id)
                        .request(MediaType.APPLICATION_OCTET_STREAM)
                        .get();
                LOGGER.log(Level.INFO, "Status GET method {0}", getResponse.getStatus());
                if (getResponse.getStatus() != 404) { // 404 = Key not found error.
                    String response = getResponse.readEntity(String.class);
                    LOGGER.log(Level.INFO,"Response " + response);
                    ObjectMapper mapper = new ObjectMapper();
                    employee = mapper.readValue(response, Employee.class);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return employee;
        }
    
        public boolean put(long id, Employee employee) {
            LOGGER.log(Level.INFO,"CacheClient put method");
            boolean result = false;
            try {
                Response putResponse = target
                        .path(CACHE_NAME + "/" + id)
                        .request(MediaType.APPLICATION_JSON_TYPE)
                        .put(Entity.json(employee));
                LOGGER.log(Level.INFO,"Status PUT method " + putResponse.getStatus());
                if (putResponse.getStatus() == 204) { //Successful!
                    result = true;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }
    
        public boolean replace(long id, Employee employee) {
            System.out.println("CacheClient replace method");
            boolean result = false;
            try {
                Response replaceResponse = target
                        .path(CACHE_NAME + "/" + id)
                        .request()
                        .header("X-Method", "replace")
                        .post(Entity.json(employee));
                LOGGER.log(Level.INFO,"Status REPLACE method " + replaceResponse.getStatus());
                if (replaceResponse.getStatus() == 204) { //Successful!
                    result = true;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }
    
        public void delete(long id) {
            LOGGER.log(Level.INFO,"CacheClient delete method");
            try {
                Response deleteResponse = target
                        .path(CACHE_NAME + "/" + id)
                        .request()
                        .delete();
               LOGGER.log(Level.INFO,"Status DELETE method " + deleteResponse.getStatus());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
  2. Open the EmployeeResource class in a text editor.

  3. Add the cache member variable of the CacheClient class.

    private final CacheClient cache = new CacheClient();
  4. Edit the getEmployee, addEmployee, updateEmployee, and deleteEmployee methods to use the cache.

        @GET
        @Path("{id}")
        @Produces(MediaType.APPLICATION_JSON)
        public Response getEmployee(@PathParam("id") long id) {
            LOGGER.log(Level.INFO, "GET Method by ID");
            Employee employee = cache.get(id);
            if (employee == null) {
                employee = employeeDao.findById(id);
            }        
            return Response.ok(employee) //200
                    .build();
        }
        
        @POST
        @Produces(MediaType.APPLICATION_JSON)
        public Response addEmployee(Employee employee) {
            LOGGER.log(Level.INFO, "POST Method");
            employeeDao.insert(employee);
            cache.put(employee.getId(), employee);
            return Response.status(201)
                    .build();
        }
    
        @PUT
        @Path("{id}")
        @Produces(MediaType.APPLICATION_JSON)
        public Response updateEmployee(@PathParam("id") long id, Employee employee) {
            LOGGER.log(Level.INFO, "PUT Method {0}", id);
            boolean response = employeeDao.update(id, employee);
            if (response) {
                cache.replace(id, employee);
                return Response.status(Response.Status.OK)
                        .build();
            } else {
                return Response.status(Response.Status.NOT_FOUND).build();
            }
        }
    
        @DELETE
        @Path("{id}")
        public void deleteEmployee(@PathParam("id") long id) {
            LOGGER.log(Level.INFO, "DELETE Method {0}", id);
            boolean response = employeeDao.delete(id);      
            if (!response) {
                throw new NotFoundException("Error Employee " + id + " not found");
            } else {
                cache.delete(id);
                Response.status(Response.Status.OK)
                        .build();
            }
        }    
    

Preparing the Application for Cloud Deployment

For your service application to run properly on Oracle Application Container Cloud Service, it must comply with the following requirements:

  • The application must be bundled in a .zip file.
  • The .zip file must contain all the project dependencies or a fat JAR, and the manifest.json file that specifies what command Oracle Application Container Cloud Service should run and the Java version.
  • Your application must listen to requests on a port provided by the PORT environment variable. Oracle Application Container Cloud uses this port to redirect requests made to your application.
  • The embedded server must run on 0.0.0.0. The 0.0.0.0, specification ensures that the server will bind to all IPs, allowing the server to be accessed from external devices through the machine's IP or host name.
  1. Create the manifest.json file in the root directory and add the following content:

    {
      "runtime": {
          "majorVersion": "8"
      },
      "command": "java -jar jersey-service-caching-1.0-SNAPSHOT.jar",
      "isClustered":"true"
    } 

    Note: To use the caching feature on Oracle Application Container Cloud Service isClustered=true is required.

  2. Create the assembly directory in the src folder.

  3. Create the distribution.xml file in the assembly folder and add the following content:

    <assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
      <id>dist</id>
      <formats>
        <format>zip</format>
      </formats>
      <includeBaseDirectory>false</includeBaseDirectory>
      <fileSets>
        <fileSet>
          <directory>${project.basedir}</directory>
          <outputDirectory>/</outputDirectory>
          <includes>
            <include>manifest.json</include>
          </includes>
        </fileSet>   
        <fileSet>
          <directory>${project.build.directory}</directory>
          <outputDirectory>/</outputDirectory>
          <includes>
            <include>jersey-service-caching-1.0-SNAPSHOT.jar</include>
          </includes>
          <excludes>
            <exclude>*.zip</exclude>
          </excludes>
         </fileSet>
      </fileSets>
    </assembly>
                                                                            
  4. The distribution.xml script creates a zip file that includes the fat JAR (jersey-service-caching-1.0-SNAPSHOT.jar) and the manifest.json file.

  5. Open the pom.xml file in a text editor and add following code inside the <plugins> tags.

    The Maven Shade Plugin generates the fat JAR: jersey-service-caching-1.0-SNAPSHOT.jar, which contains the project classes and its dependencies. The Maven Shade Plugin creates the zip file: jersey-service-caching-1.0-SNAPSHOT.zip to deploy the application on Oracle Application Container Cloud Service.

    <plugin>
    	<groupId>org.apache.maven.plugins</groupId>
    	<artifactId>maven-shade-plugin</artifactId>
    	<version>2.3</version>
    	<configuration>
    		<createDependencyReducedPom>false</createDependencyReducedPom>
    		<filters>
    			<filter>
    				<artifact>*:*</artifact>
    				<excludes>
    					<exclude>META-INF/*.SF</exclude>
    					<exclude>META-INF/*.DSA</exclude>
    					<exclude>META-INF/*.RSA</exclude>
    				</excludes>
    			</filter>
    		</filters>
    	</configuration>
    	<executions>
    		<execution>
    			<phase>package</phase>
    			<goals>
    				<goal>shade</goal>
    			</goals>
    			<configuration>
    				<transformers>
    					<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
    					<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
    						<mainClass>com.example.caching.Main</mainClass>
    					</transformer>
    				</transformers>
    			</configuration>
    		</execution>
    	</executions>
    </plugin>
    <plugin>
    	<artifactId>maven-assembly-plugin</artifactId>
    	<version>2.5.5</version>
    	<configuration>
    		<appendAssemblyId>false</appendAssemblyId>
    		<descriptors>
    			<descriptor>src/assembly/distribution.xml</descriptor>
    		</descriptors>
    	</configuration>
    	<executions>
    		<execution>
    			<phase>package</phase>
    			<goals>
    				<goal>single</goal>
    			</goals>
    		</execution>
    	</executions>
    </plugin>
  6. Open the Main class and add the java.util.Optional import.

    import java.util.Optional;
  7. Open the Main class and update the BASE_URI variable to use the PORT environment variable and the 0.0.0.0 host name.

    private static final Optional<String> port = Optional.ofNullable(System.getenv("PORT")); 
    public static final String BASE_URI = "http://0.0.0.0:"+port.orElse("8080")+"/myapp/";
  8. In the command-line window, build your application using the Maven command:

    mvn clean package
  9. Look at the target directory and you'll find the jersey-service-caching-1.0-SNAPSHOT.zip file. You'll use this file to deploy your application to Oracle Application Container Cloud Service.

Deploying the Application to Oracle Application Cloud Service

  1. Go back to the Oracle Application Container Cloud Service console.

  2. In the Applications list view, click Create Application, and select Java SE.

  3. In the Application section, enter a name for your application, and then click Choose File next to Application.

  4. In the File Upload dialog box, select the jersey-service-caching-1.0-SNAPSHOT.zip file, and click Open.

  5. In the Application section, click More Options.

  6. In More Options section, select the following values, leave the other fields with their default values, and then click Create:

    • Metering Frecuency: Monthly
    • Application Cache: MyCachingService
    Create Application dialog box
    Description of this image
  7. Wait until the application is deployed, and then click the URL.

    Application URL
    Description of this image
  8. Add /myapp/employees to the end of the URL.

    Application URL
    Description of this image
  9. Write down the URL, you'll use it in the next section.

Testing the Application

  1. Extract the content of the employee-client.zip file in your local system.

  2. Open the EmployeeController.js file in a text editor.

  3. Replace the value of the urlService variable with the URL of your application.

    $scope.urlService = "http://javaexamplecache-apaasuser-mydomain.apaas.oraclecloud.com/employees"; 
  4. Open the index.html file in a web browser, and then click Add New..

    Employee client home page
    Description of this image
  5. Enter the First Name, Last Name, Email, Phone, Birthdate, Title, and Department values.

    Add New employee page
    Description of this image
  6. Click Save.

    Employee client home page
    Description of this image
  7. Test the delete, update and search options.

Getting the Logs

  1. Open the Oracle Application Container Cloud Service console.

  2. Select your application.

    Oracle Application Container Cloud Service console
    Description of this image
  3. Click Administration, and then click Logs

    Administration page
    Description of this image
  4. Click Get Log.

    Logs page
    Description of this image
  5. Select the Instance from which you want get the logs.

    Logs page - Get Log
    Description of this image
  6. Wait a minute, and then click Refresh.

  7. Click the log file you want to download.

    Logs page - Logs table
    Description of this image
  8. In the Save As dialog box, select a location for the zip file, and click Save.

  9. Extract the content of the zip file and open the server.out file in a text editor.

  10. Examine the logs to see when the employee object was gotten from the DAO and when it was obtained from the cache.

Want to Learn More?