Injecting dependencies into microservices

duration 15 minutes

Prerequisites:

Learn how to use Contexts and Dependency Injection (CDI) to manage scopes and inject dependencies into microservices.

What you’ll learn

You will learn how to use Contexts and Dependency Injection (CDI) to manage scopes and inject dependencies in a simple inventory management application.

The application that you will be working with is an inventory service, which stores the information about various JVMs that run on different systems. Whenever a request is made to the inventory service to retrieve the JVM system properties of a particular host, the inventory service communicates with the system service on that host to get these system properties. The system properties are then stored and returned.

You will use scopes to bind objects in this application to their well-defined contexts. CDI provides a variety of scopes for you to work with and while you will not use all of them in this guide, there is one for almost every scenario that you may encounter. Scopes are defined by using CDI annotations. You will also use dependency injection to inject one bean into another to make use of its functionalities. This enables you to inject the bean in its specified context without having to instantiate it yourself.

The implementation of the application and its services are provided for you in the start/src directory. The system service can be found in the start/src/main/java/io/openliberty/guides/system directory, and the inventory service can be found in the start/src/main/java/io/openliberty/guides/inventory directory. If you want to learn more about RESTful web services and how to build them, see Creating a RESTful web service for details about how to build the system service. The inventory service is built in a similar way.

What is CDI?

Contexts and Dependency Injection (CDI) defines a rich set of complementary services that improve the application structure. The most fundamental services that are provided by CDI are contexts that bind the lifecycle of stateful components to well-defined contexts, and dependency injection that is the ability to inject components into an application in a typesafe way. With CDI, the container does all the daunting work of instantiating dependencies, and controlling exactly when and how these components are instantiated and destroyed.

Getting started

The fastest way to work through this guide is to clone the Git repository and use the projects that are provided inside:

git clone https://github.com/openliberty/guide-cdi-intro.git
cd guide-cdi-intro

The start directory contains the starting project that you will build upon.

The finish directory contains the finished project that you will build.

Try what you’ll build

The finish directory in the root of this guide contains the finished inventory application. Give it a try before you proceed.

To try out the application, first navigate to the finish directory and then run the following Maven goals to build the application and run it inside Open Liberty:

cd finish
mvn install liberty:start-server

Point your browser to the http://localhost:9080/inventory/systems URL. This is the starting point of the inventory service and it displays the current contents of the inventory. As you might expect, these are empty since nothing is stored in the inventory yet. Next, point your browser to the http://localhost:9080/inventory/systems/localhost URL. You see a result in JSON format with the system properties of your local JVM. When you visit this URL, these system properties are automatically stored in the inventory. Go back to http://localhost:9080/inventory/systems and you see a new entry for localhost. For simplicity, only the OS name and username are shown here for each host. You can repeat this process for your own hostname or any other machine that is running the system service.

After you are done checking out the application, stop the Open Liberty server:

mvn liberty:stop-server

Handling dependencies in the application

You will use CDI to inject dependencies into the inventory manager application and learn how to manage the life cycles of your objects.

Managing scopes and contexts

Navigate to the start directory to begin.

Create the InventoryManager class.
src/main/java/io/openliberty/guides/inventory/InventoryManager.java

InventoryManager.java

 1// tag::copyright[]
 2/*******************************************************************************
 3 * Copyright (c) 2017, 2019 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License v1.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-v10.html
 8 *
 9 * Contributors:
10 *     IBM Corporation - Initial implementation
11 *******************************************************************************/
12// end::copyright[]
13package io.openliberty.guides.inventory;
14
15import java.util.ArrayList;
16import java.util.Collections;
17import java.util.List;
18import java.util.Properties;
19import io.openliberty.guides.inventory.model.InventoryList;
20import io.openliberty.guides.inventory.model.SystemData;
21import javax.enterprise.context.ApplicationScoped;
22
23// tag::ApplicationScoped[]
24@ApplicationScoped
25// end::ApplicationScoped[]
26public class InventoryManager {
27
28  private List<SystemData> systems = Collections.synchronizedList(new ArrayList<>());
29
30  // tag::add[]
31  public void add(String hostname, Properties systemProps) {
32    Properties props = new Properties();
33    props.setProperty("os.name", systemProps.getProperty("os.name"));
34    props.setProperty("user.name", systemProps.getProperty("user.name"));
35
36    SystemData system = new SystemData(hostname, props);
37    if (!systems.contains(system)) {
38      systems.add(system);
39    }
40  }
41  // end::add[]
42
43  // tag::list[]
44  public InventoryList list() {
45    return new InventoryList(systems);
46  }
47  // end::list[]
48}

This bean contains two simple functions. The add() function is for adding entries to the inventory. The list() function is for listing all the entries currently stored in the inventory.

This bean must be persistent between all of the clients, which means multiple clients need to share the same instance. To achieve this by using CDI, you can simply add the @ApplicationScoped annotation onto the class.

This annotation indicates that this particular bean is to be initialized once per application. By making it application-scoped, the container ensures that the same instance of the bean is used whenever it is injected into the application.

Create the InventoryResource class.
src/main/java/io/openliberty/guides/inventory/InventoryResource.java

InventoryResource.java

 1// tag::copyright[]
 2/*******************************************************************************
 3 * Copyright (c) 2017, 2019 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License v1.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-v10.html
 8 *
 9 * Contributors:
10 *     IBM Corporation - Initial implementation
11 *******************************************************************************/
12// end::copyright[]
13package io.openliberty.guides.inventory;
14
15import java.util.Properties;
16import javax.enterprise.context.RequestScoped;
17import javax.inject.Inject;
18import javax.ws.rs.GET;
19import javax.ws.rs.Path;
20import javax.ws.rs.PathParam;
21import javax.ws.rs.Produces;
22import javax.ws.rs.core.MediaType;
23import javax.ws.rs.core.Response;
24import io.openliberty.guides.inventory.model.InventoryList;
25import io.openliberty.guides.inventory.client.SystemClient;
26
27// tag::RequestScoped[]
28@RequestScoped
29// end::RequestScoped[]
30// tag::endpoint[]
31@Path("/systems")
32// end::endpoint[]
33// tag::InventoryResource[]
34public class InventoryResource {
35
36  // tag::inject[]
37  @Inject
38  // end::inject[]
39  InventoryManager manager;
40
41  // tag::inject2[]
42  @Inject
43  // end::inject2[]
44  SystemClient systemClient;
45
46  @GET
47  @Path("/{hostname}")
48  @Produces(MediaType.APPLICATION_JSON)
49  public Response getPropertiesForHost(@PathParam("hostname") String hostname) {
50    // Get properties for host
51    // tag::properties[]
52    Properties props = systemClient.getProperties(hostname);
53    // end::properties[]
54    if (props == null) {
55      return Response.status(Response.Status.NOT_FOUND)
56                     .entity("ERROR: Unknown hostname or the system service may not be "
57                             + "running on " + hostname)
58                     .build();
59    }
60
61    // Add to inventory
62    // tag::managerAdd[]
63    manager.add(hostname, props);
64    // end::managerAdd[]
65    return Response.ok(props).build();
66  }
67
68  @GET
69  @Produces(MediaType.APPLICATION_JSON)
70  public InventoryList listContents() {
71    // tag::managerList[]
72    return manager.list();
73    // end::managerList[]
74  }
75}
76// tag::InventoryResource[]

The inventory resource is a RESTful service that is served at the inventory/systems endpoint.

Add the @RequestScoped annotation on the class to indicate that this bean is to be initialized once for every request. In other words, the bean is instantiated when the request is received and destroyed when a response is sent back to the client. While this bean can also be application-scoped, request scope is short-lived and is therefore ideal for HTTP requests.

Injecting a dependency

Refer to the InventoryResource class you created above.

The @Inject annotation indicates a dependency injection. You are injecting your InventoryManager and SystemClient beans into the InventoryResource class. This injects the beans in their specified context and makes all of their functionalities available without the need of instantiating them yourself. The injected bean InventoryManager can then be invoked directly through the manager.add(hostname, props) and manager.list() function calls. The injected bean SystemClient can be invoked through the systemClient.getProperties(hostname) function call.

Finally, you have a client component SystemClient that can be found in the src/main/java/io/openliberty/guides/inventory/client directory. This class communicates with the system service to retrieve the JVM system properties for a particular host that exposes them. This class also contains detailed Javadocs that you can read for reference.

Your inventory application is now completed.

InventoryResource.java

 1// tag::copyright[]
 2/*******************************************************************************
 3 * Copyright (c) 2017, 2019 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License v1.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-v10.html
 8 *
 9 * Contributors:
10 *     IBM Corporation - Initial implementation
11 *******************************************************************************/
12// end::copyright[]
13package io.openliberty.guides.inventory;
14
15import java.util.Properties;
16import javax.enterprise.context.RequestScoped;
17import javax.inject.Inject;
18import javax.ws.rs.GET;
19import javax.ws.rs.Path;
20import javax.ws.rs.PathParam;
21import javax.ws.rs.Produces;
22import javax.ws.rs.core.MediaType;
23import javax.ws.rs.core.Response;
24import io.openliberty.guides.inventory.model.InventoryList;
25import io.openliberty.guides.inventory.client.SystemClient;
26
27// tag::RequestScoped[]
28@RequestScoped
29// end::RequestScoped[]
30// tag::endpoint[]
31@Path("/systems")
32// end::endpoint[]
33// tag::InventoryResource[]
34public class InventoryResource {
35
36  // tag::inject[]
37  @Inject
38  // end::inject[]
39  InventoryManager manager;
40
41  // tag::inject2[]
42  @Inject
43  // end::inject2[]
44  SystemClient systemClient;
45
46  @GET
47  @Path("/{hostname}")
48  @Produces(MediaType.APPLICATION_JSON)
49  public Response getPropertiesForHost(@PathParam("hostname") String hostname) {
50    // Get properties for host
51    // tag::properties[]
52    Properties props = systemClient.getProperties(hostname);
53    // end::properties[]
54    if (props == null) {
55      return Response.status(Response.Status.NOT_FOUND)
56                     .entity("ERROR: Unknown hostname or the system service may not be "
57                             + "running on " + hostname)
58                     .build();
59    }
60
61    // Add to inventory
62    // tag::managerAdd[]
63    manager.add(hostname, props);
64    // end::managerAdd[]
65    return Response.ok(props).build();
66  }
67
68  @GET
69  @Produces(MediaType.APPLICATION_JSON)
70  public InventoryList listContents() {
71    // tag::managerList[]
72    return manager.list();
73    // end::managerList[]
74  }
75}
76// tag::InventoryResource[]

SystemClient.java

 1// tag::copyright[]
 2/*******************************************************************************
 3 * Copyright (c) 2017 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License v1.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-v10.html
 8 *
 9 * Contributors:
10 *     IBM Corporation - Initial implementation
11 *******************************************************************************/
12// end::copyright[]
13package io.openliberty.guides.inventory.client;
14
15import javax.enterprise.context.RequestScoped;
16import javax.ws.rs.client.Client;
17import javax.ws.rs.client.ClientBuilder;
18import javax.ws.rs.client.Invocation.Builder;
19import javax.ws.rs.core.HttpHeaders;
20import javax.ws.rs.core.MediaType;
21import javax.ws.rs.core.Response;
22import javax.ws.rs.core.Response.Status;
23import java.util.Properties;
24import java.net.URI;
25
26@RequestScoped
27public class SystemClient {
28
29  // Constants for building URI to the system service.
30  private final int DEFAULT_PORT = Integer.valueOf(System.getProperty("default.http.port"));
31  private final String SYSTEM_PROPERTIES = "/system/properties";
32  private final String PROTOCOL = "http";
33
34  // Wrapper function that gets properties
35  public Properties getProperties(String hostname) {
36    String url = buildUrl(PROTOCOL, hostname, DEFAULT_PORT, SYSTEM_PROPERTIES);
37    Builder clientBuilder = buildClientBuilder(url);
38    return getPropertiesHelper(clientBuilder);
39  }
40
41  // tag::doc[]
42  /**
43   * Builds the URI string to the system service for a particular host.
44   * @param protocol
45   *          - http or https.
46   * @param host
47   *          - name of host.
48   * @param port
49   *          - port number.
50   * @param path
51   *          - Note that the path needs to start with a slash!!!
52   * @return String representation of the URI to the system properties service.
53   */
54  // end::doc[]
55  protected String buildUrl(String protocol, String host, int port, String path) {
56    try {
57      URI uri = new URI(protocol, null, host, port, path, null, null);
58      return uri.toString();
59    } catch (Exception e) {
60      System.err.println("Exception thrown while building the URL: " + e.getMessage());
61      return null;
62    }
63  }
64
65  // Method that creates the client builder
66  protected Builder buildClientBuilder(String urlString) {
67    try {
68      Client client = ClientBuilder.newClient();
69      Builder builder = client.target(urlString).request();
70      return builder.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
71    } catch (Exception e) {
72      System.err.println("Exception thrown while building the client: " + e.getMessage());
73      return null;
74    }
75  }
76
77  // Helper method that processes the request
78  protected Properties getPropertiesHelper(Builder builder) {
79    try {
80      Response response = builder.get();
81      if (response.getStatus() == Status.OK.getStatusCode()) {
82        return response.readEntity(Properties.class);
83      } else {
84        System.err.println("Response Status is not OK.");
85      }
86    } catch (RuntimeException e) {
87      System.err.println("Runtime exception: " + e.getMessage());
88    } catch (Exception e) {
89      System.err.println("Exception thrown while invoking the request: " + e.getMessage());
90    }
91    return null;
92  }
93
94}

Building and running the application

To build the application, run the Maven install phase from the command line in the start directory:

mvn install

This command builds the application and creates a .war file in the target directory. It also configures and installs Open Liberty into the target/liberty/wlp directory.

Next, run the Maven liberty:start-server goal:

mvn liberty:start-server

This goal starts an Open Liberty server instance. Your Maven pom.xml is already configured to start the application in this server instance.

You can find the inventory and system services at the following URLs:

If you make changes to the code, use the Maven compile goal to rebuild the application and have the running Open Liberty server pick them up automatically:

mvn compile

To stop the Open Liberty server, run the Maven liberty:stop-server goal:

mvn liberty:stop-server

Testing the inventory application

While you can test your application manually, you should rely on automated tests since they trigger a failure whenever a code change introduces a defect. Since the application is a RESTful web service application, you can use JUnit and the RESTful web service Client API to write tests. In testing the functionality of the application, the scopes and dependencies are being tested.

Create the InventoryEndpointTest class.
src/test/java/it/io/openliberty/guides/inventory/InventoryEndpointTest.java

The @BeforeClass annotation is placed on a method that runs before any of the test cases. In this case, the oneTimeSetup() method retrieves the port number for the Open Liberty server and builds a base URL string that is used throughout the tests.

The @Before and @After annotations are placed on methods that run before and after every test case. These methods are generally used to perform any setup and teardown tasks. In this case, the setup() method creates a JAX-RS client, which makes HTTP requests to the inventory service. This client must also be registered with a JSON-P provider (JsrJsonpProvider) to process JSON resources. The teardown() method simply destroys this client instance.

See the following descriptions of the test cases:

  • testEmptyInventory() verifies that the inventory is initially empty when the server first starts up.

  • testHostRegistration() verifies that a host is correctly added to the inventory.

  • testSystemPropertiesMatch() verifies that the JVM system properties returned by the system service match the ones stored in the inventory service.

  • testUnknownHost() verifies that an unknown host or a host that does not expose their JVM system properties is correctly handled as an error.

To force these test cases to run in a particular order, put them in a testSuite() method and label it with a @Test annotation so that it automatically runs when your test class run.

Finally, the src/test/java/it/io/openliberty/guides/system/SystemEndpointTest.java file is included for you to test the basic functionality of the system service. If a test failure occurs, then you might have introduced a bug into the code.

InventoryEndpointTest.java

  1// tag::copyright[]
  2/*******************************************************************************
  3 * Copyright (c) 2017, 2019 IBM Corporation and others.
  4 * All rights reserved. This program and the accompanying materials
  5 * are made available under the terms of the Eclipse Public License v1.0
  6 * which accompanies this distribution, and is available at
  7 * http://www.eclipse.org/legal/epl-v10.html
  8 *
  9 * Contributors:
 10 *     IBM Corporation - Initial implementation
 11 *******************************************************************************/
 12// end::copyright[]
 13// tag::testClass[]
 14package it.io.openliberty.guides.inventory;
 15
 16import static org.junit.Assert.assertEquals;
 17import static org.junit.Assert.assertTrue;
 18
 19import javax.json.JsonObject;
 20import javax.ws.rs.client.Client;
 21import javax.ws.rs.client.ClientBuilder;
 22import javax.ws.rs.core.MediaType;
 23import javax.ws.rs.core.Response;
 24
 25import org.apache.cxf.jaxrs.provider.jsrjsonp.JsrJsonpProvider;
 26import org.junit.After;
 27import org.junit.Before;
 28import org.junit.BeforeClass;
 29import org.junit.Test;
 30
 31public class InventoryEndpointTest {
 32
 33  private static String port;
 34  private static String baseUrl;
 35
 36  private Client client;
 37
 38  private final String SYSTEM_PROPERTIES = "system/properties";
 39  private final String INVENTORY_SYSTEMS = "inventory/systems";
 40
 41  // tag::BeforeClass[]
 42  @BeforeClass
 43  // end::BeforeClass[]
 44  // tag::oneTimeSetup[]
 45  public static void oneTimeSetup() {
 46    port = System.getProperty("liberty.test.port");
 47    baseUrl = "http://localhost:" + port + "/";
 48  }
 49  // end::oneTimeSetup[]
 50
 51  // tag::Before[]
 52  @Before
 53  // end::Before[]
 54  // tag::setup[]
 55  public void setup() {
 56    client = ClientBuilder.newClient();
 57    // tag::JsrJsonpProvider[]
 58    client.register(JsrJsonpProvider.class);
 59    // end::JsrJsonpProvider[]
 60  }
 61  // end::setup[]
 62
 63  // tag::After[]
 64  @After
 65  // end::After[]
 66  // tag::teardown[]
 67  public void teardown() {
 68    client.close();
 69  }
 70  // end::teardown[]
 71
 72  // tag::tests[]
 73  // tag::test[]
 74  @Test
 75  // end::test[]
 76  // tag::testSuite[]
 77  public void testSuite() {
 78    this.testEmptyInventory();
 79    this.testHostRegistration();
 80    this.testSystemPropertiesMatch();
 81    this.testUnknownHost();
 82  }
 83  // end::testSuite[]
 84
 85  // tag::testEmptyInventory[]
 86  public void testEmptyInventory() {
 87    Response response = this.getResponse(baseUrl + INVENTORY_SYSTEMS);
 88    this.assertResponse(baseUrl, response);
 89
 90    JsonObject obj = response.readEntity(JsonObject.class);
 91
 92    int expected = 0;
 93    int actual = obj.getInt("total");
 94    assertEquals("The inventory should be empty on application start but it wasn't",
 95                 expected, actual);
 96
 97    response.close();
 98  }
 99  // end::testEmptyInventory[]
100
101  // tag::testHostRegistration[]
102  public void testHostRegistration() {
103    this.visitLocalhost();
104
105    Response response = this.getResponse(baseUrl + INVENTORY_SYSTEMS);
106    this.assertResponse(baseUrl, response);
107
108    JsonObject obj = response.readEntity(JsonObject.class);
109
110    int expected = 1;
111    int actual = obj.getInt("total");
112    assertEquals("The inventory should have one entry for localhost", expected,
113                 actual);
114
115    boolean localhostExists = obj.getJsonArray("systems").getJsonObject(0)
116                                 .get("hostname").toString()
117                                 .contains("localhost");
118    assertTrue("A host was registered, but it was not localhost",
119               localhostExists);
120
121    response.close();
122  }
123  // end::testHostRegistration[]
124
125  // tag::testSystemPropertiesMatch[]
126  public void testSystemPropertiesMatch() {
127    Response invResponse = this.getResponse(baseUrl + INVENTORY_SYSTEMS);
128    Response sysResponse = this.getResponse(baseUrl + SYSTEM_PROPERTIES);
129
130    this.assertResponse(baseUrl, invResponse);
131    this.assertResponse(baseUrl, sysResponse);
132
133    JsonObject jsonFromInventory = (JsonObject) invResponse.readEntity(JsonObject.class)
134                                                           .getJsonArray("systems")
135                                                           .getJsonObject(0)
136                                                           .get("properties");
137
138    JsonObject jsonFromSystem = sysResponse.readEntity(JsonObject.class);
139
140    String osNameFromInventory = jsonFromInventory.getString("os.name");
141    String osNameFromSystem = jsonFromSystem.getString("os.name");
142    this.assertProperty("os.name", "localhost", osNameFromSystem,
143                        osNameFromInventory);
144
145    String userNameFromInventory = jsonFromInventory.getString("user.name");
146    String userNameFromSystem = jsonFromSystem.getString("user.name");
147    this.assertProperty("user.name", "localhost", userNameFromSystem,
148                        userNameFromInventory);
149
150    invResponse.close();
151    sysResponse.close();
152  }
153  // end::testSystemPropertiesMatch[]
154
155  // tag::testUnknownHost[]
156  public void testUnknownHost() {
157    Response response = this.getResponse(baseUrl + INVENTORY_SYSTEMS);
158    this.assertResponse(baseUrl, response);
159
160    Response badResponse = client.target(baseUrl + INVENTORY_SYSTEMS + "/"
161        + "badhostname").request(MediaType.APPLICATION_JSON).get();
162
163    String obj = badResponse.readEntity(String.class);
164
165    boolean isError = obj.contains("ERROR");
166    assertTrue("badhostname is not a valid host but it didn't raise an error",
167               isError);
168
169    response.close();
170    badResponse.close();
171  }
172  // end::testUnknownHost[]
173  // end::tests[]
174
175  private Response getResponse(String url) {
176    return client.target(url).request().get();
177  }
178
179  private void assertResponse(String url, Response response) {
180    assertEquals("Incorrect response code from " + url, 200,
181                 response.getStatus());
182  }
183
184  private void assertProperty(String propertyName, String hostname,
185      String expected, String actual) {
186    assertEquals("JVM system property [" + propertyName + "] "
187        + "in the system service does not match the one stored in "
188        + "the inventory service for " + hostname, expected, actual);
189  }
190
191  private void visitLocalhost() {
192    Response response = this.getResponse(baseUrl + SYSTEM_PROPERTIES);
193    this.assertResponse(baseUrl, response);
194    response.close();
195
196    Response targetResponse = client.target(baseUrl + INVENTORY_SYSTEMS
197        + "/localhost").request().get();
198    targetResponse.close();
199  }
200}
201// end::testClass[]

SystemEndpointTest.java

 1//tag::copyright[]
 2/*******************************************************************************
 3* Copyright (c) 2017, 2019 IBM Corporation and others.
 4* All rights reserved. This program and the accompanying materials
 5* are made available under the terms of the Eclipse Public License v1.0
 6* which accompanies this distribution, and is available at
 7* http://www.eclipse.org/legal/epl-v10.html
 8*
 9* Contributors:
10*     IBM Corporation - initial API and implementation
11*******************************************************************************/
12// end::copyright[]
13package it.io.openliberty.guides.system;
14
15import static org.junit.Assert.assertEquals;
16import javax.json.JsonObject;
17import javax.ws.rs.client.Client;
18import javax.ws.rs.client.ClientBuilder;
19import javax.ws.rs.client.WebTarget;
20import javax.ws.rs.core.Response;
21
22import org.apache.cxf.jaxrs.provider.jsrjsonp.JsrJsonpProvider;
23import org.junit.Test;
24
25public class SystemEndpointTest {
26
27 @Test
28 public void testGetProperties() {
29     String port = System.getProperty("liberty.test.port");
30     String url = "http://localhost:" + port + "/";
31
32     Client client = ClientBuilder.newClient();
33     client.register(JsrJsonpProvider.class);
34
35     WebTarget target = client.target(url + "system/properties");
36     Response response = target.request().get();
37
38     assertEquals("Incorrect response code from " + url, 200, response.getStatus());
39
40     JsonObject obj = response.readEntity(JsonObject.class);
41
42     assertEquals("The system property for the local and remote JVM should match",
43                  System.getProperty("os.name"),
44                  obj.getString("os.name"));
45
46     response.close();
47 }
48}

Running the tests

If the server is still running from the previous steps, stop it using the Maven liberty:stop-server goal from command line in the start directory:

mvn liberty:stop-server

Then, verify that the tests pass using the Maven verify goal:

mvn verify

It may take some time before build is complete. If the tests pass, you will see a similar output to the following:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.system.SystemEndpointTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.99 sec - in it.io.openliberty.guides.system.SystemEndpointTest
Running it.io.openliberty.guides.inventory.InventoryEndpointTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.325 sec - in it.io.openliberty.guides.inventory.InventoryEndpointTest

Results :

Tests run: 2, Failures: 0, Errors: 0, Skipped: 0

To see whether the tests detect a failure, change the endpoint for the inventory service in the src/main/java/io/openliberty/guides/inventory/InventoryResource.java file to something else, then run the Maven build again. You see a test failure occur.

InventoryResource.java

 1// tag::copyright[]
 2/*******************************************************************************
 3 * Copyright (c) 2017, 2019 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License v1.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-v10.html
 8 *
 9 * Contributors:
10 *     IBM Corporation - Initial implementation
11 *******************************************************************************/
12// end::copyright[]
13package io.openliberty.guides.inventory;
14
15import java.util.Properties;
16import javax.enterprise.context.RequestScoped;
17import javax.inject.Inject;
18import javax.ws.rs.GET;
19import javax.ws.rs.Path;
20import javax.ws.rs.PathParam;
21import javax.ws.rs.Produces;
22import javax.ws.rs.core.MediaType;
23import javax.ws.rs.core.Response;
24import io.openliberty.guides.inventory.model.InventoryList;
25import io.openliberty.guides.inventory.client.SystemClient;
26
27// tag::RequestScoped[]
28@RequestScoped
29// end::RequestScoped[]
30// tag::endpoint[]
31@Path("/systems")
32// end::endpoint[]
33// tag::InventoryResource[]
34public class InventoryResource {
35
36  // tag::inject[]
37  @Inject
38  // end::inject[]
39  InventoryManager manager;
40
41  // tag::inject2[]
42  @Inject
43  // end::inject2[]
44  SystemClient systemClient;
45
46  @GET
47  @Path("/{hostname}")
48  @Produces(MediaType.APPLICATION_JSON)
49  public Response getPropertiesForHost(@PathParam("hostname") String hostname) {
50    // Get properties for host
51    // tag::properties[]
52    Properties props = systemClient.getProperties(hostname);
53    // end::properties[]
54    if (props == null) {
55      return Response.status(Response.Status.NOT_FOUND)
56                     .entity("ERROR: Unknown hostname or the system service may not be "
57                             + "running on " + hostname)
58                     .build();
59    }
60
61    // Add to inventory
62    // tag::managerAdd[]
63    manager.add(hostname, props);
64    // end::managerAdd[]
65    return Response.ok(props).build();
66  }
67
68  @GET
69  @Produces(MediaType.APPLICATION_JSON)
70  public InventoryList listContents() {
71    // tag::managerList[]
72    return manager.list();
73    // end::managerList[]
74  }
75}
76// tag::InventoryResource[]

Great work! You’re done!

You have just completed building a simple inventory application using CDI services in Open Liberty.

Guide Attribution

Injecting dependencies into microservices by Open Liberty is licensed under CC BY-ND 4.0

Copied to clipboard
Copy code block
Copy file contents

Prerequisites:

Nice work! Where to next?

What did you think of this guide?

Extreme Dislike Dislike Like Extreme Like

What could make this guide better?

Raise an issue to share feedback

Create a pull request to contribute to this guide

Need help?

Ask a question on Stack Overflow

Like Open Liberty? Star our repo on GitHub.

Star