Oracle8i Java Developer's Guide
Release 2 (8.1.6)

A81353-01

Library

Product

Contents

Index

Prev Next

3

Invoking Java in the Database

We reviewed the basics of writing and deploying Java applications on Oracle8i in Chapter 2, "Writing Java Applications on Oracle8i". This chapter gives you an overview and examples for how to invoke Java within the database.

Overview

In Oracle8i, you utilize Java in one of the following ways:

We recommend that you approach Java development in Oracle8i incrementally, building on what you learn at each step. The easiest way to invoke Java within the database is through Java stored procedures. Once you have mastered that, you should move on to CORBA and EJB applications.

  1. You should master the process of writing simple Java stored procedures as listed in "Preparing Java Class Methods for Execution" and the Oracle8i Java Developer's Guide. This includes writing the Java class, deciding on a resolver, loading the class into the database, and publishing the class.

  2. You should understand how to access and manipulate SQL data from Java. Most Java server programs, and certainly Java programs executing on Oracle8i, interact with database-resident data. The two standard APIs for accomplishing this are JDBC and SQLJ. Because JDBC forms the foundation for SQLJ, you should understand how the two work together, even though you might be using only SQLJ in your code.

  3. If you intend to distribute Java logic between client and server or in an N-tier architecture, you should understand how CORBA and EJB work in Oracle8i. CORBA and EJB provide the simplest solution to this difficult problem, in an Internet-standard manner, enabling you to leverage component-based development for transactional applications. Furthermore, EJB and CORBA utilize Oracle8i's facilities for Java stored procedures and JDBC.

Java is a simple, general purpose language for writing stored procedures. JDBC and SQLJ allow Java to access SQL data. They support SQL operations and concepts, variable bindings between Java and SQL types, and classes that map Java classes to SQL types. You can write portable Java code that can execute on a client or a server without change. With JDBC and SQLJ, the dividing line between client and server is usually obvious--SQL operations happen in the server, and application program logic resides in the client.

As you write more complex Java programs, you can gain performance and scalability by controlling the location where the program logic executes. You can minimize network traffic and maximize locality of reference to SQL data. JDBC and SQLJ furnish ways to accomplish these goals. However, as you tend to leverage the object model in your Java application, a more significant portion of time is spent in Java execution, as opposed to SQL data access and manipulation. It becomes more important to understand and specify where Java objects reside and execute in an Internet application. Now you have become a candidate for moving into the world of CORBA and Enterprise JavaBeans.

Invoking Java Methods

The way your client calls a Java method depends on the type of Java application. The following sections discuss each of the Java APIs available for creating a Java class that can be loaded into the database and accessed by your client:

Utilizing Java Stored Procedures

You execute Java stored procedures similarly to PL/SQL. Normally, calling a Java stored procedure is a by-product of database manipulation in that it is usually the result of a trigger or DML call.

To invoke a Java stored procedure, you must publish it through a call specification. The following example shows how to create, resolve, load, and publish a simple Java stored procedure that echoes "Hello world".

  1. Write the Java class.

    Define a class, Hello, with one method, Hello.world(), that returns the string "Hello world".

    public class Hello
    {
       public static String world ()
       {
          return "Hello world";
       }
    }
    
    
  2. Compile the class on your client system. Using Sun Microsystem's JDK, for example, you invoke the Java compiler, javac, as follows:

    javac Hello.java
        
    
    
    

    Normally, it is a good idea to specify your CLASSPATH on the javac command line, especially when writing shell scripts or make files. The Java compiler produces a Java binary file--in this case, Hello.class.

    Keep in mind where this Java code will execute. If you execute Hello.class on your client system, it searches the CLASSPATH for all supporting core classes it must execute. This search should result in locating the dependent class in one of the following:

    • as an individual file in a directory, where the directory is specified in the CLASSPATH

    • within a .jar or .zip file, where the directory is specified in the CLASSPATH

  3. Decide on the resolver for your class.

    In this case, you load Hello.class in the server, where it is stored in the database as a Java schema object. When you execute the world() method of the Hello.class on the server, it finds the necessary supporting classes, such as String, using a resolver--in this case, the default resolver. The default resolver looks for classes in the current schema first and then in PUBLIC. All core class libraries, including the java.lang package, are found in PUBLIC. You may need to specify different resolvers, and you can force resolution to occur when you use loadjava, to determine if there are any problems earlier, rather than at runtime. Refer to "Resolving Class Dependencies" or "loadjava" for more details on resolvers and loadjava.

  4. Load the class on the Oracle8i server using loadjava. You must specify the username and password.

    loadjava -user scott/tiger Hello.class
        
    
    
    
  5. Publish the stored procedure through a call specification

    To invoke a Java static method with a SQL CALL, you must publish it with a call specification. A call specification defines for SQL which arguments the method takes and the SQL types it returns.

    In SQL*Plus, connect to the database and define a top-level call specification for Hello.world():

    connect scott/tiger
    create or replace function HELLOWORLD return VARCHAR2 as
       language java name 'Hello.world () return java.lang.String';
        
    
    
    
  6. Invoke the stored procedure

    variable myString varchar2[20];
    call HELLOWORLD() into :myString;
    print myString;
        
    
    
    

    The call HELLOWORLD() into :myString statement performs a top-level call in Oracle8i. The Oracle-specific select HELLOWORLD from DUAL also works. Note that SQL and PL/SQL see no difference between a stored procedure written in Java, PL/SQL, or any other language. The call specification provides a means to tie inter-language calls together in a consistent manner. Call specifications are necessary only for entry points invoked with triggers or SQL and PL/SQL calls. Furthermore, JDeveloper can automate the task of writing call specifications.

    For more information on Java stored procedures, using Java in triggers, call specifications, rights models, and inter-language calls, refer to the Oracle8i Java Stored Procedures Developer's Guide.

Utilizing Distributed Objects With CORBA and EJB

In a program whose logic is distributed, the architecture of choice has three tiers--the client, the middle tier, and the database server.


Client tier  

Typically limited to display of information provided by the middle tier.  

Middle tier  

Facilitates the communication between client and server. Typically manages the server objects. Marshals and unmarshals the parameters and return values.  

Server tier  

Performs the business or application logic.  

The server object within the three-tier model does the business logic. This may or may not include accessing a database for SQL queries. Oracle8i removes the need for a physical middle tier for distributed applications where the server object requires access to a database. Oracle8i still maintains a three-tier logical architecture, but by combining the middle tier and the database server, the physical architecture is two-tier. The flexibility inherent in this architecture is ideally suited to Internet applications where the client presents information in a Web browser, interacting with servers across the network. Those servers, in turn, can be federated and cooperate in their own client-server interactions to provide information to Web-based clients in an intranet or Internet application.

To use the two-tier distributed object approach for your application, you can use either the CORBA or EJB APIs.

CORBA and EJB are complementary. The JServer implementation of the Enterprise JavaBeans 1.0 specification builds on the underlying support and services of CORBA.

IIOP Transport

Unlike a session in which the client communicates through Net8, you access CORBA and EJB sessions through IIOP, which is capable of servicing multiple client connections. Although scalable applications generally provide one session per client-server interaction, the ability to service multiple clients extends the flexibility of the session. IIOP enables callouts, callbacks, and loopbacks in your distributed communications.

Naming

You can access components through a name service, which forms a tree, similar to a file system, where you can store objects by name. When you put a CORBA or EJB object into the namespace, you are publishing it.

There are two supported naming protocols within Oracle8i:

Creating and Deploying Enterprise JavaBeans

CORBA and EJB application development are complicated topics covered in the Oracle8i Enterprise JavaBeans and CORBA Developer's Guide. This section gives an example of how to create an EJB component. This example creates an EmployeeBean to look up an employee record in the Oracle RDBMS.

  1. Create the home interface. The home interface will reside in the server, enabling you to create instances of your EJB on the server. A home interface is a Java interface that extends EJBHome. The home interface is the only object published in the namespace to be visible to clients. The client can access the component through JNDI.

  2. Create the remote interface. The remote interface specifies the methods you implement in the EJB, such as instance methods you can invoke from a client. A remote interface is a Java interface that extends EJBObject. As an interface, you use it to specify the methods implemented in the bean.

  3. Implement the bean class and the methods that the remote interface defines. In the EmployeeBean example, the only method is getEmployee(). You write a bean by creating a class that implements the SessionBean interface.

  4. Create the deployment descriptor. The deployment descriptor specifies attributes of the bean, including its transactional properties and security treatment. You specify the attributes, and the deployejb tool ensures that the server enforces them.

  5. Deploy the EJB. When you deploy the EJB, the deployejb tool does the following:

    • Places your home interface and the EJB on the server.

    • Publishes the home interface in the namespace.

    • Generates the Java code on the server side to manage transactions and security specified in the deployment descriptor.

    • Generates and returns the stub interfaces that provide the client access to the remote functionality of the bean.

Using an EJB

Once you create and deploy an EJB, you will want to use it from a client program. You can use EJBs between servers in n-tier applications also, in which case the client for one server can also be the server for other clients. In your client code, you must perform the following steps:

  1. Locate the home interface object that resides on the server. You will locate the object using Java-standard JNDI lookup facilities.

  2. Authenticate the client to the server. EJB and CORBA clients use database sessions, just as with any other Oracle client. To initiate a session, you must let the server know you are a valid user. You can use several different approaches to accomplish authentication in a secure manner.

  3. Activate an instance of the bean. Because the object you locate with JNDI is the home interface, you will use one of its create() methods to return an activated instance of the EJB.

  4. Invoke methods on the bean. When you invoke a method on the bean, the method is actually executed in the server, and the appropriate parameter and return objects are transparently transported (by copy) across the underlying IIOP connection. All objects the EJBs return must be serializable--they must implement java.io.Serializable.

The Oracle8i Enterprise JavaBeans and CORBA Developer's Guide discusses the details of these steps. Java IDEs, as with Oracle's JDeveloper, can automate and simplify the deployment and descriptor process.

Session Shell

Session shell is an example of a tool written completely in Java using Java stored procedures and CORBA. It interacts with server-resident objects that are visible through CORBA within your session by using UNIX shell commands. For more information, see the Oracle8i Enterprise JavaBeans and CORBA Developer's Guide. This tool demonstrates how you can use CORBA to build tools that make life simpler for developers and end users.

The session shell provides a shell-like interface to the server. This shell allows users to manipulate the session namespace with familiar UNIX commands, such as mkdir, ls, and rm. In addition, the session shell furnishes a convenient way to run Java programs in the server, using the java command. The session shell java command takes the name of a class and any arguments the user types in. The session shell calls the static main(String[]) method on the class, running the Java program in the server. System.out and System.err are captured and transparently redirected back to the user's console.

Utilizing Remote Method Invocation (RMI)

JServer fully supports Java Remote Method Invocation (RMI). All RMI classes and java.net support are in place. In general, RMI is not useful or scalable in JServer applications. CORBA and EJB are the preferred APIs for invoking methods of remote objects. The RMI Server that Sun Microsystem supplies does function on the JServer platform. Because Sun Microsystem's RMI Server uses operating system sockets and is not accessible through a presentation, it is useful only within the context of a single call. It relies heavily on Java language level threads. By contrast, the Oracle8i ORB and EJB rely on the database server to gain scalability. You can efficiently implement an RMI server as a presentation; however, CORBA and EJB currently serves this purpose.


Note:

A presentation is an object that accepts either a Net8 or IIOP incoming connection into the database. See "Configuring JServer" for more information.  


Utilizing Java Native Interface (JNI) Support

The Java Native Interface (JNI) is a standard programming interface for writing Java native methods and embedding the Java virtual machine into native applications. The primary goal of JNI is to provide binary compatibility of Java applications that use platform-specific native libraries.

Oracle does not support the use of JNI in JServer applications. If you use JNI, your application is not 100% pure Java, and the native methods require porting between platforms. Native methods have the potential for crashing the server, violating security, and corrupting data.

Utilizing SQLJ and JDBC for Querying Database

You can use one of two protocols for querying the database from a Java client. Both protocols establish a session with a given username/password to the database and execute SQL queries against the database.

JDBC  

Use this protocol for more complex or dynamic SQL queries. JDBC requires you to establish the session, construct the query, and so on.  

SQLJ  

Use this protocol for static, easy SQL queries. SQLJ is typically a one-liner that executes against a known table with known column names.  

JDBC

JDBC is an industry-standard API developed by Sun Microsystems that allows you to embed SQL statements as Java method arguments. JDBC is based on the X/Open SQL Call Level Interface and complies with the SQL92 Entry Level standard. Each vendor, such as Oracle, creates its JDBC implementation by implementing the interfaces of the Sun Microsystems java.sql package. Oracle offers three JDBC drivers that implement these standard interfaces:

  1. The JDBC Thin driver, a 100% pure Java solution you can use for either client-side applications or applets and requires no Oracle client installation.

  2. The JDBC OCI drivers (OCI 8 or OCI 7), which you use for client-side applications and requires an Oracle client installation.

  3. The server-side JDBC driver embedded in the Oracle8i server.

For the developer, using JDBC is a step-by-step process of creating a statement object of some type for your desired SQL operation, assigning any local variables that you want to bind to the SQL operation, and then executing the operation. This process is sufficient for many applications but becomes cumbersome for any complicated statements. Dynamic SQL operations, where the operations are not known until runtime, require JDBC. In typical applications, however, this represents a minority of the SQL operations.

SQLJ

SQLJ offers an industry-standard way to embed any static SQL operation directly into Java source code in one simple step, without requiring the individual steps of JDBC. Oracle SQLJ complies with ANSI standard X3H2-98-320.

SQLJ consists of a translator--a precompiler that supports standard SQLJ programming syntax--and a runtime component. After creating your SQLJ source code in a .sqlj file, you process it with the translator, which translates your SQLJ source code to standard Java source code, with SQL operations converted to calls to the SQLJ runtime. In the Oracle SQLJ implementation, the translator invokes a Java compiler to compile the Java source. When your Oracle SQLJ application runs, the SQLJ runtime calls JDBC to communicate with the database.

SQLJ also allows you to catch errors in your SQL statements before runtime. JDBC code, being pure Java, is compiled directly. The compiler has no knowledge of SQL, so it is unaware of any SQL errors. By contrast, when you translate SQLJ code, the translator analyzes the embedded SQL statements semantically and syntactically, catching SQL errors during development, instead of allowing an end-user to catch them when running the application.

An Example Comparing JDBC and SQLJ

The following is an example of a simple operation, first in JDBC code and then SQLJ code.

JDBC:

// (Presume you already have a JDBC Connection object conn)
// Define Java variables
String name;
int id=37115;
float salary=20000;

// Set up JDBC prepared statement.
PreparedStatement pstmt = conn.prepareStatement
   ("select ename from emp where empno=? and sal>?");
pstmt.setInt(1, id);
pstmt.setFloat(2, salary);

// Execute query; retrieve name and assign it to Java variable.
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
   name=rs.getString(1);
   System.out.println("Name is: " + name);
}

// Close result set and statement objects.
rs.close()
pstmt.close();

  1. Define the Java variables name, id, and salary.

  2. Define a prepared statement (this presumes you have already established a connection to the database so that you can use the prepareStatement() method of the connection object).

    You can use a prepared statement whenever values within the SQL statement must be dynamically set (you can use the same prepared statement repeatedly with different variable values). The question marks in the prepared statement are placeholders for Java variables and are given values in the pstmt.setInt() and pstmt.setFloat() lines of code. The first "?" is set to the int variable id (with a value of 37115). The second "?" is set to the float variable salary (with a value of 20000).

  3. Execute the query and return the data into a JDBC result set object. (You can use result sets to gather query data.)

  4. Retrieve the data of interest (the name) from the result set and print it. A result set usually contains multiple rows of data, although this example has only one row.

By comparison, here is some SQLJ code that performs the same task. Note that all SQLJ statements, both declarations and executable statements, start with the #sql token.

SQLJ:

String name;
int id=37115;
float salary=20000;
#sql {select ename into :name from emp where empno=:id and sal>:salary);
System.out.println("Name is: " + name);

SQLJ, in addition to allowing SQL statements to be directly embedded in Java code, supports Java host expressions (also known as bind expressions) to be used directly in the SQL statements. In the simplest case, a host expression is a simple variable as in this example, but more complex expressions are allowed as well. Each host expression is preceded by ":" (colon). This example uses Java host expressions name, id, and salary. In SQLJ, because of its host expression support, you do not need a result set or equivalent when you are returning only a single row of data.

Complete SQLJ Example

This section presents a complete example of a simple SQLJ program:

import java.sql.*;
import sqlj.runtime.ref.DefaultContext;
import oracle.sqlj.runtime.Oracle;
#sql iterator MyIter (String ename, int empno, float sal);

public class MyExample 
{
   public static void main (String args[]) throws SQLException 
   {
      Oracle.connect
         ("jdbc:oracle:thin:@oow11:5521:sol2", "scott", "tiger");

      #sql { insert into emp (ename, empno, sal)
         values ('SALMAN', 32, 20000) };
      MyIter iter;

      #sql iter={ select ename, empno, sal from emp };
      while (iter.next()) {
         System.out.println
            (iter.ename()+" "+iter.empno()+" "+iter.sal());
      }
   }
}

  1. Declare your iterators. SQLJ uses a strongly typed version of JDBC result sets, known as iterators. The main difference between the two is that an iterator has a specific number of columns of specific datatypes. You must define your iterator types beforehand, as in this example:

    #sql iterator MyIter (String ename, int empno, float sal);
        
    
    
    

    This declaration results in SQLJ creating an iterator class MyIter. Iterators of type MyIter can store results whose first column maps to a Java String, whose second column maps to a Java int, and whose third column maps to a Java float. This definition also names the three columns--ename, empno, and sal, respectively--to match the table column names in the database. MyIter is a named iterator. See Chapter 3 of the Oracle8i SQLJ Developer's Guide and Reference to learn about positional iterators, which do not require column names.

  2. Connect to the database.

    Oracle.connect("jdbc:oracle:thin:@oow11:5521:sol2","scott", "tiger");
        
    
    
    

    Oracle SQLJ furnishes the Oracle class, and its connect() method accomplishes three important things:

    1. Registers the Oracle JDBC drivers SQLJ uses to access the database.

    2. Opens a database connection for the specified schema (user scott, password tiger) at the specified URL (host oow11, port 5521, SID so12, "thin" JDBC driver).

    3. Establishes this connection as the default connection for your SQLJ statements. Although each JDBC statement must explicitly specify a connection object, a SQLJ statement can either implicitly use a default connection or optionally specify a different connection.

  3. Execute a SQL statement.

    1. Insert a row into the emp table:

      #sql {insert into emp (ename, empno, sal) values ('SALMAN', 32, 20000)};
          
      
      
      
    2. Instantiate and populate the iterator:

      MyIter iter;
      #sql iter={select ename, empno, sal from emp};
          
      
      
      
  4. Access the data that was populated within the iterator.

    while (iter.next()){
       System.out.println(iter.ename()+" "+iter.empno()+" "+iter.sal());
    }
        
    
    
    

    The next() method is common to all iterators and plays the same role as the next() method of a JDBC result set, returning true and moving to the next row of data if any rows remain. You access the data in each row by calling iterator accessor methods whose names match the column names (this is a characteristic of all named iterators). In this example, you access the data using the methods ename(), empno(), and sal().

SQLJ Strong Typing Paradigm

SQLJ uses strong typing--such as iterators--instead of result sets, which allows your SQL instructions to be checked against the database during translation. For example, SQLJ can connect to a database and check your iterators against the database tables that will be queried. The translator will verify that they match, allowing you to catch SQL errors during translation that would otherwise not be caught until a user runs your application. Furthermore, if changes are subsequently made to the schema, you can determine if this affects the application simply by re-running the translator.

Translating a SQLJ Program

Integrated development environments such as Oracle JDeveloper, a Windows-based visual development environment for Java programming, can translate, compile, and customize your SQLJ program for you as you build it. If you are not using an IDE, then you can use the front-end SQLJ utility, sqlj. You can run it as follows:

%sqlj MyExample.sqlj

The SQLJ translator checks the syntax and semantics of your SQL operations. You can enable online checking to check your operations against the database. If you choose to do this, you must specify an example database schema in your translator option settings. It is not necessary for the schema to have identical data to the one the program will eventually run against; however, the tables should have columns with corresponding names and datatypes. Use the user option to enable online checking and specify the username, password, and URL of your schema, as in the following example:

%sqlj -user=scott/tiger@jdbc:oracle:thin:@oow11:5521:sol2 MyExample.sqlj

Running a SQLJ Program in the Server

Many SQLJ applications run on a client; however, SQLJ offers an advantage in programming stored procedures--which are usually SQL-intensive--to run in the server.

There is almost no difference between coding for a client-side SQLJ program and a server-side SQLJ program. The SQLJ runtime packages are automatically available on the server, and there are just the following few considerations:

To run a SQLJ program in the server, presuming you developed the code on a client, you have two options:

In either case, you can use the Oracle loadjava utility to load the file or files to the server. See the Oracle8i SQLJ Developer's Guide and Reference for more information.

Converting a Client Application to Run in the Server

The steps in converting an existing SQLJ client-side application to run in the server are as follows. Assume this is an application that has already been translated on the client:

  1. Create a .jar file for your application components.

  2. Use the loadjava utility to load the .jar file to the server.

  3. Create a SQL wrapper in the server for your application. For example, to run the preceding MyExample application in the server:

    create or replace procedure SQLJ_MYEXAMPLE as language java
        
    
          name `MyExample.main(java.lang.String[])';
    
    

You can then execute SQLJ_MYEXAMPLE as with any other stored procedure.

Interacting with PL/SQL

All the Oracle JDBC drivers communicate seamlessly with Oracle SQL and PL/SQL, and it is important to note that SQLJ interoperates with PL/SQL. You can start using SQLJ without having to rewrite any PL/SQL stored procedures. Oracle SQLJ includes syntax for calling PL/SQL stored procedures and also allows PL/SQL anonymous blocks to be embedded in SQLJ executable statements, just as with SQL operations.

Debugging Server Applications

JServer furnishes a debugging capability useful for developers who use Oracle's JDeveloper or the JDK's jdb debugger. Other independent IDE vendors will be able to integrate their own debuggers with JServer.


Note:

You must have the debug permission granted to your user to run a debug agent. See "Debugging Permissions" for more information.  


The Aurora JVM includes an implementation of the sun.tools.debug.Agent Java debugging protocol. Vendors may implement extensions to this protocol. All Oracle-specific extensions in the JServer environment will be publicly specified for use by all vendors.


Note:

JDeveloper has provided a user interface that utilizes JServer's debugging facilities. You can successfully debug an object loaded into the database by using JDeveloper's debugger.  


Overview

In a single-tier environment, you debug a Java application on your own system. Sun Microsystem's jdb debugger communicates with the locally executing JVM through a protocol, which enables you to display information about the state of the Java program. In JServer, your Java program executes remotely on a server. The server can reside on the same physical machine, but it typically resides on a separate machine. The jdb debugger cannot debug a remote Java application while executing on Sun Microsystem's JDK. Oracle8i provides a method for debugging Java applications that exist on your remote database.

The DebugProxy class makes your remote Java application appear to be local. The DebugProxy enables a standard debugger that supports the sun.tools.debug.Agent protocol to connect to it as if the program is local. The proxy forwards the standard requests to the server and returns the results to the debugger.


The steps for debugging are, using jdb as the example:

  1. Start the DebugProxy. The DebugProxy waits for a DebugAgent that executes in the server.

  2. Start the DebugAgent. Once you connect to the server (starting a session), you can start the DebugAgent on the server.

    There is no way to cause server-resident code to execute and break, that is, execute and remain indefinitely in a halted mode. Instead, when you start the DebugAgent, you must specify a timeout period for the DebugAgent to wait before terminating. When the DebugAgent starts, the DebugProxy displays a password to use when connecting the debugger.

  3. Connect a debugger. Start jdb using the password provided by the DebugProxy when the DebugAgent connected to it. Use jdb to suspend all threads of the Java program executing in the server. Proceed with debugging using jdb facilities.

1. Start the Debug Proxy

The debug proxy is located in the aurora_client.jar file, which is located in $ORACLE_HOME/lib. The DebugProxy class serves as a bridge between Aurora JVMs running in the Oracle8i server and client-side debuggers running on your system.

A debug proxy waits for connections from the debug agent. Assuming the aurora_client.jar file is part of your CLASSPATH, you start the DebugProxy as follows:

debugproxy 

You can also specify a particular port to wait on.

debugproxy -port 2286

The proxy prints out its name, its address, and the port it is waiting on.

Proxy Name: yourmachinename
Proxy Address: aaa.bbb.ccc.ddd
Proxy Port: 2286

Just-in-Time Debugging

Aurora takes any arguments to DebugProxy, beyond the optional port, as a command to execute. The agent port password is appended to the command. For instance, on Windows NT, you cause the proxy to execute jdb in a new console each time an agent connects to the proxy, by issuing the following command:

debugproxy -port 2286 start jdb -password

2. Starting, Stopping, and Restarting the Debug Agent


Note:

To invoke the debug agent, the caller must have JAVADEBUGPRIV permission. For more information, see "Debugging Permissions".  


Once a proxy is running, you can start a debug agent to connect to the proxy from SQL*Plus. You must specify the IP address or URL for a machine running a debug proxy, the port the proxy is waiting on, and a timeout in seconds. You start and stop the debug agent using methods specified within the DBMS_JAVA package.

SQL> call dbms_java.start_debugging('yourmachinename', 2286, 66);

The call waits until the timeout expires or until the main thread is suspended and resumed before it completes. Calculate a timeout that includes enough time for your debugger to start up, but not so much as to delay your session if you cannot connect a debugger.


Note:

If an agent is already running, Aurora stops it and starts a new agent. You can stop the debug agent explicitly through the stop_debugging method.  


SQL> call dbms_java.stop_debugging(); 

Once a debug agent starts, it runs until you stop it, the debugger disconnects, or the session ends.

You can restart a stopped agent with any breakpoints still set with the restart_debugging method. The call waits until the timeout expires before it completes. You can also restart a running agent just to buy some seconds to suspend threads and set breakpoints.

SQL> call dbms_java.restart_debugging(66); 

OracleAgent Class

The DBMS_JAVA debug agent and proxy calls are published entry points to static methods that reside in oracle.aurora.debug.OracleAgent class. You can start, stop, and restart the debug agent in Java code using the class oracle.aurora.debug.OracleAgent directly through the following methods:

public static void start(String host, int port, long timeout_seconds);
public static void stop();
public static void restart(long timeout_seconds);

3. Connecting a Debugger

Each time a debug agent connects to a proxy, the proxy starts a thread to wait for connections from a debugger. The thread prints out the number, name and address of the connecting agent, the port it is waiting on, and the port encoded as a password. Here, a specific port and password are provided for illustration only:

Agent Number: 1
Agent Name: servername
Agent Address: eee.fff.jjj.kkk
Agent Port: 2286
Agent Password: 3i65bn

You can then pass the password to a jdb-compatible debugger (JDK 1.1.6 or later):

jdb -password 3i65bn

The first thing you should do in the debugger is suspend all threads. Otherwise, your start_debugging call might time out and complete before you get your breakpoints set.

If your code writes to System.out or System.err, then you may also want to use the dbgtrace flag to jdb, which redirects these streams to the debugging console:

jdb -dbgtrace -password 3i65bn

How To Tell You Are Executing in the Server

You might want to write Java code that executes in a certain way in the server and another way on the client. In general, Oracle does not recommend this. In fact, JDBC and SQLJ go to some trouble to enable you to write portable code that avoids this problem, even though the drivers used in the server and client are different.

If you must determine whether your code is executing in the server, use the System.getProperty method, as follows:

System.getProperty ("oracle.jserver.version")

The getProperty method returns the following:

Redirecting Output on the Server

System.out and System.err print to the current trace files. To redirect output to the SQL*Plus text buffer, use this workaround:

SQL> SET SERVEROUTPUT ON
SQL> CALL dbms_java.set_output(2000);

The minimum (and default) buffer size is 2,000 bytes; the maximum size is 1,000,000 bytes. In the following example, the buffer size is increased to 5,000 bytes:

SQL> SET SERVEROUTPUT ON SIZE 5000
SQL> CALL dbms_java.set_output(5000);

Output prints at the end of the call.

For more information about SQL*Plus, see the SQL*Plus User's Guide and Reference.




Prev

Next
Oracle
Copyright © 1999 Oracle Corporation.

All Rights Reserved.

Library

Product

Contents

Index