Container-Component Architectures

Concepts

·       Container-Component Architectures

Technology

·       Reflection

OpenApp: A simple container-component system

User-defined components are managed by the OpenApp container:

An interface has a name and a set of methods.

Normally a method would consists of a name, return type, and list of parameter types, but OpenApp assumes all methods take an array of strings as input and return a string:

String someMethod(String ... args); // note we are using varargs

The Component base class maintains two sets of interfaces: provided and required. It also maintains a table that matches names of required interfaces to components that provide those interfaces.

The execute method takes the name of an interface, the name of a method in that interface, and an array of arguments:

public String execute(String intfName, String method, String ... args) throws Exception {...}

It uses the interface name to search the providers table for an appropriate component, then invokes that component's dispatch method:

provider.dispatch(method, args);

The container maintains two tables that associate interfaces with components: yellowPages and required. When a component is added to the container, it associates the component's provided interfaces with the component in the yellow pages table, and associates the required interfaces to the component in the required table. Finally, it calls connectInterfaces, which attempts to find providers for each required interface by looking in the yellow pages. If it finds a match, it associates the name of the required interface with the provider in the component's providers table. The association in the required table is then removed.

 

The console method provides a primitive user interface for the container. A second add method uses Java's Class.forName method to load components from their .class files.

Example

Assume an area calculator component provides methods for calculating the areas of circles and triangles (IArea). But it requires methods for doing simple arithmetic (ICalc). These are provided by a calculator component. Here's the situation in the form of a UML component diagram:

To use OpenApp developers of each component extend the container package's Component class:

The only extra baggage is that a dispatch method must be provided and the required and provided interfaces must be defined:

Calculator.java

AreaCalc.java

TestComponents.java

Here's a sample session:

-> add 3.14 2.71
5.85
-> mul 6 7
42.0
-> div 1 7
0.14285714285714285
-> sub 1 9
-8.0
-> circleArea 10
314.1592653589793
-> triangleArea 6 10
30.0
-> fooBar 1 2 3
fooBar unavailable
-> help
Sorry, no help is available
-> quit
bye

Lab

Implement and test the Container, Component, and Interface classes.

Lab

Implement and test the following components:

Note: A word contains no white space characters. Use text.split("\\s+") to split text into an array of words.

Exchange your StringOps.class file with a stranger to prove your container works with third-party components.

Lab

A container provides discovery if it allows components and users to discover what interfaces are currently provided. Provide a discovery feature for your container class. The console should allow users to see what interfaces are provided by using the help command and the add method should warn users if required interfaces cannot yet be connected to providers.

Lab

Implement and test OpenApp 2.0 using Java reflection. This allows any object to discover the methods implemented by a would-be provider. In other words, any Java objects is a component, and Java has a built-in Interface class, so no Interface or Component class should be needed in OpenApp 2.0.