Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Introduction to Thin Client Framework, Part 1: The basic elements

Get familiar with TCF concepts and architectural components

Peter Bahrs, PhD (tcfhelp@us.ibm.com), Distinguished Engineer, IBM 
Dr. Peter Bahrs is an IBM Distinguished Engineer and IT Architect in the IBM Software Services organization. Dr. Bahrs specializes in large e-business systems development in the financial services industries. He holds several patents and has spoken at industry conferences such as JavaOne. Dr. Bahrs is currently on assignment to IBM Zurich, Switzerland. He can be reached at tcfhelp@us.ibm.com.
Barry Feigenbaum, Ph.D., Senior Consulting IT Specialist, IBM 
author
Dr. Barry Feigenbaum is a member of the IBM Worldwide Accessibility Center, where he serves as a member of a team that helps IBM make its products accessible to people with disabilities. Dr. Feigenbaum has published several books and articles, holds several patents, and has spoken at industry conferences such as JavaOne. He serves as an Adjunct Assistant Professor of Computer Science at the University of Texas, Austin. You can contact Dr. Feigenbaum at feigenba@us.ibm.com.

Summary:  Thin Client Framework (TCF) is a lightweight, flexible, and powerful programming framework for Java client applications. In this two-part series, you will learn about TCF from two of its originators. Follow along as Drs. Barry Feigenbaum and Peter Bahrs use detailed discussion, a working example, and live code samples to introduce you to the TCF architecture, design, and implementation.

Date:  07 Jan 2003
Level:  Introductory
Also available in:   Japanese

Activity:  7373 views
Comments:  

Thin Client Framework (TCF) is a design, development, and deployment approach for easily and rapidly developing high-functioning, extendable, and responsive e-business clients in the Java language. TCF builds on the Model-View-Controller design pattern and raises it to the level of an application architecture. Through consistent implementation of an event-based communication model, TCF provides a highly pluggable, component-based structure for client-side application development.

TCF defines best practices for writing Java client applications, with emphasis on the separation of coding concerns and responsibilities. Its high degree of modularity provides for maximum reuse. Because it is compatible with multiple data, server, and network models, TCF is extremely flexible, enabling Java clients to be as thin, or as thick, as needed. Finally, TCF supports a formula-based approach to estimating development costs, and it enables parallel component development on the client while supporting concurrent development of clients and servers.

In this two-part series, we will provide a beginner's introduction to TCF. Part 1 of the series will familiarize you with the basic elements of the architecture. We'll explain the concepts behind TCF and describe the components of the architecture. We'll also provide a working example application, so you can see for yourself how the components are coded. In Part 2, we'll provide a more detailed discussion of TCF's design and implementation.

Benefits of TCF

TCF has been shown to provide the following benefits:
  • Eases project management activities
  • Provides a repeatable development pattern
  • Enables fine partitioning of skills
  • Enables development of quick demos
  • Improves client development time by up to 75 percent
  • Offers up to two-times greater client component reuse than other methods
  • Yields small Java client programs (in terms of byte-code size)
  • Encourages high programmer productivity
  • Provides flexibility through multiple data models, servers, and protocols
  • Enables Internet-friendly clients
  • Enables parallel client- and server-side development

Client application design

Developing distributed application clients involves many interrelated design considerations. Some of these considerations are illustrated in Figure 1. A successful thin-client development framework must address these considerations in a manner that is simple and straightforward.


Figure 1. Client-side design considerations
Client-side design considerations

In the scope of end-to-end systems development, the mid-tier and back-end servers are generally the more difficult and time-consuming pieces. They, not the client, should consume the majority of your design effort. Figure 2 is one example of an end-to-end system design:


Figure 2. End-to-end system complexity
End-to-end system complexity

By providing a tested pattern for client-side development, TCF ensures that the most important aspects of the client are addressed, while greatly reducing the time spent on client-side design considerations.

Thick or thin?

One important design consideration is whether the client is to be thin or thick (also known as fat). A client is defined as thick or thin based on the amount of function (or business logic) it holds. Application clients can be implemented across a spectrum from purely thin to fully fat, and hybrids are not uncommon.

TCF applications are characterized by having application business logic split between the client and the server. Generally, in TCF applications, message sizes are small and efficient, resulting in good interactivity without the need for high-speed links. TCF apps also are known for loose coupling between the client and the server, allowing each side to be developed separately. The split functionality of TCF's design is most practical for highly distributed applications. Figure 3 shows a typical hybrid TCF configuration:


Figure 3. Hybrid thin-client configuration
Hybrid thin-client configuration

Coding the client

Once you've decided that there will be some business logic on the client, you have to decide how to implement it. The two most common approaches are:

  1. Use some form of browser-activated scripting language, such as JavaScript/Dynamic HTML (DHTML)
  2. Write the client as an applet or application in a robust programming language such as the Java language

In this article, we'll be working with a Java-based client implementation. The Java language is the preferred (or required) implementation when:

  • The application must accommodate users who are not connected to a network
  • The application calls for a richer or more responsive GUI than DHTML can provide
  • Client-side data caching is required or the client must be able to manipulate large amounts of data
  • Client scripting is insufficient
  • The server's session state is so large it must be distributed to the client side
  • The application requirements state that it must be written in the Java language

How to do it wrong

Listing 1 shows a typical Java application coding style. See if you can figure out what's wrong with the code.


Listing 1. Typical Java application code

import java.util.*;
import com.xyz.*;

Customer customer   = createCustomer();
  :
Socket socket       = createSocket();

customer = (Customer) socket.readObject();
String name         = customer.getName();

TextField tf        = new TextField();
Frame frame         = new Frame();
tf.setText(name);
frame.add(tf);

LogFile log         = createLogFile();
log.writeStatus("updated");

What we have here is the beginning of an unmanageable, thick client.

  • Why? Because it employs multiple code responsibilities mixed throughout the application.

  • What's the fix? Separate the code by responsibilities.

TCF and the MVC pattern

The Model-View-Controller (MVC) pattern is a classic and very well understood design pattern. As shown in Figure 4, the MVC pattern can be implemented at numerous levels throughout an application. At the finest level, the MVC pattern determines how GUI controls work. At the middle level, it structures application components. At the broadest level, the MVC pattern partitions multiple tiers of the application, representing the popular three-tier application model. TCF is an example of the middle level of MVC use.


Figure 4. TCF's relationship to the MVC pattern
TCF's relationship to the MVC pattern

At this point, you should have a basic understanding of the Thin Client Framework's contribution to the distributed application development process; what a typical TCF client looks like; how not to code a distributed application client in Java code; and the underlying role of the MVC pattern in TCF. From here, we're ready to delve into the TCF architecture.


The TCF architecture

The entire TCF architecture is shown in Figure 5. As you can see, it's fairly small and easy to understand. The names in ovals represent major TCF interfaces or classes, while the names in rectangles or diamonds represent TCF support classes. Communication between components is handled by events, as shown in Figure 5. Event-based communication is a fundamental characteristic of TCF's architectural pattern.


Figure 5. The TCF architecture
Diagram of the TCF architecture

Principle TCF components

The roles of the principle TCF components are:

  • The ViewController interface defines a reusable user interface component that is part of an overall client application GUI. ViewController is often implemented by an AWT (or Swing) component, such as a Panel.

  • The PlacementListener interface manages the placement of ViewControllers on the screen. PlacementListener is often implemented by the application.

  • The ApplicationMediator interface defines the control logic of an application.

  • The Transporter interface selects the appropriate destinations to process a RequestEvent.

  • A Destination is an abstraction of any service the TCF client needs.

  • The TopListener interface is used to separate business- or environment-specific responsibilities from other TCF componentry. TopListener is often implemented by the application.

  • A ViewEvent is an abstraction of a GUI event. ViewEvent is the mechanism for communication between ViewControllers and ViewListeners (typically ApplicationMediators).

  • A RequestEvent is a lightweight transaction request. RequestEvent is the mechanism for communication between ApplicationMediators and RequestListeners (typically Transporters).

  • PlacementEvent is the mechanism for communication between ApplicationMediators and PlacementListeners (typically the application).

  • TopEvent is the mechanism for communication between ApplicationMediators and TopListeners (typically the application).

Major TCF interfaces

In Figure 6, you can see the major TCF interfaces. Recall that the TCF partitions the development process into multiple coding concerns and responsibilities. Each TCF interface represents a different area of responsibility. Developers can become skilled in one or more interfaces, as appropriate to their role on the development team.


Figure 6. TCF's major interfaces/classes
TCF pattern major interfaces/classes

TCF provides a default or abstract implementation of each of its interfaces. Thus, it provides a partial implementation that you can build on. Many of the common tasks required to use TCF are built into the default interface implementation. Events fired by the source interface implementation handle all interactions between interfaces.

Event-based communication

Because the TCF architecture is component-based and event-driven, it is easy to develop and unit test each component of a TCF system in isolation. Once the events and their major, minor, and command values have been defined, the components can be tested through simple scaffolding code. Thus, definition of events between senders and receivers is the only strong tie between components.

Because the components in a TCF system are loosely coupled, they can be inserted and removed at runtime. Among other things, this enables easy support for flow tracing and data filtering/conversion.

Sizing and cost estimation

Because it uses a loosely coupled, highly scalable development paradigm, TCF makes development sizing very straightforward. Once calibrated, as shown in Figure 7, simple multiplication-based sizing will suffice for most TCF projects.


Figure 7. Example component estimation
Example component estimation

The above estimates are based on low-level design and code estimates, and the assumption that you are working with experienced Java programmers. The estimates shown are examples; your values will likely differ.


Example application

For the remainder of this article, we'll work with an example application to illustrate the concepts behind TCF. Example04 is a very simple customer information system that maintains a list of customers. The application is a panel. It can be wrapped in either a frame or an applet. The applet form is shown in the figures below. For the purposes of this article, we'll only show select parts of the application.

Once again, keep in mind that this article serves mainly as an overview; we'll go into greater detail in the second part of the series.

Example04 consists of the following components:

  • Four ViewControllers: VC1, VC2, VC3, StatusVC
  • An ApplicationMediator: AM4
  • A Transporter and a Destination
  • Akey-value pair-based data model
  • A main application (Example04)
  • A Codes interface that defines symbolic constants

We'll discuss each of the components, with the exception of the Codes interface, in the sections that follow.


Application data model

A simple key-value pair (that is, Map) structure is used as the application data model. It is passed around the application and is updated as appropriate based on user input. Listing 2 shows the two convenience methods to reset the information normally obtained from the Login and Customer Information screens:


Listing 2. Data model class definition

public class Data extends Hashtable {
    public static final String FAMILY = "Example04";
    public void initCustomer() {
    	put(Codes.TITLE, Codes.TITLE);
    	put(Codes.FIRSTNAME, Codes.FIRSTNAME);
    	put(Codes.LASTNAME, Codes.LASTNAME);
    	put(Codes.FULLNAME, Codes.FIRSTNAME + " " +
             Codes.LASTNAME);
    	put(Codes.WWW, Codes.WWW);
    	put(Codes.OFFICE, Codes.OFFICE);
    	put(Codes.PHONENUMBER, Codes.PHONENUMBER);
    	put(Codes.EMAIL, Codes.EMAIL);
    }
    public void initLogin() {
    	put(Codes.USERID, Codes.USERID);
    	put(Codes.PASSWORD, Codes.PASSWORD);
    }
    public Data() {
        initLogin();
        initCustomer();
    }
}


ViewControllers

Example04 has four view controllers:

  • VC1 is the Login screen
  • VC2 is the Customer Selection screen
  • VC3 is the Customer Information screen
  • StatusVC shows which of the previous three ViewControllers is currently active

The example application always shows two ViewControllers at once. The StatusVC is always shown at the top of the screen, while one of the other three is shown in the center of the screen. Figure 8 lets you view the Login screen:


Figure 8. VC1: The Login screen
Example ViewController 1

Event processing

Normal Java event processing is used to handle GUI events. Each ViewController translates one or more AWT events (for example, button presses) into a ViewEvent. Event data parameters are passed as data objects.

In the following code samples, we'll look at the ViewEvents for each ViewController. Each section of code is wrapped in a xxxxButton_actionPerformed method, where xxxx is the button name. To keep things brief (and simple) the wrappers are not shown.

StatusVC

StatusVC displays the Java class name of current ViewController. StatusVC is shown on all screens but its buttons are only active when VC2 is shown.

Save fires the SAVE ViewEvent:

// save customer records to a file
fireViewEvent( new ViewEvent(this, ViewEvent.SAVE));

Load fires the LOAD ViewEvent:

// load customer records
fireViewEvent( new ViewEvent(this, ViewEvent.LOAD));

Login: VC1

VC1 inputs login values, typically a userid and password. Its ViewEvents are shown below.

Login adds the input fields to the data model and fires the LOGIN ViewEvent:

// grab textfields, update data model 
     Data d = this.data;
     d.put(Codes.USERID, getNameField().getText());
     d.put(Codes.PASSWORD, getPasswordField().getText());
     setEnabled(false);
     fireViewEvent( 
         new ViewEvent(this, ViewEvent.LOGIN, d));

Note that the ViewController is disabled. This prevents it from accepting new button presses until the ViewEvent has been completely processed. The ViewEvent will be re-enabled by the refresh() method once the event has been processed.

Done fires the CANCEL ViewEvent:

     setEnabled(false);
     fireViewEvent( new ViewEvent(this, ViewEvent.CANCEL));

Customer Selection: VC2

When login is complete, VC2 is shown, as illustrated in Figure 9:


Figure 9. Customer Selection screen
Customer Selection screen

As you can see, VC2 presents a list of existing users, along with several buttons to manage and update the list. Since the processing of ViewEvents on this screen is very similar to VC1, we'll only show the Edit event.

Edit creates or updates user information:

     Data d = this.data;
     d.put( Codes.FULLNAME, 
            getAccountList().getSelectedValue());
     fireViewEvent( new ViewEvent(this, ViewEvent.DETAILS, d)); 

The selected user name is placed in the FULLNAME data model entry.

Customer Information: VC3

When either the Edit or the New button is clicked, VC3 is shown, as illustrated in Figure 10:


Figure 10. Customer information screen
Customer information screen

VC3 is used to view or edit a customer entry. Its view events are shown below.

OK grabs the data from the GUI, updates the model, and fires an UPDATE ViewEvent:

Data d = this.data(); d.initCustomer();
String fn, ln;
d.put(Codes.FIRSTNAME, fn = getFirstNameField().getText());
d.put(Codes.LASTNAME, ln = getLastNameField().getText());
d.put(Codes.FULLNAME, fn + " " + ln);
d.put(Codes.TITLE, getTitleField().getText());
d.put(Codes.PHONENUMBER, getPhoneField().getText());
d.put(Codes.WWW, getWwwField().getText());
d.put(Codes.EMAIL, geteMailField().getText());
d.put(Codes.OFFICE, getOfficeField().getText());
fireViewEvent( new ViewEvent(this, ViewEvent.UPDATE, d) );

Cancel fires a DONE ViewEvent:

fireViewEvent( new ViewEvent(this, ViewEvent.DONE) );


The ApplicationMediator

The ApplicationMediator processes the ViewEvents generated by the various ViewControllers. It sequences the ViewControllers and generates RequestEvents to preform the actions requested by the various ViewControllers. We'll look at how the ApplicationMediator handles two typical event requests below.

Initialize and activate

The ApplicationMediator is initialized as shown below. This initialization sequence creates the four ViewControllers and issues a placement request, making VC1 the active ViewController. Listing 3 shows how the ApplicationMediator handles these requests:


Listing 3. ApplicationMediator request handling

public void init() {
    super.init();
    String[] classes = {
        "com.ibm.jtc.examples.ex04.VC1",
        "com.ibm.jtc.examples.ex04.VC2",
        "com.ibm.jtc.examples.ex04.VC3",
        "com.ibm.jtc.examples.ex04.StatuVC"};
    try { initViewControllers(classes); } 
    catch (Exception e) { return; }
    firePlacementEvent( 
      new PlacementEvent(this, getVC(0), PlacementEvent.ADD, 0) );
}

Dispatch ViewEvents to handlers

The ApplicationMediator can process requests several different ways. Two of the more popular solutions, processing by event source or processing by event code, are shown below (note that both examples use synchronous event dispatching).

Option 1: Process ViewEvents by the event source
In Listing 4, the method getVC() returns the ViewControllers, as listed in the classes variable of the above init method.


Listing 4. Processing by event source

public void processViewEvent(ViewEvent ve) {
	RequestEvent re = new RequestEvent(this, MY_FAMILY);
	ViewController vc = (ViewController)ve.getSource();
	if      (vc == getVC(0)) doVC1(re, ve);
	else if (vc == getVC(1)) doVC2(re, ve);
	else if (vc == getVC(2)) doVC3(re, ve);
	else if (vc == getVC(3)) doStatusVC(re, ve);
} 

Option 2. Process ViewEvents by code values
As Listing 5 shows, the code values are major and minor. The detailed behaviors shown in Listing 5 are typically contained in the above doxxx methods.


Listing 5. Processing by code values

public void processViewEvent(ViewEvent ve) {
    RequestEvent re = new RequestEvent(this, MY_FAMILY);
    int major = ve.getMajor(), minor = ve.getMinor();
    try {
       switch ( major ) {       // process major code
            case ViewEvent.LOGIN : 
              re.setCommand(Codes.LOGIN);    // do LOGIN
              re.setData(ve.getData());
              fireRequestEvent(re);
              re.setCommand(Codes.GETNAMES); // do GETNAMES
              re.setData(ve.getData());
              fireRequestEvent(re);
              firePlacementEvent(            // remove VC1
                  new PlacementEvent(this, getVC(0),
                         PlacementEvent.REMOVE) );
    	      firePlacementEvent(            // add VC2
    	          new PlacementEvent(this, getVC(1), 
                         PlacementEvent.ADD) );
              getVC(3).refresh(getVC(1).toString());  // update status
              getVC(1).refresh(re.getData());   // update VC2 fields
              getVC(3).setEnabled(true);        // enable user actions
              break;

            case ViewEvent.DETAILS : 
              re.setCommand(Codes.GETDETAILS);  // do DETAILS
              re.setData(ve.getData());
              fireRequestEvent(re);
              firePlacementEvent(            // remove VC2
                  new PlacementEvent(this, getVC(1),
                           PlacementEvent.REMOVE) );
              firePlacementEvent(            // add VC3
                   new PlacementEvent(this, getVC(2), 
                           PlacementEvent.ADD) );
              getVC(3).refresh(getVC(2).toString()); // update status
              getVC(2).refresh(re.getData());
              break;

            case ViewEvent.CANCEL :
              fireTopEvent(                 // end execution
                  new TopEvent(this, TopEvent.EXIT) );
              break;

            case ViewEvent.REFRESH :
              re.setCommand(Codes.GETNAMES);   // do GETNAMES
              fireRequestEvent(re);
              getVC(1).refresh(re.getData());  // update VC2 fields
              break;

            case ViewEvent.DELETE :
              re.setCommand(Codes.DELETE);     // do DELETE
              re.setData(ve.getData());
              fireRequestEvent(re);
              re.setCommand(Codes.GETNAMES);   // do GETNAMES
              re.setData(ve.getData());
              fireRequestEvent(re);
              getVC(1).refresh(re.getData()); // update VC2 fields
              break;

            case ViewEvent.UPDATE :
              re.setCommand(Codes.UPDATE);    // do UPDATE
              re.setData(ve.getData());
              fireRequestEvent(re);
              refresh(re.getData());         // update all VC fields
              firePlacementEvent(            // remove VC3
                  new PlacementEvent(this, getVC(2),
                             PlacementEvent.REMOVE) );
              firePlacementEvent(            // add VC2
                   new PlacementEvent(this, getVC(1), 
                             PlacementEvent.ADD) );
              getVC(3).refresh(getVC(1).toString()); // update status
              break;

            case ViewEvent.DONE :
              firePlacementEvent(            // remove VC3
                   new PlacementEvent(this, getVC(2),
                             PlacementEvent.REMOVE) );
              firePlacementEvent(            // add VC2
                   new PlacementEvent(this, getVC(1), 
                             PlacementEvent.ADD) );
              getVC(3).refresh(getVC(1).toString()); // update status
              break;
        }
    }
    catch(Exception e) {
       e.printStackTrace();
       return;
    }
}

Listing 5 demonstrates how a typical ApplicationMediator is coded: first it decodes the major and minor values, then it processes the request. Request processing typically consists of creating and firing one or more RequestEvents to process the input action, refreshing the components with the results of the event, and changing to a new screen. To switch screens, the ApplicationMediator instructs the PlacementListener to remove the current screen and add a new one.

Transporter and Destination

Acting indirectly through the Transporter, Destinations implement RequestEvents fired from the ApplicationMediator. Note that RequestEvents go from the ApplicationMediator through the Transporter and then on to the Destination. The Transporter acts as a router to select one or more Destinations to process the RequestEvent.

Many implementations of the simple Destination provided with Example04 are possible. For simplicity, this example uses a Destination that decodes command-request values to routines that provide access to canned data. The decoding logic is shown in Listing 6:


Listing 6. Decoding logic for an example Destination

String cmd = request.getCommand();
if      (cmd.equals(Codes.GETNAMES))
    doGetNames(request);
else if (cmd.equals(Codes.GETDETAILS))
    doGetDetails(request);
else if (cmd.equals(Codes.UPDATE))
    doUpdate(request);
else if (cmd.equals(Codes.NEWRECORD))
    doNewRecord(request);
else if (cmd.equals(Codes.DELETE))
    doDelete(request);
else if (cmd.equals(Codes.LOGIN))
    doLogin(request);
else if (cmd.equals(Codes.NEWLOGIN))
    doNewLogin(request);
else if (cmd.equals(Codes.SAVE))
    doSaveData();
else if (cmd.equals(Codes.LOAD))
    doLoadData();


The example application

We'll close with a look at the example application. From the simple code samples below, you should be able to see how the various described components of the TCF architecture work together in a distributed application.

The Example04 application class is shown in Listing 7:


Listing 7. Public class Example04

public class Example04 extends JPanel 
  implements JTC, PlacementListener, TopListener {

    LocalDestination dest = null;

    AM1 am = null;

    Transporter trans = null;

    Data data = null;

    List jtcs = new Vector();       // all JTC implementers

    String filename = null";

    JPanel cp = null; 

    public Example04 app = null;    // convenient ref to me

    :
}

Listing 8 shows the application's main() method:


Listing 8. Example04's main() method

public static void main(java.lang.String[] args) {
	new Example04("Example04", 
                  args.length > 0 ? args[0] 
                                  : "example04.db");
}

Listing 9 shows the application's constructor method:


Listing 9. Example04's constructor method

public Example04(String title, String filename) {

    // setup overall GUI
    this.filename = filename;
    JFrame frame = new JFrame(title);
    frame.addWindowListener(this); // not shown
    cp = (JPanel)frame.getContentPane();
    cp.setLayout(new BorderLayout());
    cp.add(this, BorderLayout.CENTER);
    frame.pack();
    frame.setSize(525, 450);
    frame.setVisible(true);

    app = this;     // remember for JTC lists

    // setup Transporter and Destination mapping
    trans = new DefaultTransporter();
    jtcs.add(trans);
    dest = new LocalDestination();
    jtcs.add(dest);
    trans.addRequestListener(Data.FAMILY, dest);

    // setup ApplicationMediator
    am = new AM4();
    jtcs.add(am);
    am.addTopListener(this);
    am.addPlacementListener(this);
    am.addRequestListener(trans);

    //indirectly cause a PlacementEvent
    am.init(); 
    am.refresh(data = new Data()); // reset the data model
}

And the application's PlacementListener, which processes PlacementEvents, is shown in Listing 10:


Listing 10. Placement support for Example04

// the cp variable is the JFrame's ContentPane
public void placementEventPerformed(PlacementEvent pe) {
    ViewController vc = (ViewController)
          pe.getViewController();
    final Component c = pe.getComponent();
	if (vc instanceof StatusVC) {
          cp.add(c, BorderLayout.NORTH);
	} 
    else { 
        switch (pe.getMajor()) {
            case PlacementEvent.ADD :
                cp.add(c, BorderLayout.CENTER);
                validate();
                repaint();
                break;
            case PlacementEvent.REMOVE :
                cp.remove(c);
                break;
        }
    }
}

Adding complexity

Although it is extremely simple, Example04 demonstrates each of the major components and interactions of a TCF-based application. Far more complex applications are possible. For example, multiple ApplicationMediators and destinations can be used. A TopListener and TopDestination could provide access to system services. A single PlacementListener could be deployed to control the application's screen real estate. By combining several simple TCF applications, we can easily create a more complex application, as shown in Figure 11:


Figure 11. A more complex application
A more complex application

Don't miss the rest of this series

Part 2, "The TCF programming model" (January 2003)

Conclusion

In this first part of the beginner's introduction to TCF, you've learned about the conceptual underpinnings of TCF, how its architecture is laid out, and how each of the major components of the architecture works. In Part 2, we'll talk more about each of these components, but with a focus on the framework's design and programming model.


Resources

About the authors

Dr. Peter Bahrs is an IBM Distinguished Engineer and IT Architect in the IBM Software Services organization. Dr. Bahrs specializes in large e-business systems development in the financial services industries. He holds several patents and has spoken at industry conferences such as JavaOne. Dr. Bahrs is currently on assignment to IBM Zurich, Switzerland. He can be reached at tcfhelp@us.ibm.com.

author

Dr. Barry Feigenbaum is a member of the IBM Worldwide Accessibility Center, where he serves as a member of a team that helps IBM make its products accessible to people with disabilities. Dr. Feigenbaum has published several books and articles, holds several patents, and has spoken at industry conferences such as JavaOne. He serves as an Adjunct Assistant Professor of Computer Science at the University of Texas, Austin. You can contact Dr. Feigenbaum at feigenba@us.ibm.com.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=10739
ArticleTitle=Introduction to Thin Client Framework, Part 1: The basic elements
publish-date=01072003
author1-email=tcfhelp@us.ibm.com
author1-email-cc=
author2-email=feigenba@us.ibm.com
author2-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers