Oracle8i Java Developer's Guide Release 2 (8.1.6) A81353-01 |
|
Java applications are supported within the Oracle8i database. Java applications can range from the simple standalone application to large, enterprise solutions using EJB or CORBA. All supported Java APIs cannot be covered within a single document; thus, several books describe the full support for Java within Oracle8i. This book provides a general overview for how you should program your Java applications when loading and running these applications in the database. Secondly, this book helps you choose which type of Java application you might develop, and direct you to the corresponding book for detailed information on that subject.
This chapter contains the following information:
Java, which was developed at Sun Microsystems, has emerged over the last several years as the object-oriented programming language of choice. It includes the following concepts:
The result is a language easily learned by existing C programmers, but which remains truly object-oriented and efficient for application-level programs.
This section covers some basic terminology for discussing details of Java application development in the Oracle8i environment. The terms should be familiar to experienced Java programmers. A detailed discussion of object-oriented programming or of the Java language is beyond the scope of this book. Many texts, in addition to the complete language specification, are available at your bookstore and on the Internet. See "Java Information Resources" in the Preface, and "Suggested Reading" in the Oracle8i Java Stored Procedures Developer's Guide. for pointers to reference materials and for places to find Java-related information on the Internet.
All object-oriented programming languages support the concept of a class. As with a table definition, a class provides a template for objects that share common characteristics. Each class can contain the following:
When you create an object from a class, you are creating an instance of that class. The instance contains the fields of an object, which are known as its data, or state. Figure 1-1 shows an example of an Employee
class defined with two attributes: last name (lastName
) and employee identifier (ID
).
When you create an instance, the attributes store individual and private information relevant only to the employee. That is, the information contained within an employee instance is known only for that single employee. The example in Figure 1-1 shows two instances of employee--Smith and Jones. Each instance contains information relevant to the individual employee.
Attributes within an instance are known as fields. Instance fields are analogous to the fields of a relational table row. The class defines the fields, as well as the type of each field. You can declare fields in Java to be static, public, private, protected, or default access.
The language specification defines the rules of visibility of data for all fields. Rules of visibility define under what circumstances you can access the data in these fields.
The class also defines the methods you can invoke on an instance of that class. Methods are written in Java and define the behavior of an object. This bundling of state and behavior is the essence of encapsulation, which is a feature of all object-oriented programming languages. If you define an Employee
class, declaring that each employee's id
is a private field, other objects can access that private field only if a method returns the field. In this example, an object could retrieve the employee's identifier by invoking the Employee.getId()
method.
In addition, with encapsulation, you can declare that the Employee.getId()
method is private, or you can decide not to write an Employee.getId()
method. Encapsulation helps you write programs that are reusable and not misused. Encapsulation makes public only those features of an object that are declared public; all other fields and methods are private. Private fields and methods can be used for internal object processing.
Java defines classes within a large hierarchy of classes. At the top of the hierarchy is the Object
class. All classes in Java inherit from the Object
class at some level, as you walk up through the inheritance chain of superclasses. When we say Class B inherits from Class A, each instance of Class B contains all the fields defined in class B, as well as all the fields defined in Class A. For example, in Figure 1-2, the FullTimeEmployee
class contains the id
and lastName
fields defined in the Employee
class because it inherits from the Employee
class. In addition, the FullTimeEmployee
class adds another field, bonus
, which is contained only within FullTimeEmployee
.
You can invoke any method on an instance of Class B that was defined in either Class A or B. In our employee example, the FullTimeEmployee
instance can invoke methods defined only within its own class, or methods defined within the Employee
class.
Instances of Class B are substitutable for instances of Class A, which makes inheritance another powerful construct of object-oriented languages for improving code reuse. You can create new classes that define behavior and state where it makes sense in the hierarchy, yet make use of pre-existing functionality in class libraries.
Java supports only single inheritance; that is, each class has one and only one class from which it inherits. If you must inherit from more than one source, Java provides the equivalent of multiple inheritance, without the complications and confusion that usually accompany it, through interfaces. Interfaces are similar to classes; however, interfaces define method signatures, not implementations. The methods are implemented in classes declared to implement an interface. Multiple inheritance occurs when a single class simultaneously supports many interfaces.
Assume in our Employee
example that the different types of employees must be able to respond with their compensation to date. Compensation is computed differently for different kinds of employees.
In traditional procedural languages, you would write a long switch statement, with the different possible cases defined.
switch: (employee.type) { case: Employee
return employee.salaryToDate;
case: FullTimeEmployee
return employee.salaryToDate + employee.bonusToDate
...
If you add a new kind of Employee
, you must update your switch statement. If you modify your data structure, you must modify all switch statements that use it. In an object-oriented language such as Java, you implement a method, compensationToDate()
, for each subclass of Employee
class that requires any special treatment beyond what is already defined in Employee
class. For example, you could implement the compensationToDate()
method of NonExemptEmployee
, as follows:
private float compensationToDate() {
return super.compensationToDate() + this.overtimeToDate();
}
You implement FullTimeEmployee
's method, as follows:
private float compensationToDate() {
return super.compensationToDate() + this.bonusToDate();
}
The common usage of the method name compensationToDate()
allows you to invoke the identical method on different classes and receive different results, without knowing the type of employee you are using. You do not have to write a special method to handle FullTimeEmployees
and PartTimeEmployees
. This ability for the different objects to respond to the identical message in different ways is known as polymorphism.
In addition, you could create an entirely new class that does not inherit from Employee
at all--Contractor
--and implement a compensationToDate()
method in it. A program that calculates total payroll to date would iterate over all people on payroll, regardless of whether they were full-time, part-time, or contractors, and add up the values returned from invoking the compensationToDate()
method on each. You can safely make changes to the individual compensationToDate()
methods with the knowledge that callers of the methods will work correctly. For example, you can safely add new fields to existing classes.
As with other high-level computer languages, your Java source compiles to low-level machine instructions. In Java, these instructions are known as bytecodes (because their size is uniformly one byte of storage). Most other languages, such as C, compile to machine-specific instructions; for example, instructions specific to an Intel or HP processor. Your Java source compiles to a standard, platform-independent set of bytecodes, which interacts with a Java virtual machine (JVM). The JVM is a separate program optimized for the specific platform on which you execute your Java code. Figure 1-3 shows how Java can maintain platform independence. Your Java source is compiled into bytecodes, which are platform independent. Each platform has installed a JVM that is specific to its operating system. The Java bytecodes from your source get interpreted through the JVM into appropriate platform dependent actions.
When you develop a Java program, you use predefined core class libraries written in the Java language. The Java core class libraries are logically divided into packages that provide commonly-used functionality, such as basic language support (java.lang
), input/output (java.io
), and network access (java.net
). Together, the JVM and core class libraries provide a platform on which Java programmers can develop with the confidence that any hardware and operating system that supports Java will execute their program. This concept is what drives the "write once, run anywhere" idea of Java.
Figure 1-4 illustrates how Oracle's Java applications sit on top of the Java core class libraries, which in turn sit on top of the JVM. Because Oracle's Java support system is located within the database, the JVM interacts with the Oracle database libraries, instead of directly with the operating system.
Sun Microsystems furnishes publicly available specifications for both the Java language and the JVM. The Java language specification (JLS) defines things such as syntax and semantics; the JVM specification defines the necessary low-level behavior for the "machine" that executes the bytecodes. In addition, Sun Microsystems provides a compatibility test suite for JVM implementors to determine if they have complied with the specifications. This test suite is known as the Java Compatibility Kit (JCK). Oracle's JVM implementation complies fully with JCK. Part of the overall Java strategy is that an openly specified standard, together with a simple way to verify compliance with that standard, allows vendors to offer uniform support for Java across all platforms.
The Java language has key features that make it ideal for developing server applications. These features include:
The only reason that you are allowed to write and load Java applications within the database is because it is a safe language. Java has been developed to prevent anyone tampering with the operating system that the Java code resides in. Some languages, such as C, can introduce problems within the database. Java, because of its design, is a safe language to allow within the database.
Although the Java language presents many advantages to developers, providing an implementation of a JVM that supports Java server applications in a scalable manner is a challenge. This section discusses some of these challenges.
Multithreading support is often cited as one of the key scalability 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.
As a database server, Oracle8i efficiently schedules work for thousands of users. The Oracle8i Aurora JVM uses the facilities of the RDBMS server to concurrently schedule Java execution for thousands of users. Although Oracle8i supports Java language level threads required by the Java language specification (JLS) and Java Compatibility Kit (JCK), using threads within the scope of the database will not increase your scalability. Using the embedded scalability of the database eliminates the need for writing multithreaded Java servers. You should use the database's facilities for scheduling users by writing single-threaded Java applications. The database will take care of the scheduling between each application; thus, you achieve scalability without having to manage threads. You can still write multithreaded Java applications, but multiple Java threads will not increase your server's performance.
One difficulty multithreading imposes on Java is the interaction of threads and automated storage management, or garbage collection. The garbage collector executing in a generic JVM has no knowledge of which Java language threads are executing or how the underlying operating system schedules them.
Garbage collection is a major feature of Java's automated storage management, eliminating the need for Java developers to allocate and free memory explicitly. Consequently, this eliminates a large source of memory leaks that commonly plague C and C++ programs. 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, the overall cost is reasonable, considering the alternatives.
Garbage collection imposes a challenge to the JVM developer seeking to supply a highly scalable and fast Java platform. Aurora's JVM meets these challenges in the following ways:
The footprint of an executing Java program is affected by many factors:
From a scalability perspective, the key to supporting many concurrent clients is a minimum per-user session footprint. Aurora keeps the per-user session footprint to a minimum by placing all read-only data for users, such as Java bytecodes, in shared memory. Appropriate garbage collection algorithms are applied against call and session memories to maintain a small footprint for the user's session. Aurora uses three types of garbage collection algorithms to maintain the user's session memory:
JServer performance is enhanced by implementing a native compiler.
Java executes platform-independent bytecodes on top of a JVM, which in turn deals with the specific hardware platform. Anytime you add levels within software, your performance is degraded. Because Java requires going through an intermediary to interpret platform-independent bytecodes, a degree of inefficiency exists for Java applications that does not exists within a platform-dependent language, such as C. To address this issue, several JVM suppliers create native compilers. Native compilers translate Java bytecodes into platform-dependent native code. This eliminates the interpreter step and improves performance. The following describes two methods for native compilation:
Oracle8i uses static compilation to deliver its core Java class libraries, the Aurora/ORB, and JDBC code in natively compiled form. It is applicable across all the platforms Oracle supports, whereas a JIT approach requires low-level, processor-dependent code to be written and maintained for each platform. In a future release, this native compilation technology will be available for use with your own Java code. Refer to "Natively Compiled Code" for more information.
Another strong feature of Java is dynamic class loading. The class loader loads classes from the disk (and places them in the JVM-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 the following problems in a server environment:
Problem | Description | Solution |
---|---|---|
Predictability |
The class loading operation places a severe penalty on first-time execution. A simple program can cause Aurora to load many core classes to support its needs. A programmer cannot easily predict or determine the number of classes Aurora loads. |
Aurora loads classes dynamically, just as with any other Java 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. |
Reliability |
A benefit of dynamic class loading is that it supports program updating. For example, you would update classes on a server, and clients who download the program and load it dynamically see the update whenever they next use the program. Server programs tend to emphasize reliability. As a developer, you must know that every client executes a specific program configuration. You do not want clients to inadvertently load some classes that you did not intend them to load. |
Oracle8i separates the upload and resolve operation from the class loading operation at runtime. You upload Java code you developed to the server using the |
One appeal of Java is its ubiquity and the growing number of programmers capable of developing applications using it. Oracle furnishes enterprise application developers with an end-to-end Java solution for creating, deploying, and managing Java applications. The total solution consists of client- and server-side programmatic interfaces, tools to support Java development, and a Java virtual machine integrated with the Oracle8i database server. All of these products are 100 percent compatible with Java standards.
In addition to the Aurora JVM, the Oracle8i's Java programming environment consists of:
To enable your decision making for which Java APIs to use, examine the following table:
If you are a PL/SQL programmer exploring Java, you will be interested in Java stored procedures. A Java stored procedure is a program you write in Java to execute in the server, exactly as a PL/SQL stored procedure. You invoke it directly with products like SQL*Plus or indirectly with a trigger and can access it from any Net8 client--OCI, PRO*, JDBC or SQLJ. The Oracle8i Java Stored Procedures Developer's Guide. explains how to write stored procedures in Java, how to access them from PL/SQL, and how to access PL/SQL functionality from Java.
In addition, you can use Java to develop powerful programs independently of PL/SQL. Oracle8i provides a fully compliant implementation of the Java programming language and JVM.
You can invoke existing PL/SQL programs from Java and invoke Java programs from PL/SQL. This solution protects and leverages your existing investment while opening up the advantages and opportunities of Java-based Internet computing.
Oracle offers two different application programming interfaces (APIs) for Java developers to access SQL data--JDBC and SQLJ. Both APIs are available on client and server, so you can deploy the same code in either place.
JDBC is a database access protocol that enables you to connect to a database and then prepare and execute SQL statements against the database. Core Java class libraries provide only one JDBC API. JDBC is designed, however, to allow vendors to supply drivers that offer the necessary specialization for a particular database. Oracle delivers JServer with the following three distinct JDBC drivers.
For more information on JDBC, see "Utilizing SQLJ and JDBC for Querying Database" or a complete detailed description within the Oracle8i JDBC Developer's Guide and Reference.
JDBC provides a low-level API for accessing SQL data from Java. It introduces Java classes that mirror their SQL equivalents. Oracle has worked with other vendors, including IBM, Tandem, Sybase, and Sun Microsystems, to develop a standard way to embed SQL statements in Java programs--SQLJ. This work has resulted in a new standard (ANSI x.3.135.10-1998) for a simpler and more highly productive programming API than JDBC. A user writes applications to this higher-level API and then employs a preprocessor to translate the program to standard Java source with JDBC calls. At runtime, the program can communicate with multi-vendor databases using standard JDBC drivers. SQLJ provides a simple, but powerful, way to develop both client-side and middle-tier applications that access databases from Java. You can use it in stored procedures, triggers, methods within the JServer environment, and with EJB and CORBA. In addition, you can combine SQLJ programs with JDBC.
The SQLJ translator is a Java program that translates embedded SQL in Java source code to pure JDBC-based Java code. Because JServer provides a complete Java environment, you can not only compile SQLJ programs on a client for execution on the JServer, but you can compile them directly on the server. Oracle8i's adherence to Internet standards allows you to choose the development style that fits your needs.
For more information on SQLJ, see "Utilizing SQLJ and JDBC for Querying Database" or for a complete detailed description, see the SQLJ Developer's Guide and Reference.
In addition to support for traditional RDBMS-stored procedures, JServer comes with a built-in CORBA 2.0 ORB and support for Enterprise JavaBeans (EJB). CORBA and EJB allow you to distribute Java components and application logic between client, middle-tier, and database server.
"Java and Object-Oriented Programming Terminology" discusses encapsulation as 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 bean.
A large component library provides the basis for assembling an application from pre-built, pre-tested building blocks. However, beans are limited in their ability to build complex business applications involving transactional logic. To address this limitation, a group of companies, including Oracle, Sun Microsystems, and IBM, developed the Enterprise JavaBean (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, they can interact with open Internet standards, such as JavaBeans and EJB, with bridge products available from different vendors.
The introduction of Java to the Oracle8i server allows you to use several Java Integrated Development Environments. JServer's adherence to Java compatibility and open Internet standards and protocols ensures that your 100% pure Java programs work when you deploy them on JServer. Oracle delivers JServer with many tools or utilities, all written in Java, that make development and deployment of Java server applications easier. Oracle's JDeveloper has many features designed specifically to make deployment of Java stored procedures and Enterprise JavaBeans easier.
This guide is the starting point for Oracle8i Java developers. It outlines some of the unique features of Java programming with Oracle8i, including aspects of the Aurora JVM, explaining how to take advantage of these features in your Java programs.
Once you have mastered the basics of Java development within the Oracle8i database, you might need more information for the specific protocol you will use in implementing your Java application. The following list includes other books within the documentation set that will help you in your application development:
Protocol | Description | Book Title |
---|---|---|
JDBC |
Oracle8i Java developers should become familiar with Oracle's Java Database Connectivity (JDBC) product because it provides the basis for accessing SQL data from Java programs, as well as Oracle-specific extensions to this Java standard. JDBC is an industry standard. |
|
SQLJ |
You may find it easier to develop Java programs that access SQL data using embedded SQL in Java (SQLJ). SQLJ uses a preprocessor, written in Java, to translate embedded SQL statements to standard JDBC-style programs. SQLJ is an industry standard. |
|
JPublisher |
JPublisher provides a simple and convenient tool to create Java programs that access existing Oracle relational database tables. |
|
Java Stored Procedures |
If you are a PL/SQL programmer exploring Java, you will be interested in Java stored procedures. A Java stored procedure is a program you write in Java to execute in the server, exactly as a PL/SQL stored procedure. You invoke it directly with products like SQL*Plus or indirectly with a trigger and can access it from any Net8 client--OCI, PRO*, JDBC or SQLJ. The Oracle8i Java Stored Procedures Developer's Guide explains how to write stored procedures in Java, how to access them from PL/SQL, and how to access PL/SQL functionality from Java. In addition, you can use Java to develop powerful programs independently of PL/SQL. Oracle8i provides a fully compliant implementation of the Java programming language and JVM. |
|
EJB and CORBA |
For distributed applications, you will utilize either the ORB or EJB technology. Oracle's open distributed object technology is included in its Object Request Broker (the Aurora/ORB) and Enterprise JavaBeans (EJB) functionality. The Aurora/ORB and EJB furnish powerful standards-based frameworks and tools to help you build scalable Java applications that provide seamless transactional access to Oracle data across your intranet or the Internet. |
Oracle8i Enterprise JavaBeans and CORBA Developer's Guide
|