Vertical Components

Combining Web and OSGi Components

I consider myself a latecomer to Microservices; I only really started to understand and use them in 2005. Nobody called them “Microservices” at the time – as far as I can tell, the term was coined in 2006 by BEA for their microService Architecture (mSA). Regardless, with this history it was a little surprising to hear the term reinvented in 2014 and suddenly gain a great deal of traction. While implementation details vary, the fundamental has not changed: small, independently deployable, discoverable services.

I’m always keen to hear from people with a different take, and so in 2014 I found myself listening to a Software Engineering Radio podcast interview with Stefan Tilkov, an expert on REST and software architecture, on the subject of microservices. One of his ideas as elaborated on the podcast was to use microservices to slice applications vertically, rather than the horizontal layering that is much more commonly seen in enterprise architectures. He promotes the idea of a Self-Contained System that includes all of the logic, data and UI for a single business domain. Inclusion of the UI is what makes the approach unconventional: componentisation is relatively commonplace in the back-end, but does not often extend all the way up to the user. This is a fine idea, as it allows technical teams to align with business units. When building horizontal layers (data access layers, application servers, ESBs, etc) developers easily get sidetracked into endlessly polishing frameworks rather than delivering real business value.

The problem was, at least as I saw things at the time, that the UI tier was hard to componentise in this way. The web is by far the dominant UI platform, but web modularity has historically been difficult. The traditional unit of deployment and isolation in the web is the HTML page, but in a modern web application the page is the whole application. Frameworks like Angular and React help in wiring together single-page applications, but didn’t really allow applications to be composed out of independently deployable components. Also, crucially, code written for Angular is useless in a React app and vice versa.

Of course, I was missing the Web Components family of specifications. In my defence, I don’t think many people knew about Web Components, as all the noise seemed to be around the competing frameworks. Also they were not really practical until recently due to the lack of support in browsers. As I write this in mid-2016, however, things have moved forward and Web Components seem to finally be ready for production. This means we can now write independently deployable and reusable components that can be assembled into an application. There are various libraries for building components, but the specifications allow (theoretically!) for components to interoperate irrespective of their implementation details. The application developer can still use a framework to assemble these components into a complete application.

The parallels with OSGi components are very clear. So I started thinking about whether we can combine the two worlds to define vertical components. A web component is often required to invoke logic or retrieve data from a back-end server, which creates a coupling. So what if we could create an artifact that deploys both the front-end and the back-end components together? And then what if we could use the OSGi Resolver to assemble an application out of its required UI and back-end components? So that’s what I have experimented with, and the results seem quite encouraging.

I have shared a proof-of-concept on GitHub, which implements a very simple Shopping Cart component that displays the content of the customer’s cart, retrieved from a back-end REST service.

Web Component Code

I have tried to use as few libraries and assistive technologies as possible, in order to show that nothing magical is happening. So, while libraries like Polymer or Bosonic are handy for creating web components, it’s also pretty easy to define a simple component in plain vanilla ES2015:

(function() {
  let template = `
    <div class="cart-list">
      <h2>Cart Contents:</h2>
      <table class="items-table"></table>
    </div>
  `;
  
  class CartListWidget extends HTMLElement {
    createdCallback() {
      this.createShadowRoot().innerHTML = template;
      this.$table = this.shadowRoot.querySelector('.items-table');
      this.requestServer();
    };
    requestServer() {
      var that = this;
      var xhr = new XMLHttpRequest();

      xhr.open('GET', '/cart-list/servlet/');
      xhr.onload = function() {
        var cart = JSON.parse(xhr.responseText);
        var rows = '';
        for (var i = 0; i < cart.length; i++) {
          var row = '<tr><td>' + cart[i].sku + '</td><td>'
                  + cart[i].price + '</td></tr>';
          rows += row;
        }
        that.$table.innerHTML = rows;
      };
      xhr.send();
    };
  }
  document.registerElement('cart-list', CartListWidget);
})();

OSGi Component Code

The JavaScript file is served from an OSGi bundle that also provides the REST service. I could have used JAX-RS for this, but a plain old Servlet works just as well for such a small demo. I even build the JSON response with printf!

@Component(
    property = {
      HTTP_WHITEBOARD_SERVLET_PATTERN + "=/cart-list/servlet/*",
      HTTP_WHITEBOARD_RESOURCE_PATTERN + "=/cart-list/*",
      HTTP_WHITEBOARD_RESOURCE_PREFIX + "=/cart-list"
    })
@WebComponent(name = "cart-list")
@RequireHttpImplementation
public class CartServlet extends HttpServlet implements Servlet {

  private static final long serialVersionUID = 1L;
  
  @Reference
  private CartManager manager;

  public void doGet(HttpServletRequest request, HttpServletResponse response)
                                        throws ServletException, IOException {
    try (PrintStream out = new PrintStream(response.getOutputStream())) {
      Cart cart = manager.getCart("anonymous");

      StringBuilder builder = new StringBuilder();
      builder.append("[");
      int row = 0;
      for (CartEntry entry : cart.listEntries()) {
        if (row++ > 0) builder.append(',');
        builder.append(String.format("{"sku" : "%s", "price" : %d}",
                       entry.getSku(), entry.getSoldPrice()));
      }
      builder.append("]");
      response.setHeader("Content-Type", "application/json");
      out.print(builder.toString());
      out.flush();
    } catch (Exception e) {
      throw new ServletException(e);
    }
  }
}

Application Code

Finally, the application bundle contains index.html which simply uses the cart-list component we defined:

<!DOCTYPE html>
<html>
<head lang="en">
	<meta charset="UTF-8">
	<title>Bookstore App</title>
	<script src="webcomponents.min.js"></script>
	<script src="/cart-list/component.js"></script>
</head>
<body>
	<h1>Book Store</h1>
	<cart-list></cart-list>
</body>
</html>

Resolution

In the code there are a couple of new annotations, which I have adapted from OSGi en Route. In the web component bundle, the @WebComponent annotation generates a Provide-Capability header in the OSGi bundle manifest that declares our bundle provides the cart-list web component. The @RequireHttpImplementation generates a requirement for an HTTP Service implementation.

In the application bundle we use @RequireWebComponent to require the component that is provided by the web-component bundle. The application bundle also repeats the @RequireHttpImplementation annotation for completeness.

These annotations are used by an OSGi Resolver, such as the build-time resolver in Bndtools or the runtime resolver in Paremus Service Fabric. Because of this, we don’t need to manually list all of the components and libraries used by the application… we only need to list the top-level bundle (in this case org.example.webapp.bookstore which contains the index.html) and the tooling will automatically pull in the cart-list component bundle along with an HTTP Service implementation such as Jetty.

Conclusion

This is just a proof-of-concept and there are many details that could be improved. For example, the mapping between the component name and the URL of the JS and Servlet could be handled by a small server-side framework. Using third-party components from Bower or NPM could be made simpler, perhaps via an extender bundle.

What do you think… is this a useful approach? What flaws have I missed? Let me know in the comments, or using the contact details to the right.

If you are interested in learning more about web development with OSGi, and about modern component-oriented development with Java, then please consider supporting my new book, Effective OSGi, or buying a copy when it is published!


Share This:
twitterlinkedinFacebookredditpinterestmail

Functional Transaction Management – old dog, new tricks! 3 comments

This blog post is all about the new Transaction Control service which is proposed to be part of the next release of the OSGi Enterprise Specification. Paremus has been leading this specification work, which arose from a collaboration with one of our customers, McCarthys. The current state of the RFC is available on GitHub, and there’s even an implementation available in Apache Aries.

Before we delve into the cool features of the Transaction Control service, it’s probably worth remembering why we need yet another transaction abstraction… (more…)


Share This:
twitterlinkedinFacebookredditpinterestmail

The Paremus Service Fabric has no Opinions…

The emergence of the ‘Opinionated’ Microservices Platform continues apace.

We are told that business systems should be REST/Microservice based. We are told that containers should be used everywhere and container images are the deployment artefact du jour: I mean lets face it Virtual Machine Images are so last year! And of-course Reactive is the new cool.

A depressing state of affairs. These messages are at best half-truths. At worst – the IT industry’s ongoing equivalent of Snake Oil.

So (more…)


Share This:
twitterlinkedinFacebookredditpinterestmail

Modularity, Microservices and Containers

My colleague, Derek Baum, had an article published in Jaxenter last week called “Modularity, MicrJaxenter Feb 2016oservices and Containers“.

The article discusses how Microservices and Containers are examples of a general industry drive towards modularity. It goes on to demonstrate how OSGi’s Service-centric approach, its Requirements & Capabilities model, and the OSGi Remote Services specification provide an excellent solution for a containerised microservices solution.

Yes thats right, these concepts/technologies/trends aren’t competing with each other as many would have you believe. In fact they can all be complimentary when used with Paremus Packager.

Paremus Packager integrates the lifecycle of external (non-Java) applications with OSGi and provides a consistent means to start, stop, configure and inter-connect services and we will be making an early access release of the new Docker-based Paremus Packager available to a restricted audience in Q1 2016.  You can sign up for this online with just your email address.

The article is a is a follow up to the presentation of the same name given at the OSGi Community Event in 2015, by Neil Bartlett [ Slides / Video ] and these are a good source of info if you would like to learn more. Of course you can also add comments below if you have any questions.


Share This:
twitterlinkedinFacebookredditpinterestmail

Asynchronous Event Streams @ MadridJUG

Some of the Paremus team were in Madrid last week (Jan 11 to 14, 2016) for the OSGi Expert Group meetings and also an OSGi Alliance Board Meeting.

Thanks to Jorge Ferrer for picture from twitter (@jorgeferrer)

Thanks to Jorge Ferrer for picture from Twitter

While we were in town, our CTO, Tim Ward, was invited to speak at the MadridJUG on the work he has been leading within the OSGi Enterprise Expert Group on Asynchronous Event Streams. This relatively new OSGi Alliance specification is highly relevant to the use of OSGi in IoT as well as in Enterprise.

The subject proved to be an interesting topic to the MadridJUG members with good attendance and lots of questions.

Thanks to Liferay Spain (@liferay_es) for hosting the Meetup and MadridJUG (@MadridJUG) for inviting Tim to present.

 

Tim also presented this talk at the OSGi Community Event last year and you can find a video of this here and the slides here.

 

It looks like the OSGi Alliance will be having face to face meetings in Chicago, Ghent and Ludwigsburg in the coming months. If you are interested in getting someone from Paremus to come and present on anything OSGi or our products while we are in your neighbouthood then please let us know.

 


Share This:
twitterlinkedinFacebookredditpinterestmail