artykuły java.net

Syndicate content
Updated: 1 godzina 19 min ago

Rapid Web Services Development with Moose XML

Śr, 2010-04-28 22:34
Learn how Moose XML can simplify the task of prototyping and rapidly developing XML web services Rapid Web Services Development with Moose XML Wed, 2010-04-28 Michael Quigley Learn how Moose XML can simplify the task of prototyping and rapidly developing XML web services.

Moose XML is a framework that provides a set of components for getting XML data into and out of Java applications. Moose XML was created after I had experienced some of the rough edges in existing XML marshalling solutions when used in web services environments. Wherever possible, design choices have been made to simplify Moose XML's support for "contract last" web services development.

Moose XML's schema generator is what distinguishes it from the other frameworks. The schema generator can generate an XML schema directly from your annotated Java beans. These generated schemas are useful for driving "contract last" web services development approaches. When combined with the WSDL plumbing in your favorite web services toolkit, the schema generator can make the rapid development of web services applications a reality. Because the stack is automatically managing your schemas, your mapping code is easily refactored, expanded, and maintained alongside your other Java code—changes flow directly from your annotated Java beans into your generated WSDL.

This article will give you a quick tour of Moose XML. I'll start by showing you the basics of creating a mapping. I'll finish by showing you how this can be plugged into Spring Web Services, creating a rapid web services development stack. We'll create a simple "purchase order" web service, allowing for storage and retrieval of simplified purchase order data.

More information is available at the Moose XML website. The full source code of this example is available in the Moose XML source distribution. Links are provided in the Resources section at the bottom of the article.

Creating the Mapping

Our service stores and retrieves "purchase orders". Imagine that these purchase orders are for software licenses. As such, each purchase order contains a "licensee" and "license type" and a currency "amount". Purchase orders are identified by a numeric "identifier". The license type is represented using a Java 5 enum named LicenseType.

Each operation needs to include a "request" and "response" message. We'll start with the CreatePurchaseOrderRequest and CreatePurchaseOrderResponse types:

package com.quigley.moose.example.service; public class CreatePurchaseOrderRequest { // getters and setters removed for brevity private String licensee; private LicenseType licenseType; private Float amount; } package com.quigley.moose.example.service; public class CreatePurchaseOrderResponse { // getters and setters removed for brevity private Long identifier; }

Simple POJO classes like these make up our mapping layer. We'll need to add a few annotations so that Moose XML understands how to marshall and unmarshall instances of these classes:

package com.quigley.moose.example.service; import com.quigley.moose.mapping.provider.annotation.*; @XML(name="createPurchaseOrderRequest") public class CreatePurchaseOrderRequest { // getters and setters removed for brevity @XMLField(name="licensee") private String licensee; @XMLField(name="licenseType") private LicenseType licenseType; @XMLField(name="amount") private Float amount; } package com.quigley.moose.example.service; import com.quigley.moose.mapping.provider.annotation.*; @XML(name="createPurchaseOrderResponse") public class CreatePurchaseOrderResponse { // getters and setters removed for brevity @XMLField(name="identifier") private Long identifier; }

The @XML annotation defines the class-level mapping details. Each of the @XMLField annotations define the field-level mapping details. The Moose XML developer guide contains information on many other annotations, which are useful for more complicated mapping scenarios.

Marshalling and Unmarshalling

In order to initialize Moose XML, the application will need to acquire a Mapping instance. A Mapping instance is typically obtained by instantiating and configuring a MappingProvider instance. Here's an example:

StaticClassesProvider classesProvider = new StaticClassesProvider(); classesProvider.addClass(CreatePurchaseOrderRequest.class); AnnotationMappingProvider mappingProvider = new AnnotationMappingProvider(classesProvider); Mapping mapping = mappingProvider.getMapping();

The Mapping class is central to Moose XML. Once your application has access to a Mapping, performing operations with the framework is straightforward.

The following code snippet illustrates how to use a Mapping to marshall a CreatePurchaseOrderRequest object out to XML:

CreatePurchaseOrderRequest request = new CreatePurchaseOrderRequest(); request.setAmount(64.95F); request.setLicensee("Benjamin Franklin"); request.setLicenseType(LicenseType.Renewal); MarshallingContext ctx = new MarshallingContext(); mapping.marshall(request, ctx); String xml = ctx.getOutput().toString();

Here's how to unmarshall a CreatePurchaseOrderRequest from XML:

CreatePurchaseOrderRequest request = (CreatePurchaseOrderRequest) mapping.unmarshall(xml);

Generating a XML schema from your Mapping instance is no more difficult:

String xsd = SchemaGenerator.generate(mapping); Spring Web Services Integration

For the remainder of this example, I'm going to assume that you're familiar with the Spring Web Services framework and SOAP web services. Instead of describing every part of the configuration, we'll just look at the parts where Moose XML facilitates rapid web services development.

Our example contains a single "endpoint" class, which is used to expose the web service operations. This example uses the Spring @Endpoint and @PayloadRoot annotations to establish a service endpoint. Here is a snippet from the example service endpoint to illustrate the pattern:

@Endpoint public class ServiceEndpoint { @PayloadRoot(localPart="createPurchaseOrderRequest", namespace="http://quigley.com/moose/example/service/") public CreatePurchaseOrderResponse createPurchaseOrder(CreatePurchaseOrderRequest req) { // } }

When configured, Spring will route incoming messages to the method which matches the @PayloadRoot annotations defined in your @Endpoint classes. Spring Web Services also needs to know how to convert the incoming and outgoing XML to and from the parameter types and return values of your endpoint methods. Spring Web Services provides a nice AbstractMarshaller class, which facilitates the integration of various marshalling frameworks into Spring. Moose XML extends AbstractMarshaller to provide a MooseMarshaller type.

The bulk of the magic happens in our Spring context configuration:

<beans> <!-- xmlns and schema location declarations removed for brevity --> <context:annotation-config/> <bean id="serviceEndpoint" class="com.quigley.moose.example.service.ServiceEndpoint"/> <bean id="service" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition"> <property name="schema"><ref bean="mooseSchema"/></property> <property name="portTypeName"><value>ExampleService</value></property> <property name="locationUri"><value>http://localhost:8080/example/</value></property> </bean> <bean class="org.springframework.ws.server.endpoint.adapter. GenericMarshallingMethodEndpointAdapter"> <constructor-arg ref="mooseMarshaller"/> </bean> <bean class="org.springframework.ws.server.endpoint.mapping. PayloadRootAnnotationMethodEndpointMapping"/> <bean id="mooseMarshaller" class="com.quigley.moose.spring.MooseMarshaller"> <property name="mappingProvider"><ref bean="mooseMappingProvider"/></property> </bean> <bean id="mooseMappingProvider" class="com.quigley.moose.mapping.provider.annotation.AnnotationMappingProvider"> <property name="xmlNamespace"> <value>http://quigley.com/moose/example/service/</value></property> <property name="xmlPrefix"><value>es</value></property> <property name="annotatedClassesProvider"><ref bean="mooseClassesProvider"/></property> </bean> <bean id="mooseClassesProvider" class="com.quigley.moose.mapping.provider.annotation.StaticClassesProvider"> <property name="classes"> <list> <value>com.quigley.moose.example.service.CreatePurchaseOrderRequest</value> <value>com.quigley.moose.example.service.CreatePurchaseOrderResponse</value> <value>com.quigley.moose.example.service.RetrievePurchaseOrderRequest</value> <value>com.quigley.moose.example.service.RetrievePurchaseOrderResponse</value> </list> </property> </bean> <bean id="mooseSchema" class="com.quigley.moose.spring.MooseXsdSchema"> <property name="mappingProvider"><ref bean="mooseMappingProvider"/></property> </bean> </beans>

Notice the GenericMarshallingMethodEndpointAdapter. It's intended to take an instance of AbstractMarshaller as a constructor argument. We're configuring it to use our MooseMarshaller. This bean configuration is what allows our service endpoint to magically marshall and unmarshall XML to and from the methods of our ServiceEndpoint class.

The most interesting bits are the mooseSchema bean and the service bean. This combination of beans connects Moose XML's schema generator to the WSDL generation capabilities in Spring Web Services. With that linkage in place, any changes you make to your mapping beans will be automatically reflected in your WSDL.

Building the Example from the Source Distribution

Download the Moose XML source distribution from the link below. Extract the distribution into a directory. From the directory where you extracted the source distribution, execute:

$ ant -f build-example.xml example-service

When that completes successfully, you can start up a fully-configured container, pre-loaded with this example, by executing:

$ build/example-service/deploy/server/bin/run.sh Conclusion

There are many tools and frameworks for getting XML data into and out of Java applications. Moose XML tries to smooth some of the rough edges that are typically encountered when prototyping and rapidly developing XML web services. In these scenarios, generating the schema and contract information from code ("contract last") seems to be the least cumbersome methodology.

Development is currently underway extending Moose XML to support "contract first" development approaches. The centerpiece is a new tool which can ingest an existing XML schema, and generate an annotated mapping layer. This functionality will be available before Moose XML hits version 1.0.

Resources Michael Quigley is a software architect, a musician, a sailor, and a lover of animals. He enjoys spending his time somewhere in the confluence of technology and the arts and wants your development projects to be awesome.

The Match Maker Design Pattern - a New Place for the Actions

Wt, 2010-04-27 04:19
How to add actions to a system without modifying business objects, add objects without changing actions, and still keep things reusable. The Match Maker Design Pattern Tue, 2010-04-27 Michael Bar-Sinai How to add actions to a system without modifying business objects, add objects without changing actions, and still keep things reusable.

Software systems often deal with similar concepts, whose behavior differs only slightly. Classic Object-Oriented design deals with such cases using inheritance; overriding the calculateSalary() method in different Employee subclasses allows the rest of the application to remain oblivious to the subtle differences between the salary algorithms of Manager, Engineer, and AnnoyingCeoNephew.

Sadly, inheritance doesn't scale very well. You might get away with adding a toXml() method to the business model objects, but when the customer requires data export support for Excel, OpenOffice, CSV, JSON and Lotus 1-2-3 - you know inheritance just ain't gonna cut it. Another issue with inheritance is that when one holds an Employee reference to an object and needs to know the its actual type, one has to downcast, which probably means one is going to get some runtime exceptions.

Modern Object-Oriented design sometimes separates the actions from the objects, using mainly the Visitor pattern. Sadly, this solution is not applicable in many common situations - the classes must implement the accept() method, so if you're using a third party API - you're out of luck. If you wrote that API, you would be reluctant to use the visitor pattern, as adding new visitable objects in later releases would require adding methods to the visitor interface, thus breaking existing client code that implements it.

Another approach is using the instanceof operator all over the code, which normally creates huge if-else chains, is hard to test and debug, and is prone to logic errors as the order of the if checks has to be done up the type hierarchy - if you check for Employee at line 100, the check for Manager at line 300 might never be executed.

The "where does the action go" dilemma is actually an age-old problem, normally referred to as "The Expression Problem" (See the Resources section for some links). It boils down to "it is either easy to add types, or it is easy to add operations". This article is (yet another) poke on the problem - we will see how one can add actions to the system without modifying the business objects, add objects without changing the actions, and still keep things reusable, testable, and clear. As an aside, this pattern allows us to change the application behavior on the fly, lends itself to using closures, and allows Java to implement Scala-style case class pattern matching.

Unfortunately, this is not a silver bullet - static type safety is somewhat compromised. Later in the article we will offer an effectively type-safe solution.

Making Matches

As the astute reader might have expected, the match maker pattern involves an object that makes matches between business objects to objects that act on them. The usage, shown below, is simple. At the setup, the client code registers class-handler pairs. In our example, the handler classes implement EmployeeHandler, an interface with a method handle(Employee e).

// Setup MatchMaker<class<? extends Employee>, EmployeeHandler> m = new MatchMaker(); m.registerHandler( Manager.class, new ManagerHandler() ); m.registerHandler( Engineer.class, new EngineerHandler() ); .... // Usage for ( Employee emp : staff ) { EmployeeHandler h = m.match(emp); h.handle(emp); // line X }

Below is the code that deals with the managers:

class ManagerPrinter implements EmployeeHandler { public void handle(Employee emp) { System.out.println( emp.getGivenName() + " " + emp.getFamilyName() + " manages the " + ((Manager)emp).getDepartmentName() + " dept." ); } }

At a glance, it looks like we could get away with implementing a match maker using a simple Map. We can't.

Sooner or later the organization would hire an employee who deserves a class of his own (say, an AnnoyingCeoNephew, who also implements the infamous YouTubeUploader interface). When the above loop would get to that employee, no handler would be found, and so we will get a NullPointerException on line X. What's more, a movie documenting the embarrassment would probably be featured in YouTube.

Dealing With New Classes On The Fly

A MatchMaker instance does hold a Map mapping classes to handlers, but with a twist. When it is given an instance of a class for which a handler was not explicitly specified, it embarks on a breadth-first search (BFS) up the class hierarchy, starting from that object's class, looking for a class for which a handler was explicitly specified. A property of BFS is that it ensures that the class found is the closest one to the original object's class. Note that there might be a few classes with the same distance. Below is the BFS code; the rest of the class is removed for brevity. Full implementations and examples are available in the Resources section.

protected Handler getExplicitHandler(Class<? extends BaseClass> valClass) { // the BFS' "to be visited" queue Queue<Class<?>> queue = new LinkedList<Class<?>>(); // the class objects we have visited Set<Class<?>> visited = new HashSet<Class<?>>(); queue.add(valClass); visited.add(valClass); while (!queue.isEmpty()) { Class<?> curClass = queue.remove(); // get the super types to visit. List<Class<?>> supers = new LinkedList<Class<?>>(); for (Class<?> itrfce : curClass.getInterfaces()) { supers.add(itrfce); } // this would be null for interfaces. Class<?> superClass = curClass.getSuperclass(); if (superClass != null) { supers.add(superClass); } for (Class<?> ifs : supers) { if (explicitHandlers.containsKey(ifs)) { return explicitHandlers.get(ifs); } if (!visited.contains(ifs)) { queue.add(ifs); visited.add(ifs); } } } return explicitHandlers.get(Object.class); }

The BFS looks at implemented interfaces before looking at the superclass of the object. This behavior normally creates better matches, especially in shallow class hierarchies where most of the classes extend Object directly, and implement a few interfaces (a similar approach is taken by Javadoc's {@inheritDoc} attribute). Considering the superclass last also allows for a convenient way for specifying a default handler - just register a handler for the base class, and it will by returned if no other handler is found. The found handler is cached (this time on a simple Map); so next time, finding the handler would be an O(1) issue.

For instance, in Figure 1, SwingEngineer instances would be handled by H1, J2meEngineer instances by H2, and JeeEngineer instances by H3. When the company would hire a JTableMaster (blue) it will automatically be handled by the H1, which knows how to handle Swing Engineers and is probably the most appropriate handler for such an expert. H4 is a bit of a "catch-all", handling all employees for which no better matching handler was found.


Figure 1. Class hierarchy and handlers example.

Making it (Almost) Statically Type-Safe

Seasoned developers would probably frown at the type safety of this pattern. The handlers have to downcast the object they get, and there's no guarantee that the handler registered to handle a class can actually handle it. It's time for some wildcards.

First, we need to get the handlers to declare what class they handle. The HandlerOf<ClassToHandle> interface does just that - it is a designator interface (i.e. no methods, like java.io.Serializable).

public interface HandlerOf<ClassToHandle> {}

Suppose we need to print a list of Employees to System.out. We define a base class to handle the base Employee class, both for code reuse and for having a default handler for any employee type in the list. Then we subclass it to handle subclasses (full code is available in the Resources section):

class EmployeePrinter implements HandlerOf<Employee> { public void handle( E emp ) { printPersonalDetails(emp); } protected void printPersonalDetails( Employee emp ) { ... } } class ManagerPrinter extends EmployeePrinter implements HandlerOf<Manager> { @Override public void handle( Manager m ) { super.handle(m); System.out.println("- Manages " + m.getDepartmentName()); } }

Don't try to run it - it wouldn't compile. The problem is that one cannot override a type parameter. Once a generic class had its type parameter specified, there's no turning back. Luckily, we can turn sideways: make the base class abstract and limit its type parameter using wildcards:

abstract class AEmployeePrinter<E extends Employee> implements HandlerOf<E> { public void handle( E emp ) { printPersonalDetails(emp); } protected void printPersonalDetails( Employee emp ) { ... } } class EmployeePrinter extends AEmployeePrinter<Employee>{} class ManagerPrinter extends AEmployeePrinter<Manager> { @Override public void handle( Manager m ) {...} } class J2meEngineerPrinter extends AEmployeePrinter<J2meEngineer> { @Override public void handle( J2meEngineer m ) {...} } class EngineerPrinter extends AEmployeePrinter<Engineer> { @Override public void handle( Engineer m ) {...} }

Note that the compiler forces us to handle the correct class. If the ManagerPrinter would have implemented only a handle(Employee) method, the code wouldn't compile. Consequently, the downcasting is gone.

We now turn to the MatchMaker's register() method. It has to ensure that the client code cannot register a handler to a class it can't take care of:

public class MatchMaker<Input, Output extends HandlerOf<? super Input>> { ... public <T extends Input> void registerHandler(Class<T> aClass, HandlerOf<? super T> aHandler) { ...} }

The above declaration might look slightly daunting, so let's look into it. We want to make sure that only handlers of a class, or superclasses of it, could be registered with that class. This is why we declare the handler as <? super T> rather than <T>. But we wouldn't want just any T - it has to be a T that extends Input. Constraining T is done at the beginning of the declaration, as is applies to all occurrences of T in the declaration. As shown in Figure 2, static analysis (NetBeans, in this case) can detect wrong handler-class registration at design time.


Figure 2. The compiler complains about registering handlers for classes they can't handle.

How Type Safe is it?

Deep in the internals of the matchmaker, maps store the handlers as Objects, and cast them to Handlers, before returning them from the match() method. Drawing on Brian Goets' "Effectively Immutable" idiom, we could call this approach effectively type safe, since:

  1. The client code cannot enter anything that's not a Subclass of Output, hence downcasting to Output is safe;
  2. The BFS algorithm, when implemented correctly, will always return a handler capable of handling the instance; and
  3. The normal usage would be to get the handler from the match and use it immediately.

Still, switch the instance after the match, and get a ClassCastException on a downcast you did not do. Hey, I said it's not a silver bullet.

Summary

We have seen the Match Maker pattern, which allows programmers to:

  • add actions on objects without modifying the objects those actions operate on;
  • add objects and have appropriate actions automatically operate on them; and
  • work on a subclass while holding only a superclass reference to it, without downcasting.

We have seen two implementations, one simple yet not statically type safe, and one effectively type safe. Creating a full statically type safe solution is left as an exercise to the reader, providing the reader is looking for a subject for a PhD thesis.

I have used this this pattern in production code for analyzing emails, drawing tables, building UI, and handling JMS messages; I hope you'll find it useful too.

Resources Michael Bar-Sinai is a Senior Software Architect at Be'eri Print AttachmentSize matchmaker-sample-code.zip9.82 KB Art20100427_complex-hierarchy.png42.62 KB Art20100427_static-type-safety.png14.72 KB

HTML5 Server-Push Technologies, Part 2

Po, 2010-04-26 20:15
In the colclusion to his two-part series, Gregor Roth covers the new HTML5 WebSockets protocol. HTML5 Server-Push Technologies, Part 2 Mon, 2010-04-26 Gregor Roth In the colclusion to his two-part series, Gregor Roth covers the new HTML5 WebSockets protocol.

The upcoming HTML5 specification includes a lot of powerful and exiting features which turn web browsers into a fully capable ich internet application (RIA) client platform. Part 1 of this article series presented an overview of the history of the web, and investigated the new HTML5 Server-Sent Events communication standard.

2.2 WebSockets

The upcoming HTML5 standard also includes WebSockets. WebSockets enables establishing a bidirectional communication channel. In contrast to Server-Sent Events, the WebSocket protocol is not build on top of HTTP. However, the WebSocket protocol defines the HTTP handshake behaviour to switch an existing HTTP connection to a lower level WebSocket connection. WebSockets does not try to simulate a server push channel over HTTP. It just defines a framing protocol on top of TCP. In this way WebSockets enables two-way communication natively.

Like the Server-Sent Events specification, WebSockets specifies an API as well as a wire protocol. The WebSockets API specification includes a new HTML element, WebSocket.

Listing 5. Example JavaScript using the WebSocket interface
<html> <head> <script type='text/javascript'> var ws = new WebSocket('ws://localhost:8876/Channel', 'mySubprotocol.example.org'); ws.onmessage = function (message) { var messages = document.getElementById('messages'); messages.innerHTML += "<br>[in] " + message.data; }; sendmsg = function() { var message = document.getElementById('message_to_send').value document.getElementById('message_to_send').value = '' ws.send(message); var messages = document.getElementById('messages'); messages.innerHTML += "<br>[out] " + message; }; </script> </head> <body> <form> <input type="text" id="message_to_send" name="msg"/> <input type="button" name="btn" id="sendMsg" value="Send" onclick="javascript:sendmsg();"> <div id="messages"></div> </form> </body> </html>

A WebSocket will be established by creating a new WebSocket instance. The constructor takes one or two arguments. The WebSocketURL argument specifies the URL to connect. A WebSocketURL starts with the new scheme type ws for a plain WebSocket connection or wss for secured WebSocket connection. Optionally, a second parameter protocol can be set which defines the sub-protocol to be used (over the WebSocket protocol). As with the EventSource element, an onmessage handler can be assigned to a WebSocket, which will be called each time a message is received. Data will be sent by calling the send() method.

If a new WebSocket is created, first the underlying user agent will establish an ordinary HTTP(S) connection to the host of the URL. Based on this new HTTP connection, an HTTP upgrade will be performed. The HTTP specification defines the upgrade header field to do this. The upgrade header is intended to provide a simple mechanism for transition from HTTP protocol to other, incompatible protocols. This capability of the HTTP protocol is used by the WebSocket specification to switch the newly created HTTP connection to a WebSocket connection. By adding the optional WebSocket-Protocol header, a specific sub-protocol is requested.

REQUEST: GET /Channel HTTP/1.1 Upgrade: WebSocket Connection: Upgrade Host: myServer:8876 Origin: http://myServer:8876 WebSocket-Protocol: mySubprotocol.example.org RESPONSE: HTTP/1.1 101 Web Socket Protocol Handshake Upgrade: WebSocket Connection: Upgrade WebSocket-Origin: http://myServer:8876 WebSocket-Location: ws://myServer:8876/Channel WebSocket-Protocol: mySubprotocol.example.org Figure 2. WebSocket upgrade handshake

After receiving the response HTTP header, data will be transmitted according to the WebSocket protocol. This means at this point only WebSocket frames will be transferred over the wire. A frame can be sent at each time in each direction. The WebSocket protocol defines two types of frames: a text frame and a binary frame. Each text frame starts with a 0x00 byte and ends with a 0xFF byte. The text will be transferred UTF8-encoded between the start and the end byte. A text frame requires only 2 additional bytes for packaging purposes. Figure 3 shows a text frame for the string "GetDate" and the string "Sat Mar 13 14:00:25 CET 2010".

Text frame of "GetDate": 0x00 0x47 0x65 0x74 0x44 0x61 0x74 0x65 0xFF Text frame of "Sat Mar 13 14:00:25 CET 2010": 0x00 0x53 0x61 0x74 0x20 0x4D 0x61 0x72 0x20 0x31 0x33 0x20 0x31 0x34 0x3A 0x30 0x30 0x3A 0x32 0x35 0x20 0x43 0x45 0x54 0x20 0x32 0x30 0x31 0x30 0xFF Figure 3. Text frame example

Binary data can be transferred by using a binary frame. A binary frame starts with 0x80. In contrast to the text frame the binary frame does not use a terminator. The start byte of a binary frame is followed by the length bytes. The number of length bytes is given by the required bytes to encode the length. Figure 4 shows the binary frame for a small number of bytes to transfer which requires one length byte as well as a larger binary frame which requires two length bytes.

binary frame of 0x00 0x44: 0x80 0x02 0x00 0x44 binary frame of 0x30 0x31 0x32 0x33 0x34 0x35 [?] 0x39 (1000 bytes): 0x80 0x87 0x68 0x30 0x31 0x32 0x33 0x34 0x35 [?] 0x39 Figure 4. Binary frame example

Because JavaScript cannot operate with binary data represented as a byte array, the binary frame type is limited to be used for languages other than JavaScript. In addition the binary frame and text frame, new frames types can be introduced by future releases of the WebSocket protocol specification. WebSocket's framing is designed to support new frame types. A connection can be closed at any time. No extra end-of-connection byte or frame exists.

The overhead involved managing a WebSocket is very minimal. Comet protocols such as Bayeux and BOSH, for instance, uses some "hacks" to break the HTTP Request-Response barrier. This forces such protocols to implement a complex session and connection management. Due the fact that WebSockets is not implemented on the top of HTTP it will not run into trouble caused by HTTP protocol limitations.

On the other hand WebSockets, does almost nothing for reliability. It does not include reconnect handling or support guaranteed message delivery like Server-Sent Event does. Further more, as a non-HTTP based protocol, WebSocket cannot make use of the built-in reliability features of HTTP. For instance HTTP supports auto-retry execution strategies in case of network errors. Based on the fact that a GET method can be executed at any time without side effects, a GET method will be re-executed by browsers and modern HttpClients automatically, if a network error occurs. A GET method must not change the server-side resource state by definition and is therefore safe.

This means reliability has to be implemented in the application (sub-protocol level) when using WebSockets. The same is true for the "keep alive" message approach to avoid a proxy server dropping the connection after a small period of inactivity. Additionally, sharing a WebSocket between different pages often causes trouble. In contrast to Server-Sent Events, a WebSocket also includes an upstream channel which is difficult to share. For instance, concurrent writes and reads have to be synchronized, which is not a simple task. This general challenge also affects bidirectional Comet protocols such as Bayeux or BOSH. When using WebSockets, the per-server connection limitation has to be considered carefully.

As with the origin policy used by web browsers to restrict browser-side programming languages from contacting the server, a WebSocket server will only be contacted if the web page is loaded from the same domain. This is not true for stand-alone WebSocket clients such as shown in Listing 6. Such clients contact the WebSocket server in a direct way without same origin policy limitations.

Listing 6. Example Java Client class MyWebSocketHandler implements IWebSocketHandler { public void onConnect(IWebSocketConnection wsCon) throws IOException { } public void onMessage(IWebSocketConnection wsCon) throws IOException { IWebMessage msg = wsCon.readMessage(); System.out.println(msg.toString()); } public void onDisconnect(IWebSocketConnection wsCon) throws IOException { } } MyWebSocketHandler hdl = new MyWebSocketHandler (); IWebSocketConnection wsCon = httpClient.openWebSocketConnection( "ws://myServer:8876/WebSocketsExample", "mySubprotocol.example.org", hdl); wsCon.writeMessage(new TextMessage("GetDate")); // ...

Listing 7 shows an example WebSocket Server implementation. The server handler implements two interfaces: the IHttpRequestHandler handles ordinary HTTP requests and the IWebSocketHandler handles WebSocket connections. In the case of a standard HTTP request (without the upgrade request) the IHttpRequestHandler's onRequest() method will be called. If the client opens a WebSocket, the server will handle the HTTP upgrade and call the IWebSocketHandler's onConnect() method. Each time a WebSocket message is received, the IWebSocketHandler's onMessage() method is called.

Within the onConnect() method some preconditions can be checked. For instance if a required sub-protocol is not supported, the example server will return an error status. Furthermore the origin header will be checked. As is the case with the referer header, the origin header will be set by the browser automatically. The origin header is defined by the HTTP Origin Header RFC, which is in draft. In contrast to the referer header, the origin header includes the domain name of the page's source only. Each time embedded code makes a request, the browser adds the origin header which contains the origin page's domain. Web Servers can block requests that send invalid origin headers.

Listing 7. Example Java WebSocket Server class ServerHandler implements IHttpRequestHandler, IWebSocketHandler { // IHttpRequestHandler method public void onRequest(IHttpExchange exchange) throws IOException { String requestURI = exchange.getRequest().getRequestURI(); if (requestURI.equals("/WebSocketsExample")) { sendWebSocketPage(exchange, requestURI); } else { exchange.sendError(404); } } private void sendWebSocketPage(IHttpExchange exchange, String uri) throws IOException { String page = "<html>\r\n " + " <head>\r\n" + " <script type='text/javascript'>\r\n" + " var ws = new WebSocket('ws://" + exchange.getRequest().getHost() + "/Channel', 'mySubprotocol.example.org');\r\n" + " ws.onmessage = function (message) {\r\n" + " var messages = document.getElementById('messages');\r\n" + " messages.innerHTML += \"<br>[in] \" + message.data;\r\n"+ " };\r\n" + " \r\n" + " sendmsg = function() {\r\n" + " var message = document.getElementById ('message_to_send').value\r\n" + " document.getElementById('message_to_send').value = ''\r\n" + " ws.send(message);\r\n" + " var messages = document.getElementById('messages');\r\n" + " messages.innerHTML += \"<br>[out] \" + message;\r\n"+ " };\r\n" + " </script>\r\n" + " </head>\r\n" + " <body>\r\n" + " <form>\r\n" + " <input type=\"text\" id=\"message_to_send\" name=\"msg\"/>\r\n" + " <input type=\"button\" name=\"btn\" id=\"sendMsg\" value=\"Send\" onclick=\"javascript:sendmsg();\">\r\n" + " <div id=\"messages\"></div>\r\n" + " </form>\r\n" + " </body>\r\n" + "</html>\r\n "; exchange.send(new HttpResponse(200, "text/html", page)); } // IWebSocketHandler method public void onConnect(IWebSocketConnection webStream) throws IOException, BadMessageException { IHttpRequestHeader header = webStream.getUpgradeRequestHeader(); // check origin header String origin = header.getHeader("Origin"); if (!isAllowed(origin)) { throw new BadMessageException(403); } // check the subprotocol String subprotocol = header.getHeader("WebSocket-Protocol", ""); if (!subprotocol.equalsIgnoreCase("mySubprotocol.example.org")) { throw new BadMessageException(403); } } private boolean isAllowed(String origin) { // check the origin // ... return true; } // IWebSocketHandler public void onMessage(IWebSocketConnection webStream) throws IOException { WebSocketMessage msg = webStream.readMessage(); if (msg.toString().equalsIgnoreCase("GetDate")) { webStream.writeMessage(new TextMessage(new Date().toString())); } else { webStream.writeMessage(new TextMessage( "unknown command (supported: GetDate)")); } } // IWebSocketHandler public void onDisconnect(IWebSocketConnection webStream) throws IOException { } } XHttpServer server = new XHttpServer(8876, new ServerHandler()); server.start();class ServerHandler implements IHttpRequestHandler, IWebSocketHandler { // IHttpRequestHandler method public void onRequest(IHttpExchange exchange) throws IOException { String requestURI = exchange.getRequest().getRequestURI(); if (requestURI.equals("/WebSocketsExample")) { sendWebSocketPage(exchange, requestURI); } else { exchange.sendError(404); } } private void sendWebSocketPage(IHttpExchange exchange, String uri) throws IOException { String page = "<html>\r\n " + " <head>\r\n" + " <script type='text/javascript'>\r\n" + " var ws = new WebSocket('ws://" + exchange.getRequest().getHost() + "/Channel', 'mySubprotocol.example.org');\r\n" + " ws.onmessage = function (message) {\r\n" + " var messages = document.getElementById('messages');\r\n" + " messages.innerHTML += \"<br>[in] \" + message.data;\r\n"+ " };\r\n" + " \r\n" + " sendmsg = function() {\r\n" + " var message = document.getElementById( 'message_to_send').value\r\n" + " document.getElementById('message_to_send').value = ''\r\n" + " ws.send(message);\r\n" + " var messages = document.getElementById('messages');\r\n" + " messages.innerHTML += \"<br>[out] \" + message;\r\n"+ " };\r\n" + " </script>\r\n" + " </head>\r\n" + " <body>\r\n" + " <form>\r\n" + " <input type=\"text\" id=\"message_to_send\" name=\"msg\"/>\r\n" + " <input type=\"button\" name=\"btn\" id=\"sendMsg\" value=\"Send\" onclick=\"javascript:sendmsg();\">\r\n" + " <div id=\"messages\"></div>\r\n" + " </form>\r\n" + " </body>\r\n" + "</html>\r\n "; exchange.send(new HttpResponse(200, "text/html", page)); } // IWebSocketHandler method public void onConnect(IWebSocketConnection webStream) throws IOException, BadMessageException { IHttpRequestHeader header = webStream.getUpgradeRequestHeader(); // check origin header String origin = header.getHeader("Origin"); if (!isAllowed(origin)) { throw new BadMessageException(403); } // check the subprotocol String subprotocol = header.getHeader("WebSocket-Protocol", ""); if (!subprotocol.equalsIgnoreCase("mySubprotocol.example.org")) { throw new BadMessageException(403); } } private boolean isAllowed(String origin) { // check the origin // ... return true; } // IWebSocketHandler public void onMessage(IWebSocketConnection webStream) throws IOException { WebSocketMessage msg = webStream.readMessage(); if (msg.toString().equalsIgnoreCase("GetDate")) { webStream.writeMessage(new TextMessage(new Date().toString())); } else { webStream.writeMessage(new TextMessage("unknown command (supported: GetDate)")); } } // IWebSocketHandler public void onDisconnect(IWebSocketConnection webStream) throws IOException { } } XHttpServer server = new XHttpServer(8876, new ServerHandler()); server.start();

As shown in Listing 7, the origin header is checked against an internal whitelist to reject unwanted requests. This technique avoids the situation where an attacker copies a java script fragment from a publicly available page and embeds this code fragment into his page. In this case the browser would set the origin header with the domain of the attacker?s page and the upgrade request could be rejected. This technique helps to defend against Cross-Site Request Forgery attacks. The origin header specification is independent of the WebSocket protocol specification. However, the WebSocket protocol defines a WebSocket-Origin header which has to be included in the WebSocket upgrade response.

Due the fact that a WebSocket connection will be established over an HTTP connection, the WebSocket protocol also works with HTTP proxy servers. When using a visible proxy server, the browser always communicates with the proxy server, which forwards the HTTP requests and responses. If the browser is configured to use an HTTP proxy and a WebSocket is opened, first the browser opens a tunnel to the proxy server. By sending an HTTP/1.1 connect request, as shown in Figure 5, the browser asks the HTTP proxy to make a TCP connection to a dedicated (WebSocket) server. Once this connection has been established, the role of the HTTP proxy is ?downsized? to act as a simple TCP proxy to the WebSocket server. Using this proxied connection, the browser sends the WebSocket upgrade request to WebSocket server.

1. REQUEST: CONNECT myServer:8876 HTTP/1.1 Host: myServer:8876 User-Agent: xLightweb/2.12-HTML5Preview6 Proxy-Connection: keep-alive 1. RESPONSE: HTTP/1.1 200 Connection established Proxy-agent: myProxy 2. REQUEST: GET /Channel HTTP/1.1 Upgrade: WebSocket Connection: Upgrade Host: myServer:8876 Origin: http://myServer:8876 WebSocket-Protocol: mySubprotocol.example.org 2. RESPONSE: HTTP/1.1 101 Web Socket Protocol Handshake Upgrade: WebSocket Connection: Upgrade WebSocket-Origin: http://myServer:8876 WebSocket-Location: ws://myServer:8876/Channel WebSocket-Protocol: mySubprotocol.example.org Figure 5. WebSocket upgrade handshake based on a tunnel

Even though a browser does not explicitly configure an HTTP proxy, transparent HTTP proxies can be passed through invisibly by calling the WebSocket server. This depends on the current network infrastructure. Under some circumstances, such transparent HTTP proxies cause trouble for WebSockets. The Connection and Upgrade header are hop-by-hop headers by definition. The HTTP specification says that hop-by-hop headers have to be removed by an intermediary if a request is forwarded to the next hop. In the case of the WebSocket upgrade request, a transparent HTTP proxy will remove the Connection: upgrade header, which will result in the WebSocket server receiving a corrupt WebSocket upgrade request. Today, most HTTP proxies are not familiar with the WebSocket protocol.

Using secured WebSockets can avoid this effect. In creating a secured WebSocket connection, the browser opens an SSL connection to the WebSocket server. In this case intermediaries will not be able to interpret or modify data.

Conclusion

With WebSockets, writing highly interactive real-time web applications becomes a simple task. The WebSocket API is very easy to understand and to use. The underlying WebSocket protocol is high efficient: there is a minimal overhead involved in managing a WebSocket. Due the fact that the WebSocket protocol runs on the top of TCP, the WebSocket protocol does not have to deal with "hacks" as do popular Comet protocols like Bayeux or BOSH. Simulating a bidirectional channel over HTTP leads to complex and less efficient protocols. Especially if only a small amount of data will be transferred, such as tiny notification events, the overhead of the classic Comet protocols is very high. This is not true for WebSockets.

Furthermore, WebSockets fit well into the existing Web infrastructure. For instance WebSockets, use the same ports that standard HTTP connections use. To establish a new WebSocket connection, the WebSocket protocol makes use of the connection management capabilities of the HTTP protocol. WebSockets support highly efficient bi-directional communication by using the existing Web infrastructure without adding new requirements or components.

On the other hand, WebSockets do less for reliability. This has to be done on the application (sub-protocol) level. In contrast to Server-Sent events, the WebSocket protocol does not include reconnect handling or guarantee message delivery. The current WebSocket protocol represents a low-level communication channel only.

In contrast to WebSockets, the Server-Sent Events protocol includes powerful features to reconnect and synchronize messages. High reliability is a built-in feature of Server-Sent Events. Furthermore, as with WebSockets, the overhead involved in managing a Server-Sent Event stream is very low. However, Server-Sent Events support a unidirectional server push channel only. By creating a Server-Sent Event, a server-to-client server-push event stream will be opened. Often Server-Sent Events will satisfy the requirements of a server-push situation, but this depends on the concrete use cases.

What do WebSockets and Server-Sent Events mean for popular Comet protocols such as Bayeux and BOSH? The HTML5 communication standards have the potential to substitute for the classic Comet protocols and become the dominant server-push technology, at least for new applications. On the other side, for instance, the cometd community started implementing cometd 2.0 which will support the WebSockets protocol as a new transport type. cometd is the most popular Bayeux implementation.

Resources Gregor Roth works as a software architect at United Internet group, a leading European Internet Service Provider to which GMX, 1&1, and Web.de belong. His areas of interest include software and system architecture, enterprise architecture management, object-oriented design, distributed computing, and development methodologies.

Using Styles, Themes, and Painters with LWUIT

Wt, 2010-04-20 05:17
Discover how to use some of the new and enhanced features in LWUIT version 1.3 Using Styles, Themes, and Painters with LWUIT Mon, 2010-04-19 Biswajit Sarkar Discover how to use some of the new and enhanced features in LWUIT version 1.3

Lightweight User Interface Toolkit (LWUIT) version 1.3, released in December 2009, consolidates the modifications over version 1.1 initiated in version 1.2 and incorporates some new ones too. It also introduces three new components -- Tree, Table and Spinner. The use of the Tree widget is demonstrated through the LWUIT Demo that comes with the LWUIT download bundle. In this article we examine the changes with respect to Style and go on to check out Table and Spinner.

The demo applications have been developed on the Sprint Wireless Toolkit 3.3.2 (SWTK). Not only does this toolkit support LWUIT extremely well, it also has an interesting array of device emulators like those for HTC Touch and Samsung Instinct. If you intend to try out LWUIT, I would strongly suggest that you install the Sprint WTK on your computer.

Style

The idea behind Style is to centrally define the visual attributes for each widget (component). In addition to its physical design, such as its shape, the appearance of a widget can be defined in terms of a number of common features or attributes. In LWUIT 1.1 the settable attributes for a component were:

  • Background and foreground colors.
  • Fonts for writing text on it.
  • Background transparency.
  • Background image.
  • Margin and padding.
  • Background painters.
  • Border.

The additional attributes defined under LWUIT 1.3 are:

  • Background type -- specifies whether the background has an image or a color gradient. An image can be tiled, scaled or aligned (unscaled with alignment). A gradient for background can be linear (vertical/horizontal) or radial.
  • Background alignment -- if an image (tiled or aligned) is used for the background, the alignment (top/bottom/left/right/center) is defined by this attribute.
  • Background gradient start and end colors.

A Style object holds all these attributes for each state of each component that is used in an application, and has appropriate accessor methods. In addition this class also has the ability to inform a registered listener when a style object associated with a given component is altered.

A Style for Each State

In the early days of LWUIT, that is up to version 1.1, there used to be just one Style object for each widget to be displayed. This single Style object had separate attributes corresponding to the different widget states. For example, the background color for the unselected (unfocused) state would be defined as bgColor and that for the selected (focused) state as bgSelectionColor. The code for setting these colors would look like this.

//when the widget does not have focus //the background will be red myComponent.getStyle().setBgColor(0xff0000); //when the widget has focus //the background will be blue myComponent.getStyle().setBgSelectionColor(0x0000ff);

However, as of version 1.2, this has changed. Components now have distinct styles for each of their permissible states. Most components would have a selectedStyle and an unselectedStyle. Components like buttons and those that extend the Button class will have an additional style corresponding to the pressed state -- the pressedStyle. So, the above code sample will now look as follows.

//when the widget does not have focus //the background will be red myComponent.getUnselectedStyle().setBgColor(0xff0000); //when the widget has focus //the background will be blue myComponent.getSelectedStyle().setBgColor(0x0000ff);

Note that we have used two different versions of the getter method -- one for each style. Actually, the Component class has a getStyle method too, which returns the appropriate style depending upon the state of the component. This capability leads to simpler coding especially for methods that render components.

When a component is created, a default Style object gets associated with it as its unselectedStyle. The other styles are created when accessed for the first time through the corresponding setter or getter methods.

There are several ways for setting and modifying attributes as shown in the following list.

  • By using the get*Style().set* combination as above.
  • By creating a new style with the desired attributes and then invoking the set*Style method to set the new style.
  • Style for an entire set of widgets can be set through the UIManager instance. The relevant technique is
    //method for setting unselected style UIManager.getInstance().setComponentStyle (String id, Style style) //method for setting selected style UIManager.getInstance().setComponentSelectedStyle (String id, Style style) However, currently this approach works for selected and unselected styles.
  • Through a Theme.

In the following section we shall check out a simple demo application which shows how styling can be done under LWUIT 1.3.

Using Style

Our application will have a single form with three widgets and will look like the Figure 1:


Figure 1. Style Update Demo.

The screenshot above shows a screen with two labels and one button. Labels, by default, cannot receive focus and the topmost widget is such a label. The second label has been explicitly made focusable as shown by the code snippet below.

//create a label Label focusLabel = new Label("Focusable"); //and make it focusable focusLabel.setFocusable(true);

In Figure 1 we see the second label in the selected state. The applicable style is set as follows:

//modify default style to set attributes //for selected state of focus label focusLabel.getSelectedStyle().setBgColor(0x555555); focusLabel.getSelectedStyle().setFont(font); focusLabel.getSelectedStyle().setBorder (Border.createBevelRaised());

The first label and the button are unselected and their appearances are styled through the same Style object. This object has the following attributes:

//create a common style for unselected state Style unselStyle = new Style(); unselStyle.setFont(font); unselStyle.setBgTransparency(64); unselStyle.setFgColor(0xffc605); unselStyle.setBorder(Border.createEtchedRaised());

This style is set as the unselected one for all labels by calling the setComponentStyle(String id, Style style) method. This is shown below.

//set unselected style for labels UIManager.getInstance().setComponentStyle ("Label", unselStyle);

The unselected style for the button is set in the following way using the same style object that is used for labels.

//create button Button button = new Button("Button"); //set style for unselected state of button button.setStyle(unselStyle);

Figure 2 shows the same screen as above with the button in the selected state.


Figure 2. The button is selected.

We can see that both labels are unselected and their appearances are the same. The button, which has focus, looks just like focusLabel in Figure 1. This is ensured by creating a style with attributes that have the same values that were used for the selected style of focusLabel. This new style -- buttonSelStyle -- is then installed as the selected style for the button.

//create selected style for button Style buttonSelStyle = new Style(); buttonSelStyle.setBgColor(0x555555); buttonSelStyle.setFont(font); buttonSelStyle.setBorder(Border.createBevelRaised()); ... //set style for selected state of button button.setSelectedStyle(buttonSelStyle);

In a similar manner we create and set a style for the pressed state of the button:

//create pressed style for button Style buttonPrStyle = new Style(); buttonPrStyle.setBgColor(0xff0055); buttonPrStyle.setFont(font); buttonPrStyle.setBgTransparency(127); buttonPrStyle.setBorder(Border.createRoundBorder (12, 5, 0xff0000)); ... //set style for pressed state of button button.setPressedStyle(buttonPrStyle);

The result of pressing the button can be seen in Figure 3 below.


Figure 3. The button is pressed.

In the demo application above, style attributes have been set programatically to show some fundamental aspects of styling. In real life applications, though, it would be advisable to apply themes.

The Theme Creator

In the beginning there was the Resource Editor -- a very handy tool for creating and editing resource files. In Decemeber 2008 it was renamed LWUIT Designer, and in the latest release it has become the Theme Creator. While the essential functionality remains the same, both the LWUIT Designer 1.2 and the Theme Creator allow the creation of three distinct styles, as we can see in Figure 4.


Figure 4. Creating a theme with three styles.

The Theme Creator now provides support for SVG images too. This is shown in Figure 5.


Figure 5. SVG support.

UIID

Every component can have its own unique id which is used for styling as we have seen. All components in the library have their ids. When creating a custom component, a new id should be alloted. Sometimes, components are built up using existing ones and these constituent parts can have ids different from their original ones. Consider the case of a component that uses a label to form a part. If we want to give this part a distinct id for styling, the getUIID method of Component class would have had to be overridden in the days of LWUIT 1.1. A new method -- setUIID -- was provided in LWUIT 1.2 to do the same thing in a simpler and more intuitive way. So now we can write:

Label newMyPart = new Label(); newMyPart.setUIID("NewMyPart"); Spinner

A spinner is similar to a combo box in the sense that it shows a single value from a list of values. However, spinner does not show a drop down list for selection. Instead the up or down key has to be used to scroll through the list. Also, a spinner can show only a date, time or numerical value. Figure 6 shows a form with two components: a button and a spinner. The button has been added to show how different styles take effect depending on whether the spinner has focus or not. Here the spinner is shown in the unselected state.


Figure 6. Spinner is unselected

The Spinner class does not have an accessible constructor. One of the factory methods has to be used to get an instance of spinner. In this case we create a spinner to display time in twenty-four hour format showing hours, minutes and seconds. The method used is: createTime(int min, int max, int currentValue, int step, boolean twentyFourHours, boolean showSeconds). The first two parameters specify the minimum and maximum values for the list. The third parameter defines the value to be shown initially. The unit for all the three is seconds since midnight. The fourth is the difference between two successive values in seconds. The fifth and sixth parameters define the display format.

The image on the right of the time display is called the spinnerHandle and is meant to indicate that the display can spin. The following code snippet shows how the spinner is created and the spinnerHandle is set. A word about the value initially shown in Figure 6 above: while creating the spinner instance, the value specified for initial display is 180, which corresponds to three minutes or, in the given format, 00:03:00. However, note that the step size has been specified as 40 which means 180 is not in the list. The time displayed corresponds to 160 which is the highest value not exceeding 180.

//create spinner with seconds display spinner = Spinner.createTime(0, 7200, 180, 40, true, true); //set image to visually indicate it is spinnable try { spinner.setSpinnerHandle(Image.createImage("/handle.png")); } catch(java.io.IOException ioe) { }

In Figure 6 we see the spinner in the unselected state. There is a dark olive green background on which the numerical display is rendered in blue. The background represents the spinner container and its unselected appearance is set as follows:

//affects look when spinner does not have focus spinner.getUnselectedStyle().setBgColor(0x556b3f); spinner.getUnselectedStyle().setBorder(Border.createBevelRaised());

The first step in setting style for the time display is to get the DefaultListCellRenderer instance for the spinner. The style attributes can then be set as shown below.

//create a font Font font = Font.createSystemFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD,Font.SIZE_LARGE); ... //affects look when spinner does not have focus spinner.getUnselectedStyle().setBgColor(0x556b3f); spinner.getUnselectedStyle().setBorder(Border.createBevelRaised()); ... //renderer for the cell containing display DefaultListCellRenderer dlcr = (DefaultListCellRenderer)spinner.getRenderer(); //affects steady state look dlcr.getSelectedStyle().setBgColor(0x0000ff); dlcr.getSelectedStyle().setFgColor(0); dlcr.getSelectedStyle().setFont(font); dlcr.getSelectedStyle().setPadding(Component.RIGHT, 7); //affects look during scrolling dlcr.getUnselectedStyle().setBgTransparency(0); dlcr.getUnselectedStyle().setFgColor(0); dlcr.getUnselectedStyle().setFont(font);

The code above also sets the renderer style for the unselected state. This style becomes effective when the spinner value scrolls. To see how that works, press the down key. Now, the spinner gets focus and its appearance changes as specified by the code below.

//affects look when spinner has focus spinner.getSelectedStyle().setBgColor(0x0000ff); spinner.getSelectedStyle().setBorder (Border.createRoundBorder(12, 5, 0xff0000));

The spinner now looks like what's shown in Figure 7.


Figure 7. Spinner is selected.

Although the spinner now has focus, it will not respond to the up or the down key. At this stage the scrolling keys will toggle focus between the spinner and the button. To direct the scrolling key events to control the spinner display, the select key has to be pressed while the spinner has focus. Generally speaking, the select key can be used to toggle the applicability of scrolling keys between a form itself and a component with focus contained in the form. The scrolling keys can now be used to sequentially change the time displayed.

What remains now is to see how we can retrieve the value selected on the spinner. The demo does this in different ways. One way is through a command. We add the Show command to the form and, in the actionPerformed method, call into the getValue method of Spinner class.

//create and add 'Exit' command to the form //the command id is 1 demoForm.addCommand(new Command("Exit", 1)); //create and add command to show spinner value //the command id is 2 demoForm.addCommand(new Command("Show", 2)); //this MIDlet is the listener for the form's command demoForm.setCommandListener(this); ... //act on the commands and the click public void actionPerformed(ActionEvent ae) { Command cmd = ae.getCommand(); if(cmd != null) { switch (cmd.getId()) { //'Exit' command case 1: notifyDestroyed(); break; //'Show' command case 2: System.out.println("Value shown through command : " + spinner.getValue()); } return; } ... } A second method is to register the MIDlet as the ActionListener for the spinner. If we now click on the spinner, the actionPerformed method of the MIDlet will be invoked. The necessary action can then be taken.
//this MIDlet is the action listener for spinner spinner.addActionListener(this); ... //act on the commands and the click public void actionPerformed(ActionEvent ae) { Command cmd = ae.getCommand(); if(cmd != null) { ... return; } if(ae.getSource() == spinner) { System.out.println("Value shown on click : " + spinner.getValue()); } }

The third approach used in the demo is to add the MIDlet to the spinner as the SelectionListener. For this technique to work, the MIDlet has to implement the SelectionListener interface so that its selectionChanged method is called whenever the spinner selection is changed.

//this MIDlet is the selection listener for spinner spinner.addSelectionListener(this); ... public void selectionChanged(int oldSelected, int newSelected) { if(oldSelected != newSelected) { ListModel model = spinner.getModel(); System.out.println("Selection changed from " + model.getItemAt(oldSelected) + " to " + model.getItemAt(newSelected)); } }

When we click on a list, its selection changes, and this causes the selectionChanged method of the registered SelectionListener to be called in addition to the actionPerformed method of its ActionListener. As Spinner is a subclass of List, it behaves in a similar fashion and clicking on it results in the printing of the selection change message for the demo. For a spinner, however, we do not consider this to be a valid selection change since the value remains the same. The if clause in the above code listing takes care of this issue. The resultant console printouts for all three approaches are shown in Figure 8.


Figure 8. Message printouts.

Table

A table displays information in the form of a grid. The topmost row describes the name of the data in each column. These are the Headers. The rest of the table displays data and is comprised of Cells. The headers are instances of Label and are meant to be uneditable. The cells can be either editable or uneditable. Editable cells are instances of TextField while uneditable cells are instances of Label. However, uneditable does not mean unmodifiable as we shall see when we discuss the demo application.

Figure 9 shows a table with 5 rows and 3 columns. The topmost row holds the headers. The rest of the rows hold cells that display data. Here we have two kinds of data: text in the leftmost column (column 0) and numbers in the other columns (columns 1 and 2).


Figure 9. A table.

The contents of a table are determined by an underlying model -- the table model. LWUIT defines the TableModel interface that must be implemented by a table model; the default implementation included in the library is the DefaultTableModel class. So the first step in creating a table is to set up the model. This model is then passed as a parameter to the table constructor. The relevant code for our application is:

//define headers String[] columns = new String[] {"Items", "Good", "Scrap"}; //define data Object[][] data = new Object[][] {{"Plate-01", new Integer(1605), new Integer(57)}, {"Plate-02", new Integer(5001), new Integer(326)}, {"Coil-01", new Integer(417), new Integer(124)}, {"Coil-02", new Integer(451), new Integer(22)}}; //create model with uneditable cells //as specified by last parameter //for editable cells last parameter must be 'true' DefaultTableModel model = new DefaultTableModel(columns, data, false); //create table table = new Table(model);

The cells of our table are labels and the default alignment is Label.LEFT. There is a method in the Table class to set cell alignment -- setCellAlignment. However, this is not a static method and works only for new cells created for an existing table. The default alignment for headers is Label.CENTER To change the alignment of cells, we need to access each label that forms a cell and set its alignment. Another point to be noted is that, for some form layouts, the sizing of the last column may not work properly. We have used a kind of rendering prototype to ensure proper sizing. All this is shown in the code snippet below.

//create a font Font font = Font.createSystemFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD,Font.SIZE_LARGE); //width of 'rendering prototype' int w = font.stringWidth("WWWW"); ... //does not affect alignment of cells already created as //table is constructed with cells with default alignment //works only for cells created later //this happens, for example, if new data is set table.setCellAlignment(Label.CENTER); TableLayout layout = (TableLayout)table.getLayout(); Component c = null; //'getRowCount' does not take into account the header row //so add 1 to get total number of rows int rows = ((DefaultTableModel)table.getModel()). getRowCount() + 1; int cols = ((DefaultTableModel)table.getModel()). getColumnCount(); for(int i = 0; i < rows; i++) { for(int j = 0; j < cols; j++) { //get the component for cell at //specified row and column c = layout.getComponentAt(i,j); if(i == 0) { //set border for headers c.getUnselectedStyle().setBorder (Border.createLineBorder (1, 0xff0000)); if(j == cols - 1) { //use prototype //to size the last column c.setPreferredSize(new Dimension(w, c.getPreferredH())); } } else { //necessary because cells were originally //created with default (left) alignment ((Label)c).setAlignment(Label.CENTER); } } }

The header strings and the cell data are held within the table model. The TableModel interface defines methods to access these variables. Note that there is only a getter method for the column names while there is a getter as well as a setter method for the cell values. The Show command on our demo form uses the getValueAt method to print out a cell value on the console.

//act on the commands public void actionPerformed(ActionEvent ae) { Command cmd = ae.getCommand(); switch (cmd.getId()) { ... //'Show' command case 2: //get the table model instance DefaultTableModel dtm = (DefaultTableModel) table.getModel(); //get the value at the specified cell //use actual row number - 1 //since actual first row is not for data Object val = dtm.getValueAt(0, 2); //print value System.out.println ("Plate-01 Scrap : " + val); ... } }

The printout is shown in Figure 10.


Figure 10. Accessing cell data.

The setValueAt method can be used to programatically change data in a cell -- even for uneditable cells. In our demo application the Show command is replaced with a Modify command which changes the data in the cell for Plate-02 Scrap from 326 to 750. The setValueAt method leads to the creation of a new label to replace the existing one. As we have already set cell alignment to Label.CENTER, the new value remains properly aligned.

//create and add command to show value //the command id is 2 //demoForm.addCommand(new Command("Show", 2)); //create and add command to change value //the command id is 2 demoForm.addCommand(new Command("Modify", 2)); ... } ... //act on the commands public void actionPerformed(ActionEvent ae) { Command cmd = ae.getCommand(); switch (cmd.getId()) { //'Exit' command case 1: notifyDestroyed(); break; //'Show' command /*case 2: //get the table model instance DefaultTableModel dtm = (DefaultTableModel) table.getModel(); //get the value at the specified cell //use actual row number - 1 //since actual first row is not for data Object val = dtm.getValueAt(0, 2); //print value System.out.println ("Plate-01 Scrap : " + val);*/ //'Modify' command case 2: //get the table model instance DefaultTableModel dtm = (DefaultTableModel) table.getModel(); //set the value at the specified cell //use actual row number - 1 //since actual first row is not for data dtm.setValueAt(1, 2, new Integer(750)); } }

In Figure 11 we can see the new value for Plate-02 Scrap.


Figure 11. Cell data modified.

In the demo application for table, the only styling done programmatically is for the set of borders for the headers. The rest of the styling has been defined in a theme. The theme file is shown below in Figure 12. A word of caution here. This theme file has been created by the Theme Creator that comes with LWUIT 1.3. The Resource Editor that comes with the SWTK is of an earlier vintage and will not be able to open this file.


Figure 12. Theme file for the demo app.

Conclusion

We have seen how the approach to styling has been modified since LWUIT 1.1. We have also checked out the new Theme Creator and two new components that have been introduced in LWUIT 1.3. However, there are a number of interesting new features that have not been discussed here. These are listed in What's new in This Release in the LWUIT 1.3 download bundle.

Resources Biswajit Sarkar is an electrical engineer with specialization in Programmable Industrial Automation. Biswajit is the author of "LWUIT 1.1 for Java ME Developers" published by PACKT Publishing. AttachmentSize Art14_FocusedButton.png41.21 KB Art14_FocusedLabel.png41.32 KB Art14_FocusedSpinner.png41.11 KB Art14_Modified1.png41.38 KB Art14_NewTheme.png2.94 KB Art14_PressedButton.png41.06 KB Art14_SpinnerValues.png33.92 KB Art14_SVG.png10.65 KB Art14_Table.png41.5 KB Art14_TableValue.png21.58 KB Art14_ThemeFile.png51.61 KB Art14_UnfocusedSpinner.png40.96 KB Art14_src_codes.zip6.99 KB

Rethinking Multi-Threaded Design Principles, Part 2

Śr, 2010-04-14 18:39
Harnessing the processing power of next generation multi-core processors Rethinking Multi-Threaded Design Principles, Part 2 Wed, 2010-04-14 Dibyendu Roy Harnessing the processing power of next generation multi-core processors

Introduction

In Part 1 of this series, I introduced some basic principles for working in a multi-threaded application. Kevin Farnham, in his blog, pointed out that our next challenge would be to design an application that fully harnesses the processing speed of next generation multi-core processors. That challenge has made me rethink some of the various means by which that goal can be achieved.

Laws governing a processor's speed and performance:

In terms of concurrency, when multiple threads run simultaneously, only one thread gets executed at a time. But to achieve parallelism, the processor should support multiple threads that can be executed at any given point in time. Flynn's taxonomy classifies processing platforms based on Instruction Set and Data stream, as follows: Single Instruction Single Data (SISD), Single Instruction Multiple Data (SIMD), Multiple Instruction Single Data (MISD), and Multiple Instruction Multiple Data (MIMD). As modern processors fall under either SIMD or MIMD, it makes it possible for us to write a data or task centric application that could run in parallel.

Since historically processor clock speed was following Moore's law, there was no real need for most programs to execute multiple instructions at a time. Applications simply ran faster because new processors were faster. However, today processor speeds are no longer increasing rapidly.

To increase overall processing power, chip manufacturers began developing processors that provide instruction level parallelism: the processors evolved to have multiple processing units in them. While some processor architectures include a logical processing unit within the same space to allow Simultaneous Multi-Threading, others go a step further by implementing two or more execution units (Cores) in a processor.

To see how much performance improvement the parallelism contributes, we can easily derive an equation:

Speed Enhancement = (Time needed for Sequential execution) / (Time needed for Parallel execution)

Considering number of processor cores, the equation has been further simplified by Amdahl's Law as:

Speed Enhancement = 1 / (Fs + ((1 - Fs) / N)),

where Fs is the fraction of entire program spent running sequentially and N being number of cores in the processors. Here, if N is 1, we get no speedup, but as N increases (tends to infinity, (1 - Fs)/N becomes 0), the speed is totally dependent on the 1/Fs part - which leads to the conclusion that, to improve execution speed of an application, we need to figure out ways or patterns to make more code execute in parallel.

Finding different ways to lock

As we go on finding ways to refactor the code into parallelized parts, it becomes quite clear that some way or other, different parts of the code must contend for some resource that requires a lock. Whenever any thread tries to access a lock that's already being held by someone, it gets suspended first and awakened later when lock is available, thus spending some time doing nothing. In this case the JVM manages everything for you, but after holding the lock, if the thread is blocked forever (Database connection down or some I/O operation), it would suspend all waiting threads, causing resource starvation. To ameliorate the situation, we can implement our own lock and let client code handle acquiring or releasing the lock by itself. Though this sounds appealing, the task to implement that would undoubtedly be daunting, as you have to manage the lock by yourself. A simple mistake can make you fail miserably.

Lets revisit our previous CarBookings example:

class CarBookings{ final ReentrantLock lock = new ReentrantLock(); private final Set bookings = new HashSet(); public boolean putCar(CarBooking booking){ boolean status = false; if(!lock.isLocked() ){ lock.lock(); try { bookings.add(booking); } finally { lock.unlock(); } status = true; } return status; } }

So, when BookingRequester calls the putCar method, if it's already being used (locked) by someone else it returns false, providing better control to the requester on whether to retry or abort, without going through a Run - Suspend - Run phase. Though it looks simple, it gets more complicated with multiple locks; it becomes very easy for someone to forget to put in the unlock code, resulting in all threads waiting forever. So, make sure you keep track of all locks, and make sure they will be unlocked properly.

Non-Blocking operation

In addition to strictly following the rules of using explicit locks, another way to achieve concurrency is to perform non-blocking operation on the contention points. The Compare-And-Swap (CAS) is one of such operation, where a field can be updated with new value only when certain precondition is met. So, when multiple threads try to make a non-blocking call, only one succeeds at a time, but others are given a choice either to continue re-trying or abort the operation without falling prey to being suspended and awakened later on. This allows them to be in a Running state even if the lock is not acquired, unlike the case of a synchronized lock where they have to be in a Suspended state for some time and come back to Running state when the lock is available. Clearly, as the Non-blocking-Lock-acquiring process reduces the extra transition (Run-Suspend-Run) time, it becomes the better choice for developing highly scalable application.

Let's implement the queue (BookingQ or AdviceQ) from the previous article.

public class BookingQ{ private static class Node { CarBooking booking; Node nextBooking; Node(CarBooking cb, Node next) { this.nextBooking = next; booking = cb; } boolean compareAndSetNext(Node en, Node sn){ if(this.nextBooking==en){ this.nextBooking = sn; return true; } return false; } } boolean compareAndSetNode(Node node, Node en, Node sn){ if(node==en){ node = sn; return true; } return false; } private volatile Node head; private volatile Node tail; public BookingQ() { tail = head = new Node(null,null); } public void putBooking(CarBooking booking){ Node newBooking = new Node(booking,null); while(true){ Node currBooking = tail; Node nextTail = tail.nextBooking; if(currBooking == tail){ if(nextTail != null){ //Line 1 compareAndSetNode(this.tail, currBooking, nextTail); }else{ //Line 2 if(currBooking.compareAndSetNext(null, newBooking)){ // Line3 compareAndSetNode(this.tail, currBooking, newBooking); // Line4 break; } } } } } public CarBooking getBooking(){ while(true){ Node currHead = head; Node currTail = tail; //Line 5a Node headNext = currHead.nextBooking; //Line 5b if(currHead == head){ if(currHead!=currTail){ //Line6, Some bookings have been made if(compareAndSetNode(this.head, currHead, headNext)){ //Line7, Advancing head CarBooking firstBooking = headNext.booking; if(firstBooking!=null){ headNext.booking = null; //Line8 return firstBooking; //Line9 } } }else{ //No booking yet if(headNext != null){ //Line10 compareAndSetNode(this.tail, currTail, headNext); }else{ return null; } } } } } }

Here, the unit element of the queue is a Node that has a booking property holding the CarBooking and nextBooking to point to the next Node in queue. The BookingQ starts with its head and tail pointer set to a Node with NULL booking and NULL nextBooking. The process of putting any node into the queue requires updating two pointers:

  • Step 1: set the next pointer of current node to the new node
  • Step 2: advance the tail pointer to the new node also

After successfully adding a node to the queue, the head's nextBooking would point to new not-NULL node, but the booking element still remains NULL.

The CAS is applied wherever there is a contention point, like updating a node in compareAndSetNext or compareAndSetNode.

Now consider a situation when a new booking is being added in putBooking by a thread (T1). It checks to find tail of the queue in Line 2 and does compareAndSetNext. But between Step 1 and 2 if another thread (T2) tries to put another booking and finds in Line 1 that another thread's work is underway (meaning that Line 3 is done, but 4 is not, so the tail's nextBooking no more NULL), it then completes T1's unfinished job (Step 2) of updating the tail pointer to the new node. After that, T2 goes to the next iteration to put a new booking.

In case of getBooking, when the tail and head are not same (Line 6), it advances the head pointer to the next node of first booking node (Line 7) and returns its booking element (Line 9). Setting headNext.booking to NULL (Line 8) resets the head node back to a starting point. As head no longer references the previous node, the Garbage Collector would collect it eventually, making the queue length shorter. In line 10, a similar situation to putBooking may arise when a thread tries to read off of the empty queue and between Line 5a and 5b another thread puts a booking (Line 3), and in that case it also advances the tail pointer to the new booking.

Note, we could do the same CAS using the Java AtomicReference class, but for clarity of understanding we've just elaborated it a bit.

Conclusion

Refering back to important laws, it becomes clear that though modern processors provide better means to improve application performance, the program is where the work of implementing parallelism must occur. The more the program can be decomposed into parallelized parts, the better it performs on multicore computers. In addition, it becomes clear that while working with explicit locks gives you better control than the JVM intrinsic lock, non-blocking operations also enable you achieve higher performance than any synchronized operation. In any case, parallelized programs must be designed carefully and tested properly. Even small oversights may result in undesirable consequences in multithreaded applications.

Dibyendu Roy has more than ten years of design and development experience in various domains including Banking and Financial Systems, Business Intelligence tools and ERP products.