Oracle8i Java Developer's Guide
Release 8.1.5

A64682-01

Library

Product

Contents

Index

Prev Next

2
Java Platform for the Enterprise

This chapter discusses features that make the Java language well suited to enterprise application development, focusing initially on general language features and then describing the specifics of the JServer implementation. JServer provides the most scalable Java server solution on the marketplace because of critical design features that we will discuss in this chapter.

Key Features of the Java Language

The Java language has key features that make it ideal for developing server applications. These features include:

Challenges In Developing a Scalable Java Platform

Although the Java language presents many advantages to developers, providing an implementation of a virtual machine that supports Java server applications in a scalable manner is a challenge. This section discusses some of these challenges. By understanding Oracle8i's solution to these challenges, you will be better prepared to build Java applications that make maximum use of the power of Oracle's JServer platform.

Multithreading

Multithreading support is often cited as one of the key features of the Java language. Certainly, the Java language and class libraries make it simpler to write multithreaded applications in Java than many other languages, but it is still a daunting task in any language to write reliable, scalable multithreaded code. Oracle8i is, of course, a server, and a critical element of the server is its ability to efficiently schedule the work of many thousands of users. The Oracle8i Aurora Java virtual machine uses the facilities of the RDBMS server to concurrently schedule Java execution for thousands of users. We refer to this as Java executing within a server. Although Oracle8i supports Java language level threads required by the JLS and JCK, all Java code in Oracle8i executes as a call within a session. It is, therefore, not necessary to write server-resident Java code that uses Java's multithreading capabilities to attempt to gain throughput for multiple users. We refer to this case as writing a server in Java. The array of programming services Oracle8i furnishes allows you to write Java code that will automatically be called on behalf of your clients, in the context of a highly scalable server. For people who do need to deliver a scalable server written in Java, as opposed to Java executing in the Oracle8i server, we provide a powerful framework for gaining access to the same scalability architecture Oracle uses internally. For example, the Aurora/ORB uses this framework rather than the Java language-level threads that the standard VisiBroker ORB it is based on uses. The difference is, of course, completely invisible to ORB developers, and the users of ORB applications enjoy greater responsiveness under load.

Refer to the discussions in the section "Threads" in Chapter 4, "JServer Environment Details", for more information on the thread model implementation in JServer.

One difficulty that multithreading imposes on Oracle as the provider of a scalable Java platform is the interaction of threads and automated storage management, or garbage collection. The garbage collector executing in a virtual machine has no knowledge of which Java language threads are executing or how the underlying operating system (or the virtual machine in some case) schedules them. In a simple non-Oracle8i model where a single user maps to a single Java language level thread, the same single garbage collector deals with all garbage from all users. Different techniques typically deal with allocation and collection of objects of varying lifetimes and size. The result in a heavily multithreaded application is, at best, heavily dependent upon O/S support for native threads and, at worst, unreliable and extremely limited in scalability. High levels of scalability for such implementations have not been convincingly demonstrated.

Oracle8i's solution to this problem is built in. Even when thousands of users connect to the server and execute the same Java code, each user experiences it as if he is executing his own Java code on his own Java virtual machine. It is the responsibility of the Aurora virtual machine and the Oracle8i server to make use of O/S processes and threads using the proven and scalable approach of the Oracle RDBMS. As a by-product of this approach, the virtual machine's garbage collector is more reliable and efficient because it never collects garbage from more than one user at any time.

Automated Storage Management

Garbage collection is a major aspect of Java's automated storage management, eliminating the need for Java developers to allocate and free memory explicitly and, consequently, eliminating a large source of bugs and memory leaks that commonly plague C and C++ programs. As you might expect, there is a price for such a benefit--garbage collection contributes to the overhead of program execution speed and footprint. Although many papers have been written qualifying and quantifying the trade-off with languages that do not support it, the overall cost is reasonable considering the alternatives. In any event, garbage collection certainly imposes a challenge to the virtual machine developer seeking to supply a highly scalable and fast Java platform. Part of this challenge is met by the fundamental architectural decisions regarding multithreading and scheduling, as we just discussed--Java executes in the Oracle8i server and makes use of the server's proven scalability architecture to provide a scalable Java platform.

The Oracle8i Aurora Java virtual machine enjoys a huge advantage because the burden and complexity of the memory manager's job does not increase as the number of users increases. The memory manager always deals with the allocation and collection of objects within a single session--which typically translates to the activity of a single user. The simplicity of this approach allows us to apply sophisticated allocation and collection schemes tuned to the types and lifetimes of objects. For example, new objects are allocated in fast and cheap call memory, designed for quick allocation and access. Objects held in Java static variables are migrated to more precious and expensive session space. Different garbage collection algorithms are applied in the various memory areas, resulting in high efficiency and low overhead.

Figure 2-1 Encapsulation


Garbage collection is "transparent" to you as a Java programmer. You generally do not need to worry about it, and you certainly do not need to account for it as a platform portability issue. Later, we will discuss in more detail the different tools at your disposal in Oracle8i to control the default assumptions and behavior of the memory manager and garbage collector. In addition, we will discuss how migration of static variables at end of call may affect you.

Footprint

The footprint of an executing Java program is affected by many factors:

From a scalability perspective, the key to supporting many concurrent clients is minimum incremental per-user session footprint, which is a major focus of the Oracle8i Aurora Java virtual machine. Aurora keeps the per-user session footprint to a minimum primarily by placing read-only data all users employ, such as Java bytecodes, in shared memory. Garbage collection algorithms appropriate to the kind of memory being used help to keep call and session memory usage in control. For example, Aurora uses generational scavenging in call memory where it typically allocates and collects many short-lived objects, while it uses a copying collector for session memory where compactness of longer-lived object allocations is critical. Again, although the details of garbage collection techniques have no impact on you as a developer, they form one of the key underlying features that enable you to write scalable Java applications in a server environment.

Aurora preserves the state of your Java program between calls by migrating all objects reachable from static variables into session space at end of call. Aurora performs this migration operation at the end of every call, without any intervention by you. From a footprint and performance perspective, you must be aware of the way you use static variables. If you store objects in static variables indiscriminately or needlessly, then you will be imposing a burden on the memory manager to perform the migration and consume per-session resources when it is not necessary. This consumption of valuable memory resources will ultimately limit the number of users who can exercise your Java program on a given hardware platform. You can control excess session space usage by avoiding the use of static variables for instance-specific data. When necessary, you can use the EndOfCallRegistry notification furnished by the Aurora virtual machine to clear static variables at end of call and a lazy initialization technique to initialize them. Refer to the discussion in the section "End-of-Call Migration" in Chapter 4, "JServer Environment Details", for more information.

The issue of migration may seem as an unnecessary complication to consider when writing Java programs. However, with Aurora, you do not need to deal with it at all--if you ignore it, then your program will work anyway. This is a by-product of the single-user-single-virtual-machine model that provides a consistently scalable model across all Oracle platforms. You will not need to be concerned about the issue of migration when you use Java for implementing simple stored procedures. It becomes a concern only for more complex "stateful" server applications you implement in Java. The Aurora/ORB is an example of an application where a single user invokes many calls within a session. In this case, the amount of state migrated is carefully limited to only what is relevant, and unnecessary caches of objects (which are often held in static variables) are flushed at the end of call.

Speed

Because Java executes platform-independent bytecodes on top of a virtual machine, which in turn deals with the specific hardware platform, a degree of inefficiency is inherent in Java bytecode interpreters as compared to a language such as C. Virtual machine suppliers such as Oracle address this speed issue in different ways. One popular approach is to use a Just In Time (JIT) compiler. JITs quickly compile Java bytecodes to native (platform-specific) machine code, allowing Java code that is run frequently to be executed at speeds closer to languages such as C. Oracle has adopted a Way Ahead of Time (WAT) approach to gain speed. In the WAT approach, Aurora translates Java bytecodes to platform-independent C code, which a standard C compiler then compiles for the target platform. This approach is more suitable to a server environment where you deploy and update Java applications relatively infrequently. It has the advantage of being applicable across all of the platforms Oracle supports, whereas a JIT approach requires low-level, processor-dependent code to be written and maintained for each platform. Oracle's approach also benefits from the extremely mature and efficient platform-specific compilation technology found in modern C compilers.

Oracle8i uses this technology to deliver the core Java class libraries, the Aurora/ORB, and JDBC code in natively compiled form. In a future release, this native compilation technology will be available for use with your own Java code. Refer to the discussion in the section "Natively Compiled Code" in Chapter 4, "JServer Environment Details", for more information.

Dynamic Class Loading

In addition to Java's security model, Java has been embraced as the language of the Internet because of its approach to dynamic class loading. The class loader loads classes from the disk (and places them in the virtual-machine-specific memory structures necessary for interpretation) only as they are used during program execution. The class loader locates the classes in the CLASSPATH and loads them during program execution. This approach, which works well for applets, poses some challenges in a server environment:

Oracle8i meets these challenges while satisfying the constraints of the Java Language Specification. The Aurora Java virtual machine loads classes dynamically, just as with any other virtual machine. The same one-time class loading speed hit is encountered. However, because Aurora loads the classes into shared memory, no other users of those classes will cause the classes to load again--they will simply use the same pre-loaded classes. Oracle8i ensures the reliability of this operation because it separates the upload and resolve operation from the class loading operation at runtime. You upload Java code you developed to the server using a utility known as loadjava. Instead of the Java-style CLASSPATH environment variable that tells the class loader how to find classes your code uses or refers to at runtime, you specify a resolver at installation time. The resolver is completely analogous to the runtime CLASSPATH, but allows you to specify the schemas in which the classes reside. This separation of resolution from class loading means that you will always know exactly what program users will execute. Refer to the discussion in Appendix A, "Tools", for more details on loadjava and other utilities, as well as resolvers.

Using Components

As discussed in Chapter 1, encapsulation is a key element of object-oriented programming. Each object maintains its own private state and supports a set of behaviors, which you implement as methods. Java provides a formal way to define components, using JavaBeans. A JavaBean component is a reusable object or group of objects (more precisely, an object graph) that you can manipulate in a "builder tool" of some type. IDEs, such as JDeveloper, provide tools to build user interfaces that use JavaBeans and create JavaBean components. Each bean specifies its public interface and properties that can be manipulated. JavaBeans do not have to be visually-oriented components. Virtually any Java programming abstraction can potentially be represented and manipulated as a JavaBean.

A large component library provides an excellent basis for assembling an application from pre-built, pre-tested building blocks. However, JavaBeans are limited in their applicability to complex business applications involving transactional logic. To address this limitation, a group of companies including Oracle, Sun Microsystems, and IBM developed the Enterprise JavaBeans (EJB) specification. EJB introduces a declarative mechanism for specifying how components deal with transactions and security. Refer to the Oracle8i Enterprise JavaBeans and CORBA Developer's Guide for detailed information about using EJB components in Oracle8i.

There are alternative component models to JavaBeans and Enterprise JavaBeans-- notably, Microsoft's COM and COM+ models. If you have existing Microsoft COM-oriented applications, then they can interact with open Internet standards such as JavaBeans and EJB with bridge products available from different vendors.




Prev

Next
Oracle
Copyright © 1999 Oracle Corporation.

All Rights Reserved.

Library

Product

Contents

Index