Chapter 10. Architecting a microservice hybrid

This chapter covers

  • Running the Cayambe monolith
  • Integrating microservices into Cayambe with a hybrid approach
  • Modifying Cayambe to integrate your microservices
  • Running the integrated Cayambe in a hybrid cloud

This chapter starts by showing you the old Cayambe and how to get it running locally. Then, after covering some theory on using the hybrid approach to integrating your microservices, you’ll revisit the architecture you’re looking to achieve for the new Cayambe. Next, you’ll dive into implementing the hybrid approach, with the microservices you’ve developed throughout the book so far. Finally, you’ll take your revitalized Cayambe monolith, along with the required microservices, and get them all running in the cloud.

10.1. The Cayambe monolith

Figure 10.1 provides a reminder of the Cayambe homepage from a user’s perspective.

Figure 10.1. Cayambe homepage

Cayambe (https://sourceforge.net/projects/cayambe/) is described as a “J2EE E-Commerce Solution using Java Servlets & JSP & EJB.” It was built on JDK 1.2 and uses Apache Struts v1. The existing code, which was last updated 15 years ago and can be found at http://cayambe.cvs.sourceforge.net/viewvc/cayambe/, was downloaded and imported to the code repository for this book under /cayambe.

I faced initial challenges in finding compatible versions of Apache Struts, as well as making the necessary changes for it to compile on JDK 8! I resolved some minor bugs as well, to ensure that the basic UI was as functional as possible (as much as possible, given that I wasn’t involved in Cayambe’s creation).

Note

The changes required to compile and run the original Cayambe code are beyond the scope of this book. But you can see the changes by viewing the Git commit history of the code at http://mng.bz/4MZ5.

Figure 10.2 provides a detailed view of the layers of code that Cayambe currently has architected. You start with JavaServer Pages (JSP) for the UI; these pages interact with Struts forms and actions. In turn, they interact with a layer of delegates that communicate with the Enterprise JavaBeans (EJB) that are present in what is referred to as the backend because it doesn’t involve user-facing code. Finally, the EJBs execute calls on the Data Access Objects (DAOs) that provide persistence to the database.

Figure 10.2 provides a great view into the many layers that are present within Cayambe, as well as which pieces of each layer interact with the others. For instance, you can see that Struts forms and actions for both the Admin WAR and Cart WAR use the same delegate classes for Category and Product. Though such a situation is typical of older code, you should use design tools such as DDD (Domain-Driven Design), which was discussed in chapter 1, to separate the domain model of administration from a user placing an order. You likely would want particular pieces of data for Category and Product present that are applicable to only administrators of the site, but not to a user trying to place an order.

Figure 10.2. Cayambe code structure

10.2. Running the Cayambe monolith

Running Cayambe locally requires these prerequisites:

10.2.1. Database setup

With a running MySQL server, you can now set up the database and load data.

Listing 10.1. Create database and load data
mysql -h127.0.0.1 -P 32768 -uroot                                         1
create user 'cayambe'@'172.17.0.1' identified by 'cayambe';               2
grant all privileges on *.* to 'cayambe'@'172.17.0.1' with grant option;  3
create database cayambe;                                                  4
use cayambe;                                                              5
source cayambesqlmysql.sql                                             6
source cayambesql	est_data.sql                                         7

  • 1 Connect to the MySQL server running on port 32768 on localhost as the root user. This may be different in your environment.
  • 2 Create a user named cayambe with a password of cayambe.
  • 3 Grant privileges to the cayambe user in MySQL Server.
  • 4 Create a database named cayambe.
  • 5 Switch to using the database you just created.
  • 6 Execute the SQL script in mysql.sql to create all the necessary tables for Cayambe.
  • 7 Execute the SQL script in test_data.sql to load initial data into the tables.

With these steps, you now have a database ready for use with Cayambe. The next task is to configure WildFly to be able to access the database you just set up.

10.2.2. WildFly setup

After you’ve extracted the WildFly 11.0.0.Final download into a directory of your choosing, you need to provide some setup so that WildFly knows where the MySQL driver can be found. To do that, you create /modules/system/layers/base/com/ mysql/main inside the location where WildFly was extracted.

Inside the directory you just created, copy the MySQL connector for Java JAR file that you downloaded earlier. In the same directory, create this file.

Listing 10.2. MySQL driver module.xml for monolith
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.3" name="com.mysql">             1

  <resources>
    <resource-root path="mysql-connector-java-5.1.43-bin.jar"/>    2
  </resources>
  <dependencies>                                                   3
    <module name="javax.api"/>
    <module name="javax.transaction.api"/>
  </dependencies>
</module>

  • 1 Sets the module name to be com.mysql, matching the directory structure you created
  • 2 Path to the MySQL connector for Java JAR. Your JAR may require a different version in the name.
  • 3 Some dependencies that are required for JDBC drivers in WildFly

What you’ve done here is create a JBoss module definition that’s used by WildFly. JBoss Modules is an open source project at the core of WildFly’s management of classloaders, and the separation of classes between classloaders to prevent clashes. For this example, you don’t need to understand how JBoss Modules does what it does. All you need to know is how to create a new module, as you did here, for adding JDBC drivers into WildFly.

Finally, you need to tell WildFly about the new database driver and define a new data source that Cayambe can use to talk to the database. All WildFly configuration is present in standalone.xml. You need to locate standalone.xml inside /standalone/configuration/ of the WildFly installation and then open the file for editing. Locate the section for the datasource’s subsystem and replace the entire section with the following content.

Listing 10.3. standalone.xml snippet
<subsystem xmlns="urn:jboss:domain:datasources:5.0">
  <datasources>
    <datasource jndi-name="java:jboss/datasources/ExampleDS"
        pool-name="ExampleDS" enabled="true" use-java-context="true">       1
      <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-
1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
      <driver>h2</driver>
      <security>
        <user-name>sa</user-name>
        <password>sa</password>
      </security>
    </datasource>
    <datasource jta="true" jndi-name="java:/Climb" pool-name="MySqlDS"
enabled="true" use-ccm="true">                                            2
      <connection-url>jdbc:mysql://localhost:32768/cayambe</connection-url> 3
      <driver-class>com.mysql.jdbc.Driver</driver-class>
      <driver>mysql</driver>                                                4
      <security>
        <user-name>cayambe</user-name>                                      5
        <password>cayambe</password>
      </security>
      <validation>
        <valid-connection-checker
          class-name="org.jboss.jca.adapters.jdbc.extensions.mysql
.MySQLValidConnectionChecker"/>
        <background-validation>true</background-validation>
        <exception-sorter class-
     name="org.jboss.jca.adapters.jdbc.extensions.mysql
.MySQLExceptionSorter"/>
      </validation>
    </datasource>
    <drivers>
      <driver name="h2" module="com.h2database.h2">                         6
        <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</
xa-datasource-class>
      </driver>
      <driver name="mysql" module="com.mysql">                              7
        <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</
xa-datasource-class>
      </driver>
    </drivers>
  </datasources>
</subsystem>

  • 1 Existing ExampleDS datasource present in WildFly. It hasn’t been altered.
  • 2 Climb datasource for Cayambe made accessible under JNDI name java:/Climb
  • 3 MySQL connection URL to database. Needs to be modified for your environment.
  • 4 mysql is the name of the driver definition, which is added at the end of the listing.
  • 5 Security credentials you created in MySQL for the database
  • 6 Existing h2 driver for ExampleDS
  • 7 mysql driver definition, which points to the com.mysql module you created earlier

That’s all you need to do to configure WildFly to work with Cayambe.

10.2.3. Running Cayambe

You’re almost ready to start Cayambe and see it running. But first you need to build the EAR deployment. Figure 10.3 reminds you of what Cayambe looks like from a deployment perspective, which you first saw in chapter 2.

Figure 10.3. Cayambe monolith deployment

Cayambe uses EAR (Enterprise Application aRchive) as the means of packaging the deployment. EAR allows Cayambe to include multiple WARs in addition to common JAR libraries that can be shared.

Note

Though EARs were the preferred method for packaging a Java EE deployment, WAR deployments are more common at present. That’s not to say that EARs aren’t still being used, either by choice or legacy code, but EAR usage is less prevalent than it was.

To build Cayambe, you need to change to the /cayambe directory of the book’s code and run the following:

mvn clean install

Maven will construct each of the JARs and WARs that the project code resides within, and then package it into an EAR for you to deploy. After that construction is complete, copy /cayambe-ear/target/cayambe.ear into /standalone/deployments of the WildFly installation.

Now start WildFly, including your deployment, by running this command from the root of the WildFly installation:

./bin/standalone.sh

Lots of messages are output to the console as WildFly starts, and then your deployment is started. WildFly is ready to accept traffic to Cayambe after the messages stop, and you should see a message that contains content like this:

WFLYSRV0025: WildFly Full 11.0.0.Final (WildFly Core 3.0.8.Final) started in
6028ms

You can access the user site at http://localhost:8080, and the administration site at http://localhost:8080/admin.

10.3. Cayambe hybrid—monolith with microservices

In chapter 1, you learned about the Hybrid pattern for monoliths, whereby an existing monolith can have existing functionality migrated to a microservice environment. This pattern allows those pieces of the monolith that require higher scalability or performance to be efficiently separated, while not requiring the entire monolith to be rebuilt to make improvements. Let’s revisit what a monolith using the Hybrid pattern might look like; see figure 10.4.

Figure 10.4. Enterprise Java and microservices hybrid architecture

Note

In this particular instance, you won’t be using a gateway that fronts all your microservices.

There are certainly benefits to being able to split a monolith into pieces, while also separating out where those pieces might be deployed. Although doing so adds overhead, at least in terms of network calls and performance, the advantages often outweigh any downsides. This is especially true when those advantages revolve around key aspects, such as continuous delivery and release cadence.

In chapter 2, you developed a new administration UI, as well as RESTful endpoints for interacting with the data. In chapter 7, you introduced a separate microservice for processing card payments, to make it easier to integrate with external systems. Finally, in chapter 9, you added security to your administration UI, which was originally created in chapter 2.

How does it all fit together? Figure 10.5 represents the proposed architecture of the Cayambe hybrid monolith. You’ll combine large pieces of the original monolith with new microservices that you’ve developed throughout the book. This architecture has certainly come a long way from where it started, but you still have some work ahead.

Figure 10.5. Proposed Cayambe hybrid monolith

So what exactly did you do in figure 10.5? You wanted to integrate the Payment microservice for processing card payments during the checkout process, and you wanted the UI to retrieve category information from Admin instead of storing the data itself. In addition to the new microservices, you also replaced the UI for administration with a new one, so you can remove the old one from Cayambe.

Let’s look at the requirements for each integration. All the code for the Cayambe hybrid monolith and its microservices is present within the book’s code in /chapter10.

10.3.1. Integrating the Payment microservice

As a result of integrating the Payment microservice (and, in particular, because you’re using an external payment provider—in this case, Stripe), you no longer need to store your customers’ credit card information. This is a huge benefit because the rules and restrictions around storing credit card information can be difficult to enforce, and offloading that responsibility to a company specializing in that area is easier.

Because you don’t need to store that information, let’s remove it from the billing_info table of Cayambe. You modify /sql/cayambe/mysql.sql so that the following columns are removed:

  • name_on_card
  • card_type
  • card_number
  • card_expiration_month
  • card_expiration_year
  • authorization_code

You replace all those columns with a single column for card_charge_id. In changing what you’re storing in the database, you also need to update classes that passed those values around.

Listing 10.4. OrderDAO
public class OrderDAO {
    public void Save(OrderVO orderVO)
    {
    ...

        StringBuffer sqlBillingInfo = new StringBuffer(512);
        sqlBillingInfo.append("insert into billing_info ");
        sqlBillingInfo.append("(order_id,name,address1,address2,city,state,
zipcode,country,name_on_card,");
        sqlBillingInfo.append("card_charge_id,phone,email) ");               1
        sqlBillingInfo.append("values ('" );
        sqlBillingInfo.append(orderId);
        sqlBillingInfo.append("','");

    ...

        sqlBillingInfo.append(orderVO.getBillingInfoVO().getCountry());
        sqlBillingInfo.append("','");
        sqlBillingInfo.append(orderVO.getBillingInfoVO().getCardChargeId()); 2
        sqlBillingInfo.append("','");

    ...
   }
    ...

    public OrderVO getOrderVO( OrderVO orderVO )
    {
    ...
            b.setCardChargeId( rs.getString("billing_info.card_charge_id") );3
    ...
   }

}

  • 1 Remove existing card columns from the select statement and add card_charge_id.
  • 2 Remove calls to set the values for the removed columns, and replace them with getCardChargeId() for the new field.
  • 3 Remove retrieval of old card data columns and add one for card_charge_id.

Here you modify OrderDAO that interacts directly with the database for storing and retrieving the data for an order. Because you’ve modified methods that were on BillingInfoVO, you now need to make changes there as well, as shown in listing 10.5.

Listing 10.5. BillingInfoVO
public class BillingInfoVO implements Serializable {

  private Long billingId = null;
  private Long orderId =  null;
  private String name = null;
  private String address = null;
  private String address2 = null;
  private String city = null;
  private String state = null;
  private String zipCode = null;
  private String country = null;
  private String phone = null;
  private String email = null;

  private String cardToken = null;                                          1
  private String cardChargeId = null;

  ...

  public void setCardToken ( String _cardToken ) { cardToken = _cardToken; }2
  public String getCardToken () { return cardToken; }

  public void setCardChargeId ( String _cardChargeId ) { cardChargeId =
_cardChargeId; }
  public String getCardChargeId () { return cardChargeId; }
}

  • 1 Replace nameOnCard, cardType, cardExpirationMonth, cardExpirationYear, and authorizationCode with cardToken and cardChargeId. cardToken is used to pass a token from the UI, which you’ll see shortly.
  • 2 Remove getter and setter methods for the previously mentioned fields, and add them for cardToken and cardChargeId.

Now that you’ve modified the data objects that you’re passing around, let’s add the code needed to call the Payment client proxy from inside the Cayambe monolith.

To be able to send and receive the JSON and have it converted to objects, you need ChargeStatus, PaymentRequest, and PaymentResponse. To make it easy, you’ve copied these files from the Payment microservice, so you have them. Next you need an interface that represents Payment.

Listing 10.6. PaymentService
@Path("/")
public interface PaymentService {
    @POST
    @Path("/sync")                                                 1
    @Consumes(MediaType.APPLICATION_JSON)                          2
    @Produces(MediaType.APPLICATION_JSON)
    PaymentResponse charge(PaymentRequest paymentRequest);         3
}

  • 1 You’re using the /sync endpoint on the Payment microservice.
  • 2 RESTful endpoint will consume and produce JSON.
  • 3 Method to be proxied that will call Payment.

That’s all you need in order to define the external Payment microservice. Now let’s see how you integrate it into the existing Struts code. To be able to process a card transaction before you save the order, you need to modify SubmitOrderAction from within /cayambe-hybrid/checkout.

Listing 10.7. SubmitOrderAction
public class SubmitOrderAction extends Action                                   1
{
  public ActionForward perform( ActionMapping mapping, ActionForm form,
      HttpServletRequest request, HttpServletResponse response )
      throws IOException, ServletException
  {
    ...

    OrderActionForm oaf = (OrderActionForm)form;

    try {
      delegate = new CheckOutDelegate();
      OrderVO orderVO = new OrderVO();
      orderVO = (OrderVO)oaf.toOrderVO();
      orderVO.setCartVO( (CartVO) session.getAttribute("Cart") );

      // Call Payment Service
      ResteasyClient client = new ResteasyClientBuilder().build();
      ResteasyWebTarget target =
        client.target("http://cayambe-payment-service-
myproject.192.168.64.33.nip.io");                                             2
      PaymentService paymentService = target.proxy(PaymentService.class);       3
      PaymentResponse paymentResponse =
paymentService.charge(new PaymentRequest()                                    4
                          .amount((long) (orderVO.getCartVO().getTotalCost()
* 100))
                          .cardToken(oaf.getCardToken())
                          .orderId(Math.toIntExact(orderVO.getOrderId()))
      );

      orderVO.getBillingInfoVO().setCardChargeId(paymentResponse.getChargeId());5
      delegate.Save ( orderVO );

      CartDelegate cartDelegate = new CartDelegate();
      cartDelegate.Remove( orderVO.getCartVO() );

    } catch(Exception e) {
      forwardMapping = CayambeActionMappings.FAILURE;
      errors.add( ActionErrors.GLOBAL_ERROR, new
ActionError("error.cart.UpdateCartError") );
    }

  return mapping.findForward( forwardMapping );
  }
}

  • 1 Existing Struts Action class for handling order submission
  • 2 Create a ResteasyClient that calls Payment within OpenShift.
  • 3 Create a proxy instance of PaymentService.
  • 4 Call Payment, passing it a PaymentRequest with the amount of the order and the cardToken from Stripe.
  • 5 Set the chargeId you got back from Payment onto the BillingInfoVO.

The preceding code will be familiar from chapters 6, 7, and 8, because you used the RESTEasy client proxy generation in those examples as well.

In creating a PaymentRequest instance, you called oaf.getCardToken(), which contains the card token you need for processing a Stripe request. But you need to update OrderActionForm to provide that information for you.

OrderActionForm is located in /cayambe-hybrid/web-common. You remove the following fields, and their associated getters and setters:

  • nameOnCard
  • cardNumber
  • cardType
  • cardExpirationMonth
  • cardExpirationYear

Finally, you add a field for cardToken of type String, and the getter and setter for it as well.

Let’s modify the checkout page to capture the credit card details, before calling Stripe to retrieve a cardToken representing the credit card. For that, you need to update CheckOutForm.jsp inside /cayambe-hybrid/checkout.

Listing 10.8. CheckOutForm.jsp
...
<script src="https://js.stripe.com/v3/"></script>
<script type="text/javascript">
  var stripe = Stripe({STRIPE_PUBLISH_KEY});                            1
  var elements = stripe.elements();                                     2
...
  var card = elements.create('card', {style: style});

  function stripeTokenHandler(token) {
    // Insert the token ID into the form so it gets submitted to the server
    var cardToken = document.getElementById('cardToken');
    cardToken.value = token.id;                                         3

    // Submit the form
    document.getElementById('orderForm').submit();                      4
  };

  document.body.onload = function() {
    card.mount('#card-element');                                        5

    card.addEventListener('change', function(event) {                   6
      var displayError = document.getElementById('card-errors');
      if (event.error) {
        displayError.textContent = event.error.message;
      } else {
        displayError.textContent = '';
      }
    });

    var form = document.getElementById('orderForm');                    7
    form.addEventListener('submit', function(event) {
      event.preventDefault();

      stripe.createToken(card).then(function(result) {                  8
        if (result.error) {
          // Inform the user if there was an error.
          var errorElement = document.getElementById('card-errors');
          errorElement.textContent = result.error.message;
        } else {
          stripeTokenHandler(result.token);                             9
        }
      });
    });
  };
</script>

<form:form name="OrderForm" styleId="orderForm"
type="org.cayambe.web.form.OrderActionForm"
    action="SubmitOrder.do" scope="request">
...
  <tr>
    <th align="right">
      <label for="card-element">
        Enter card details
      </label>
    </th>
    <td align="left">
      <div id="card-element">                                         10
        <!-- A Stripe Element will be inserted here. -->
      </div>

      <!-- Used to display form errors. -->
      <div id="card-errors" role="alert"></div>
      <form:hidden property="cardToken" styleId="cardToken"/>         11
    </td>
  </tr>
...
</form:form>

  • 1 Create a Stripe JavaScript instance, passing in a publisher key.
  • 2 Initialize the prebuilt UI components from Stripe.
  • 3 Set the token ID you received from Stripe onto the cardToken element.
  • 4 Retrieve the orderForm and submit it.
  • 5 When the document is loaded, mount the Stripe card element onto the card-element div.
  • 6 Add an event listener on the UI component to handle Stripe errors.
  • 7 Add an event listener for submit onto the orderForm.
  • 8 Submit event listener asks Stripe to create a token from the card element in the UI.
  • 9 If Stripe returned success, call the stripeTokenHandler function.
  • 10 Div to hold the card element Stripe will create for you.
  • 11 Add a hidden form field to pass the Stripe card token into OrderActionForm.
Note

The full details of how to integrate UI elements of Stripe into a website can be found at https://stripe.com/docs/stripe-js.

In addition to adding the card capture into the table of the form, you remove all the existing fields that captured each piece of credit card information.

For the preceding CheckOutForm.jsp to work, you also need to modify struts-forms.tld in /cayambe-hybrid/checkout to add styleId to both the form and hidden tags. This allows you to set a name that will be added to the id attribute of the generated HTML element.

That’s all the changes you need for the Payment microservice integration. Now it’s time to integrate Admin!

10.3.2. Integrating the Admin microservice

To integrate Admin, you want to do something similar to Payment—at least in that you want to provide the classes required to send and receive objects to Admin, as well as to generate a proxy from an interface that represents Admin.

In addition to being able to call Admin, you need to integrate the category retrieval into the Cayambe monolith wherever categories are currently used. In looking at how categories are defined within Cayambe, you notice that categories are a separate database table, and the category/parent relationship is present in a separate table.

You also see that categories are called from various layers within the Cayambe monolith, and that the Category EJB provides many ways to interact with the categories that are split across many Java classes. Such a situation doesn’t bode well for a smooth integration of Admin, at least not in the same way that Payment was integrated.

Because the integration would require large code changes across nearly the entire stack, you decide that such an enhancement, though beneficial, has too many risks associated with it. In wanting to be agile and nimble, you don’t want to be held up for weeks or months to integrate Admin because you’re dealing with problems. These problems could be anything from issues in integrating the actual code, to spending a large amount of time testing the new changes in Cayambe—in addition to regression testing to make sure the changes don’t have ripple effects into other parts of the code. It’s unfortunate, but sometimes tough decisions like this need to be made for the stability of production code.

So did I just waste large parts of the book for you to write a new UI and service for Admin that you won’t use? Far from it! In chapter 11, you’ll minimize your risk concerns by using event streaming, allowing you to retain the existing code within the Cayambe monolith but still take advantage of the new Admin UI and microservice.

10.3.3. New administration UI

You’ve seen the new administration UI, along with its associated microservice, but there’s already an administration section inside the Cayambe monolith. You remove the content from /cayambe-hybrid/admin, because you no longer need the existing administration UI. Next you remove all the references to the Admin.war that were present in /cayambe-hybrid/cayambe-ear, as that WAR is no longer a dependency of the EAR and doesn’t need to be packaged inside it.

10.3.4. Cayambe hybrid summary

Figure 10.6 provides the complete picture of where you are currently, as well as the remaining pieces that are yet to be developed. You’ll add the remaining pieces in chapter 11.

Figure 10.6. Cayambe hybrid monolith

10.4. Deploying everything to a hybrid cloud

Because you’ve converted the Cayambe monolith to a hybrid, deploying everything becomes more complex—but you’re also doing everything manually. In a real environment, you’d want the deployments to be automated to make the process even simpler.

This section covers all the pieces of the Cayambe hybrid that need to be set up, configured, or deployed to run it. The first thing you need to do is have Minishift running. It should also start with a clean OpenShift environment, to remove any services that might be present. You’re going to need all the room you can get inside a local OpenShift! So let’s delete any existing Minishift VM (virtual machine) you have and start from scratch:

> minishift delete
> minishift start --cpus 3 --memory 4GB

The main difference from previous executions of Minishift is that you’re specifying three virtual CPUs and 4 GB of memory. This is necessary to ensure that you have the capacity to install the services you need for this and the next chapter.

10.4.1. Database

Let’s create a MySQL database to store your data! Run minishift console and log into the OpenShift console.

Open the default My Project. Click the Add to Project menu item near the top and select Browse Catalog. This provides all the types of prebuilt images that OpenShift can install for you, as shown in figure 10.7.

Figure 10.7. Choosing the Browse Catalog option in the OpenShift console

Click the Data Stores box in the bottom row to see the different data stores available. On the Data Stores page that opens, shown in figure 10.8, click the Select button in the MySQL (Persistent) box.

You’ll be presented with a page containing configuration for MySQL, most of which can be left with the defaults. The only options you need to set are MySQL Connection Username, MySQL Connection Password, and MySQL Root User Password. Enter values for those fields, make a note of that information, and then click Create.

Warning

Don’t use cayambe as the MySQL Connection Username, because that would conflict with the user you need to create later.

Figure 10.8. OpenShift console—data stores

After a minute or two, a MySQL service will be available in OpenShift. To be able to set up the databases, tables, and data that you need for Cayambe, you need to access the service remotely. Open a terminal window, log in to the OpenShift CLI with oc login, and then run oc get pods. The command returns a list similar to this:

NAME                                  READY     STATUS      RESTARTS   AGE
mysql-1-xq98q                         1/1       Running     0          2m

You need to copy the name of the MySQL pod, mysql-1-xq98q in this case, to connect to it:

oc rsh mysql-1-xq98q

From inside the pod, you can then run the following to open a command prompt into the MySQL instance:

mysql -u root -p$MYSQL_ROOT_PASSWORD -h $HOSTNAME

Within the MySQL pod, $MYSQL_ROOT_PASSWORD and $HOSTNAME are defined as environment variables, so you don’t need to remember them to connect to the MySQL instance. Now that you’re inside MySQL, let’s set up the data you need!

Admin microservice data

The following commands create a cayambe-admin user for the admin database, grant the user all privileges to the cayambe_admin database, create the database, and finally switch to using that database:

create user 'cayambe-admin' identified by 'cayambe-admin';
grant all privileges on cayambe_admin.* to 'cayambe-admin' with grant option;
create database cayambe_admin;
use cayambe_admin;

In the context of the cayambe_admin database, you can now execute some SQL to create the tables and populate them with initial data.

Open /chapter10/sql/admin/mysql.sql and paste the contents into the terminal window where you’re logged into MySQL. You should see SQL statements flash by, and if all went well, no errors! Now that the tables are there, do the same with /chapter10/sql/admin/data.sql to load the data.

Payment microservice data

You now run a similar set of commands for a cayambe-payment user and cayambe_payment database:

create user 'cayambe-payment' identified by 'cayambe-payment';
grant all privileges on cayambe_payment.* to 'cayambe-payment' with grant
option;
create database cayambe_payment;
use cayambe_payment;

Now open /chapter10/sql/payment-service/mysql.sql and paste the contents into the terminal window where you’re logged into MySQL. That should create the two tables you need and set an initial value for the ID sequence generator that JPA needs.

Cayambe monolith data

Finally, run a similar set of commands for the cayambe user and database:

create user 'cayambe' identified by 'cayambe';
grant all privileges on cayambe.* to 'cayambe' with grant option;
create database cayambe;
use cayambe;

Open /chapter10/sql/cayambe/mysql.sql and paste the contents into the terminal window, which will create all the tables for the Cayambe monolith. Then copy the contents of /chapter10/sql/cayambe/test_data.sql to load the initial test data.

10.4.2. Security

You already have a Keycloak server that you set up as part of chapter 9, so you’re going to reuse that:

/chapter9/keycloak> java -Dswarm.http.port=9090 -jar keycloak-2018.1.0-
swarm.jar

Open http://localhost:9090/auth/ and log into the administration console. Select the Clients option from the left navigation menu. From the list of available clients, click cayambe-admin-ui to open its details. All you need to do is update the three URLs that specify where your new administration UI is running, by changing the port from 8080 to 8090.

10.4.3. Microservices

Now it’s time to start deploying the microservices to OpenShift.

Admin microservice

Because the Admin microservice was brought across from previous chapters, you don’t need to do anything to it other than deploy it!

/chapter10/admin> mvn clean fabric8:deploy -Popenshift

After this microservice is deployed, you should see it within the OpenShift console.

Stripe microservice

As with Admin, you don’t need to do anything in the Stripe code, so you just deploy it:

/chapter10/stripe> mvn clean fabric8:deploy -Popenshift
Payment microservice

Next, you need to deploy Payment, which is done in the same way as the others:

/chapter10/payment-service> mvn clean fabric8:deploy -Popenshift

10.4.4. Cayambe hybrid

Now you’re ready to set up a WildFly application for the Cayambe hybrid. You can reuse the WildFly 11 and MySQL connector JAR downloads from earlier in the chapter and unpack them into a new directory.

After they’re all extracted, create a directory structure that matches /wildfly-11.0.0.Final/modules/system/layers/base/com/mysql/main. Into that directory, copy the JAR file for MySQL Connector, and create a module.xml file with the following content.

Listing 10.9. MySQL driver module.xml for hybrid
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.3" name="com.mysql">

  <resources>
    <resource-root path="mysql-connector-java-5.1.43-bin.jar"/>        1
  </resources>
  <dependencies>
    <module name="javax.api"/>
    <module name="javax.transaction.api"/>
  </dependencies>
</module>

  • 1 The particular version referenced here needs to match the file you copied into the directory.

Next you need to provide WildFly with the information it needs to configure the datasource for Cayambe. Open /wildfly-11.0.0.Final/standalone/configuration/standalone.xml, and replace the current datasource’s subsystem config with the following.

Listing 10.10. standalone.xml
<subsystem xmlns="urn:jboss:domain:datasources:5.0">
  <datasources>
    <datasource jndi-name="java:jboss/datasources/ExampleDS" pool-
name="ExampleDS"
        enabled="true" use-java-context="true">
      <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-
1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
      <driver>h2</driver>
      <security>
        <user-name>sa</user-name>
        <password>sa</password>
      </security>
    </datasource>
    <datasource jta="true" jndi-name="java:/Climb" pool-name="MySqlDS"
enabled="true" use-ccm="true">
      <connection-url>jdbc:mysql://localhost:53652/cayambe</connection-url>
      <driver-class>com.mysql.jdbc.Driver</driver-class>
      <driver>mysql</driver>
      <security>
        <user-name>cayambe</user-name>
        <password>cayambe</password>
      </security>
      <validation>
        <valid-connection-checker
          class-name="org.jboss.jca.adapters.jdbc.extensions.mysql
.MySQLValidConnectionChecker"/>
        <background-validation>true</background-validation>
        <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.mysql
.MySQLExceptionSorter"/>
      </validation>
    </datasource>
    <drivers>
      <driver name="h2" module="com.h2database.h2">
        <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</
xa-datasource-class>
      </driver>
      <driver name="mysql" module="com.mysql">
        <xa-datasource-
     class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-
class>
      </driver>
    </drivers>
  </datasources>
</subsystem>

Listing 10.10 is virtually identical to listing 10.3, except for one difference: the port number for the MySQL instance for Cayambe is set to 53652. You might be wondering what that port number is from, because it’s not a standard MySQL port. Well, you’re going to define that port by forwarding the mysql service port within OpenShift so you can access it:

oc port-forward {mysql-pod-name} 53652:3306
Note

If an existing forwarded port is shut down, or your machine is rebooted, you’ll have to rerun this command before WildFly will be able to find the database.

10.4.5. Cayambe EAR

Now that WildFly is set up, let’s deploy the modified Cayambe hybrid EAR to it. First you need to build it!

/chapter10/cayambe-hybrid> mvn clean install

After it’s built, copy /cayambe-hybrid/cayambe-ear/target/cayambe.ear into /wildfly-11.0.0.Final/standalone/deployments. Now you start WildFly:

/wildfly-11.0.0.Final/bin/standalone.sh

With WildFly started, it’s now possible to try out the Cayambe UI by opening http://localhost:8080.

10.4.6. Admin UI

The last piece to get running is the new administration UI, because you already have the Admin microservice running from earlier.

For the most part, the code is the same as that you used in chapter 9, with two small modifications. You adjusted the port that the UI runs on to be 8090, so it didn’t clash with the main UI, and you also modified ROOT_URL in /chapter10/admin-ui/app/actions/category-actioxns.js to be the URL shown in the OpenShift console for cayambe-admin-service.

Note

Be sure to remove the trailing slash from the URL.

It’s time to start the administration UI:

/chapter10/admin-ui> mvn clean package
/chapter10/admin-ui> npm start

Summary

  • You set up and ran the Cayambe monolith to show the code as it was before you made any modifications.
  • You integrated the microservices that you’d developed throughout the book into Cayambe, making the necessary modifications to Cayambe to make the integration possible.
  • You learned that although you might want to integrate a microservice (in this case, Admin), sometimes doing so can add too much risk, so other options need to be considered.
  • You deployed the handful of microservices and the Cayambe hybrid and had them all functioning together.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.97.187