This chapter covers
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.
Figure 10.1 provides a reminder of the Cayambe homepage from a user’s perspective.
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).
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.
Running Cayambe locally requires these prerequisites:
With a running MySQL server, you can now set up the 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
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.
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.
<?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>
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.
<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>
That’s all you need to do to configure WildFly to work with 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.
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.
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.
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.
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.
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.
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:
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.
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 ... } }
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.
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; } }
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.
@Path("/") public interface PaymentService { @POST @Path("/sync") 1 @Consumes(MediaType.APPLICATION_JSON) 2 @Produces(MediaType.APPLICATION_JSON) PaymentResponse charge(PaymentRequest paymentRequest); 3 }
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.
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 ); } }
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:
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.
... <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>
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!
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.
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.
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.
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.
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.
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.
Don’t use cayambe as the MySQL Connection Username, because that would conflict with the user you need to create later.
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!
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.
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.
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.
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.
Now it’s time to start deploying the microservices to OpenShift.
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.
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
Next, you need to deploy Payment, which is done in the same way as the others:
/chapter10/payment-service> mvn clean fabric8:deploy -Popenshift
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.
<?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>
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.
<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
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.
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.
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.
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
3.144.97.187