Comments
Richard Davies wrote: The UK has a good crop of technology pioneers in cloud computing - for example ElasticHosts, FlexiScale, Flexiant, OnApp - and also some strong government initiatives such as G-Cloud. We will have to see whether this kind of technical leadership converts into swift mass-market adoption or not.
Cloud Expo on Google News


2008 West
DIAMOND SPONSOR:
Data Direct
SOA, WOA and Cloud Computing: The New Frontier for Data Services
PLATINUM SPONSORS:
Red Hat
The Opening of Virtualization
GOLD SPONSORS:
Appsense
User Environment Management – The Third Layer of the Desktop
Cordys
Cloud Computing for Business Agility
EMC
CMIS: A Multi-Vendor Proposal for a Service-Based Content Management Interoperability Standard
Freedom OSS
Practical SOA” Max Yankelevich
Intel
Architecting an Enterprise Service Router (ESR) – A Cost-Effective Way to Scale SOA Across the Enterprise
Sensedia
Return on Assests: Bringing Visibility to your SOA Strategy
Symantec
Managing Hybrid Endpoint Environments
VMWare
Game-Changing Technology for Enterprise Clouds and Applications
Click For 2008 West
Event Webcasts

2008 West
PLATINUM SPONSORS:
Appcelerator
Get ‘Rich’ Quick: Rapid Prototyping for RIA with ZERO Server Code
Keynote Systems
Designing for and Managing Performance in the New Frontier of Rich Internet Applications
GOLD SPONSORS:
ICEsoft
How Can AJAX Improve Homeland Security?
Isomorphic
Beyond Widgets: What a RIA Platform Should Offer
Oracle
REAs: Rich Enterprise Applications
Click For 2008 Event Webcasts
SYS-CON.TV
Top Links You Must Click On


Eiffel-Like Separate Classes
Eiffel-Like Separate Classes

To extend Java's concurrent behavior in a more natural way, in a more object-oriented point of view, we propose an extension to Java's concurrency model that will emulate Eiffel's separate statement. (Eiffel is an object-oriented language with a comprehensive approach to software construction.) The extension permits the attachment of nonphysical processors or threads to objects, thus allowing them to behave in an asynchronous and completely independent manner. This article briefly shows the concurrency tools of the Java programming language, points out their shortcomings, proposes solutions, and ends with the implementation of a solution.

It's useful to evaluate Java's concurrent programming model by reviewing how this language implements the concepts explained by Bertrand Meyer and referred to as "The three forces of computation," which represent the statement: "To perform a computation is to use certain processors to apply certain actions to certain objects."

Java classes and objects play the same role in Eiffel as they do in Java. In Java the notion of a nonphysical processor fits in with the concept of thread as represented by the Thread class. A processor would then represent an autonomous thread of control that's capable of supporting the sequential execution of instructions on one or more objects.

Differences arise when we look at the possible assignment of processors to actions. In Java we have only the run() method, which belongs to the Runnable interface, for concurrent execution. This interface must be implemented by a class attached to a Thread instance in construction time and then, and only then, can we explicitly start the thread's execution, employing the technique known as delegation.

The problem originates from the fact that threads and objects represent different entities - methods run on threads, objects do not - so the only way to get a method to run concurrently (in an independent thread) is to call it from inside that thread's run() method. This is a disadvantage of this model since the object technology's basic model for computation would somehow be broken, as we can easily conclude from the following statement:

objRef.operID(args);

Here the execution of method operID(), called as part of an action performed on a client object, won't occur concurrently as long as it's not placed inside a thread's run() method. The model is said to be broken since there's no natural, object-oriented way in Java to provoke the attachment of different streams of execution to both the client object and objRef. The entire class design should be oriented to the implementation of the Runnable interface and the creation of Thread class instances.
Figure 1 shows, in UML notation, a possible general pattern for this problem.

The benefits of this mechanism are based on the fact that Java clearly separates the notion of data abstraction, implemented by classes, from the notion of control, represented by the framework that's composed of the Thread and ThreadGroup classes and the Runnable interface. Table 1 shows the main components of this framework.
Once this model has been analyzed, let's proceed with Eiffel's concurrency model.

A Closer Look at Eiffel's Model
We'll now analyze Eiffel by looking for features that are capable of improving the former concurrency model. According to Meyer: "... any object O2 is handled by a certain processor, its handler; the handler is responsible for executing all calls on O2 (all calls of the form x.f (a) where x is attached to O2)."

From this statement we can conclude that the proposed model has two different call semantics:

  • Synchronous: The client object will be forced to wait for the server to complete its operation, as requested in the code.
  • Asynchronous: An object doesn't need to wait for the others to proceed with its execution, since it occurs in different processors.

In Java the default semantic is obviously synchronous. It doesn't provide any syntactic construction in its classes that will specify a different processor for its methods. So we need to define asynchronous execution through the use of Thread instances and the method run. This is the only way to define an asynchronous split of control.

Defining Separate Entities in Java:
A Straightforward Implementation
The essential difference between sequential and concurrent execution of actions is that the handler of the call's target is different from the one that originated the call. Doug Lea's interactive diagrams show this difference with solid and dashed lines that represent synchronous and asynchronous method calls. Figure 2 depicts such an interactive diagram for the pattern in Figure 1.

To implement this difference in Java, we'll follow Eiffel's approach, which allows us to define separate entities in two ways. The first one permits the creation of an object's instance and attaches it as an independent processor.

x: separate A

Here we're declaring an object x, instance of class A, that you'd execute on a different processor.

The second approach takes a static form and is applicable when all the instances of a class are intended to be separate entities:

separate class A ...

We cover both forms in this article. Our semantics require a new processor to handle all the messages for each of the instances of our separate classes or objects.

Obviously, we need to modify the Java syntax, adding a new keyword as an optional modifier in class and field definitions. To accomplish this, a preprocessing approach is proposed. This means that a parser program should be developed for parsing the Java source file and eliminate, if included, the separate modifier and replace it with some standard code.

The following is our first approach to the problem, but not the best one. We'll add some code before any invocation to a public method, and in separate-declared classes replace every method's body with code that's responsible for the creation of a new thread and the execution of its run() method. Inside this method we'll select the original code and invoke it. That's not the exact semantic of separate in Eiffel, but it provides us with a good place to start our evaluation. Since we need to intercept method invocation, we use the Java Reflection API.

Java Tools for the Solution
The Reflection API is composed of a set of classes that enable us to discover information about Java classes at runtime. This new feature of Java, developed with version 1.1 of the JDK, has also been called the introspection API because it gives objects the ability to look inside themselves or other classes during runtime.

The API defines the following elements:

  • At the core of the API is an object called Class for reflecting classes and interfaces in a running Java application.
  • Every object has a constructor, can perform a set of actions (also called methods), and is characterized through a number of attributes or variables. All these components are reflected through the Constructor, Method, and Field objects in the API that permit us to obtain information about each object's elements according to the security police used.
  • The Member interface, implemented by the three former objects, contains the prototypes of methods that allow you to query the object's members.
  • To represent primitive Java data types, the API contains nine Class objects defined as constants such as java.lang.Boolean.TYPE and java.lang.Character.TYPE.
  • There are two utility classes: Array and Modifier. The former allows us to access and construct Java arrays dynamically; the latter helps to decode language modifiers on classes and members.

Let's now proceed with our desired output definition on the basis of these elements.

Implementing the Solution
Separate as a Class Modifier
Let's now define how our solution should work, what we need as input data, and what we should produce. First we have a class like the one in Listing 1. After preprocessing, we obtain the code in Listing 2.

Two things must be taken into account:

  1. The security police used
  2. The methods' formal parameters

The security police that are used could affect the way we obtain the original method references, the one we invoke later in method run(). In Listing 1 we defined the method m2() as public, since the getMethod() method just returns Method objects that reflect the specified public member of the class. To obtain a reference to members affected by private-, protected-, or default-access modifiers, like m1(), for example, we can take one of the two approaches listed below:

  1. We can use the getDeclaredMethod(...) method instead of getMethod(), which can throw a security exception when a security manager is installed.
  2. As in Listing 2, the original modifiers on the methods generated by the preprocessing parser, m1() and m2(), remain untouched, and the original programmer's methods in the generated code, orig_m1() and orig_m2(), get declared public. This approach shouldn't affect the security of the application, since orig_m1() and orig_m2() are completely new for the program and invocations on them don't exist.

The second item to take into account is the methods' formal parameter treatment that must be done. The reflection API allows us to refer them at runtime through an array of Object instances, the __params variable used in Listing 2. Because of this, you shouldn't declare any parameter belonging to some of Java's primitive types. Instead we propose the use of the corresponding wrapper classes found in the java.lang package such as Integer, Float, and Double.

Separate as a Modifier for Class Fields
This solution is a little bit trickier since we'll find situations where the object's instances should run in their own thread and others where this behavior won't be needed.

To accomplish this, we've implemented the desired output in an inner class whose role is to permit the execution of each method's invocation in an object's thread. We use the starting code in Listing 3, then after preprocessing we should obtain the code in Listing 4.

As you can see, the changes affect classes A and B. The _Aux class in A encapsulates the behavior to execute in the separate case. Each invocation of m1() in B should be replaced with a separate_m1().

Another detail to take into account is the use of the getDeclaredMethod() method, instead of the getMethod() mentioned earlier, for taking a reference to the method that will be invoked. The main reason behind this decision is that we're invoking methods of A from class B, so we can't make them all of public type.

One more thing: the solution of encapsulating the separate behavior in an inner class is perfectly portable to the first analyzed case. The difference is just in the semantics of the problem.

Implementing the Preprocessing Parser
Traditionally, as everyone knows, a parser is a tool capable of performing three basic tasks:

  1. It receives some text from an input source, a Java program, for example.
  2. The text has to be organized according to some predefined criteria.
  3. Some actions have to be performed on this input based upon the above-generated organization.

The first two tasks are frequently encompassed and performed by an auxiliary application named scanner. Its main objective consists of building high-level language units called tokens, while discarding constructs that don't represent any useful information, such as white spaces and comments. Figure 3 depicts this functionality.

The actions mentioned in Step 3 try to match the tokens generated by the scanner against a language specification. If this match becomes successful, the parser then performs some action upon the construct. In our case it could generate the code that implements the separate behavior.

Building a parser from the ground up is a highly complex and time-consuming task. We used a parser generator, namely Sun's Java Compiler Compiler version 1.0, or JavaCC, which can be freely downloaded from Sun's Web site or from Metamata.com. The last one offers the parser generator and a set of example grammars.

A parser generator is usually a tool that's capable of generating parser and scanner programs starting from a grammar specification of the language to one we want to parse. The Java grammar we used was one of the samples that ships with JavaCC from Metamata.com, which covers Java's 1.1 language extensions.

JavaCC is based on ANTLR technology; also, it is an LL(k) predicate-based parser generator. It is beyond the intention of this article to describe in depth the details of the parser generator's algorithms. The interested reader should note the references at the end of this article.

Changes to the Java Input Grammar
To correctly parse a Java program whose objects can be affected by the separate modifier, first modify the Java grammar that's used as input for the generation of the parser and scanner tools. For this purpose there are only a few elements to modify from the original grammar construct:

  • The set of reserved words and literals that have to include the token separately
  • The set of class and class field modifiers that allow separate to be a valid modifier for both elements

These changes are very simple since the specification language to build the input description is Java-based with a few extensions to specify grammars (see Listings 5 and 6).

Note: There's a special method for analyzing a class field, instead of a general method for fields belonging to classes or interfaces. That's because the interface's fields may not be declared separate.

Output Generation
The generation of the output code, in case of separate behavior, is straightforward. In the JavaParser class generated by JavaCC, when the separate modifier is found, we start storing the class elements defined by the programmer since the parser just analyzes language units, eliminating the separate token. At the end of this analysis the stored code is added to the one needed for separate behavior, which is generated by the class JavaParserNewCode.

To accomplish this generation, the only things to take into account are the method definitions, since separate behavior consists only of executing every method invocation in its own processor.

JVM Scheduling vs Eiffel's Concurrency Control Files
We've defined processors as abstract concepts, independent of the underlying hardware and operating system architectures. In doing so, we've achieved a desirable independence for physical details. Our object system can run on a single processor workstation with a time-sharing schedule or in an SMP server.

Eventually we need to assign our physical resources to the processors of our program. In Eiffel we have the Concurrency Control File as a mechanism for defining this mapping.

In Java it's impossible to define such things programmatically. Threads are created dynamically in runtime as any other object, and the scheduling is left to the Java Virtual Machine (JVM). We can use groups of threads and priorities to obtain some level of control over the execution of threads, but the core algorithm is embedded in the JVM and, in current versions of the JDK, it's not possible to customize or substitute. In fact, it's somewhat implementation-defined (as noted in earlier versions of JDK, Solaris and Windows implementations differ in that the first is not preemptive).

In Java, distributed programming uses an additional API, called RMI, for communicating remote JVMs via remote interfaces. Alternatively, we can use IDL and CORBA.

The JVM is an operating system process in current commercial OSs, so they're under control of the OS process control. We haven't heard about parallel implementations of the JVM, exploiting the runtime information about threads, but it's clear that it would be advantageous to obtain better performance in architectures that include multiprocessing.

Conclusion
We've described our experiences and related studies regarding the introduction of Eiffel's concurrency model into Java. Our goal has been to extend Java's concurrent programming capabilities with the creation of completely independent objects through the use of a separate modifier.

Our approach helped us to unify, in some way, the notion of objects and threads, giving a more consistent object-oriented view to the design and implementation of concurrent applications in Java. The newly introduced model keeps the conceptual architecture strictly separate from the physical one; the former assumes that there'll be as many resources as the application needs; the latter is responsible for the creation of threads and their assignation to separate objects.

Another benefit to this approach is applicable to the academic field; we've taught Concurrent Java Design for three years and lacked a uniform object-oriented-based vision of the problem. With our extension, the design of concurrent Java applications is divided into two stages. The first is based on objects that are affected by the separate clause in which we apply the usual object-oriented execution mechanism of object.operation(args) and introduce the concurrency concepts in a more natural way. In the second stage we present Java's concurrency tools in more detail, going deeper into its mechanism and behavior.

Through this division, new concepts become simpler and more natural for the student since the move from sequential to concurrent programming just represents, initially, a little change in processor assignation.

One problem is the management of distributed resources. In Eiffel resources are mapped to processors through the Concurrency Control File, which enables you to manage the allocation of local and remote resources to processes. This unified view of mapping creates a better plan for running threads, allowing applications to control the physical allocation. The only ways for thread control in Java are, as mentioned previously, the Thread and ThreadGroup classes and the methods inherited from the Object class. These elements have to be combined with the functionality contained in the RMI package when we're developing distributed multithreaded applications. This makes this work error-prone and creates hard-to-predict client machine dependencies. Hence, we're preparing an extension of Java's thread control capabilities with support for distributed resources management.

References

  1. Lea, D. (1997). Concurrent Programming in Java. Design Principles and Patterns. Addison-Wesley.
  2. Meyer, B. (1997). Object-Oriented Software Construction. Prentice Hall.
  3. "ANTLR: A Predicated-LL (k) Parser Generator." Software - Practice and Experience, Vol. 25(7), 789-810. July 1995.
  4. Voss, G., and Parr, T. "Parsers, Part I." (http://developer.java.sun.com/ developer/technicalArticles/Parser/SeriesPt1/index.html). January 1997.
  5. Voss, G., and Parr, T. "Parsers, Part II. Building a Java Class Browser." (http://developer.java.sun.com/developer/technicalArticles/Parser/SeriesP...). January 1997.
  6. Parr, T., and Coker, J. "Parsers, Part III. A Parser for the Java Language." (http://developer.java.sun.com/developer/technicalArticles/Parser/SeriesP...). March 1997.
  7. Stanchfield, S., and Parr, T. "Parsers, Part IV. A Java Language Cross-Reference Tool."
    (http://developer.java.sun.com/developer/technicalArticles/Parser/SeriesP...). December 1997.
  8. Joy, B., Steele, G., Gosling, J., and Bracha, G. The Java Language Specification. Addison-Wesley.

In order to post a comment you need to be registered and logged in.

Register | Sign-in

Reader Feedback: Page 1 of 1

Enterprise Open Source Magazine Latest Stories . . .
Apache Deltacloud, the Red Hat-contributed ReSTful API that abstracts differences between clouds so services on any cloud can be managed – provided of course there’s a driver – has graduated from the Apache Foundation’s incubator and is now a full-fledged Top-Level Project (TLP). The...
With Cloud Expo 2012 New York (10th Cloud Expo) just four months away, what better time to start introducing you in greater detail to the distinguished individuals in our incredible Speaker Faculty for the technical and strategy sessions at the conference... We have technical and st...
AMD said late Tuesday that its chief sales officer Emilio Ghilardi had left the company and that CEO and president Rory Read is going to do his job while a replacement is sought. AMD didn’t say why Ghilardi left but it’s assumed Read wants his own people. Read is relatively new to th...
During the lifespan of M3 (Monitis Monitor Manager) there has always been something lacking – timers. M3 execution procedure was outlined in this previous article. The execution mentioned in the latter was a one-time-execution, whereas server monitoring requires periodic invocati...
Red Hat is putting its bought-in Gluster scale-out NAS storage technology, acquired in October, on the Amazon cloud. It’s styled Red Hat Virtual Storage Appliance for Amazon Web Services and other clouds are supposed to follow in short order.
A new episode of the screencast series is now available at the OpenNebula YouTube Channel. This screencast demonstrates the new easily-customizable self-service portal for cloud consumers. Its aim is to offer a simplified access to shared infrastructure for non-IT end users. The scree...
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021


SYS-CON Featured Whitepapers
ADS BY GOOGLE