Runtime Behavior

Before you move on to server configuration, it's important to understand certain key elements of the server architecture and runtime behavior. In this section, we'll discuss the basic server architecture, classloading schemes, ports, protocols, memory usage, and compilers.

Server Architecture

OC4J Standalone provides a complete J2EE 1.3-compliant environment for J2EE applications. This means that it supports web applications, EJBs, Java Naming and Directory Interface (JNDI) and all of the other standard J2EE technologies we discussed in Chapter 1. However, it doesn't include value-added features such as Single Sign-On or Personalization.

Figure 3-5 gives a quick visual overview of OC4J's general architecture, which is very similar to that of most other J2EE servers. Don't worry if you haven't used all of these technologieseach will be discussed in a lot more detail in later chapters.

image from book
Figure 3-5: Server architecture

In particular, make note of the following:

  • Multiple HTTP listeners can be configured to accept requests from web clients on various ports, thereby directing them to individual web applications according to context mappings. Each website can define one default web application to be mapped to the root context.

  • RMI and RMI-IIOP ports can be defined to allow Java and CORBA clients to access JNDI, EJBs, and other resources.

  • JMS servers can be configured with individual ports and JMS destinations.

  • J2EE applications can contain web applications, EJB modules, Connectors, and application clients, and are deployed in a hierarchy, with child applications able to access the resources of their parents. Any application with no defined parent becomes a child of the global application. Web modules also inherit settings from the default web application configuration.

  • DataSources, Connectors, and two-phase commit coordinators can be configured both at the global level and by individual J2EE applications.

  • A default XML-based JAAS Provider is available to manage user , group , and role-based security, but can be replaced by a custom implementation.

Classloading

Many J2EE developers agree that classloading errors can be among the most difficult to understand and fix, especially when running within an application server. Due to ambiguities in the J2EE specification, some server vendors have designed incompatible classloading architectures that can make it difficult to migrate an application without code changes. The following section looks at OC4J's classloading scheme and how to avoid potential pitfalls.

Review of Java Classloading

Every class used in a Java application must be initially loaded using a classloader . This class-loader may load the byte code from a file, the network, a parent classloader, or one of many other possible sources. With the exception of the bootstrap classloader (which is responsible for loading the ClassLoader class itself), these classloaders are all Java objects that can be instantiated and arranged in a hierarchy with the following properties:

  • A child classloader can see classes loaded by its parent.

  • When it receives a request to load a class, a child classloader will delegate to its parent first, and only load the class itself if its parent is unable to.

  • Classes loaded by two different classloaders aren't compatible.

  • Once loaded, a class can never be unloaded. However, the classloader can be destroyed and a different classloader can be used to load a new copy of the class.

Many Java applications have no need for multiple classloaders, and get by with the most basic configurationa bootstrap classloader to load the very first classes (before the ClassLoader class exists), an extension classloader to load any Java extensions, and a system classloader to load all of the classes required by the application, as shown in Figure 3-6.

image from book
Figure 3-6: Standard J2SE classloader hierarchy

In this scenario, when a class needs to change, you just replace its class file and restart the JVM.

J2EE Classloading

When moving to an enterprise environment, you'll probably start to see a few problems with this default classloading scheme.

First, you would like your application server to be able to manage several individual applications within a single JVM. However, if all classes are loaded through the system class-loader, then every application will be able to see and use any class loaded by any other applicationnot a very secure setup! Trying to manage this entirely through security policies would be tedious and prone to errors, particularly when two applications depended on a single library, or worse yet, two different versions of that library.

Furthermore, with just one classloader, changes to any application require you to restart all of them. This kind of frequent downtime is rarely acceptable.

Thus, instead of depending on the system classloader, it looks like you'll need at least one per application, and possibly one for the server itself so that it can keep its own internal classes hidden from the applications it runs. This will keep each application independent of all the others, and allow you to easily reload it by destroying and re-creating its classloader, as shown in Figure 3-7.

image from book
Figure 3-7: Typical J2EE classloading hierarchy

In practice, since these applications are component based, J2EE vendors go one step further and create multiple classloaders for each J2EE application, giving you even more flexibility (and complexity).

OC4J Classloading

Although the preceding scheme divides components into independent, reloadable pieces, it introduces a new problem. If individual modules have their own classloaders, how do you share classes between them? Declaring dependencies in manifest files works fine for modules within the same J2EE 1.2 application since all shared objects pass through serialization. However, with EJB 2.0, objects can be passed directly from one module to another through local interfaces. Unless the two modules can somehow share a classloader, we'll end up with a ClassCastException on the other side.

To solve this problem, as shown in Figure 3-8, OC4J and other servers chain the class-loaders within an application, creating one Connectors classloader, which is parent to an EJB classloader, which in turn is parent to any web application classloaders.

image from book
Figure 3-8: Classloading within a J2EE application

Of course, this still doesn't help us share code between applications, so OC4J has added a number of additional proprietary extensions, as shown in Figure 3-9.

image from book
Figure 3-9: Full OC4J classloader example

First, there's a global Connectors classloader that loads any Connectors to which all applications should have access (as configured at the server level). Similarly, a global application serves as the parent to all other applications, loading any libraries that should be available to all. See Chapter 9 for more about configuring global applications.

Besides these global classloaders, OC4J also allows any application to specify another application as its parent. In the previous example, both Application C and Application D share a parent Application B. Any EJBs or libraries made available within B will be visible to both C and D. See Chapter 9 for more about configuring parent applications.

Tip 

The J2EE specification recommends (but doesn't require) that web application classloaders load classes from within the WAR before looking to their parent classloaders. This behavior can be enabled in OC4J (9.0.4) within the orion-web .xml descriptor, as described in Chapter 10. This might be desirable, for example, if the web application and EJBs both need to use a library that loads application classes dynamically. Without this option, the classes would only be loaded at the EJB level, and would get ClassNotFound exceptions when trying to load and use web application classes on the fly).

Troubleshooting

All of this complexity can give rise to a number of classloading headaches during development. The following sections describe some troubleshooting tips for three of the most common.

ClassNotFoundException

This exception occurs anytime you're trying to explicitly load a class that cannot be found, for example, with a Class.forName("someClass") . Check whether a shared library loaded by a top-level classloader is trying to dynamically load a class only available at a lower level.

Whenever you have to specify class names in a configuration file, it's a good clue that the code that requires that configuration file will be dynamically instantiating those classes. So make sure that both that code and the classes you listed are being loaded by the same class-loader.

For example, if the Struts web framework has been placed anywhere higher than the web application level, it will be unable to load the web application classes you reference in your Struts configuration file.

NoClassDefFoundException

This exception occurs when a class depends on another class that cannot be found. Check that no dependencies have been missed, or split across classloading levels. This usually happens when you've compiled a bunch of classes together, but didn't deploy all of the class files, or put some of them in a separate JAR at a lower level. You can prevent this from occurring in the future by packaging all dependent classes in the same JAR. If you must split them up, declare any dependencies on other libraries in each JAR's manifest file, like this:

META-INF/MANIFEST.MF File Placed Inside JAR to Declare Dependencies

 Manifest-Version: 1.0 Class-Path: format.jar dataaccess.jar drivers/oracle.jar 

For example, if classes in CurrencyUtils.jar depend on and were compiled against classes in NumberUtils.jar , but you don't include NumberUtils.jar in your application or system classpath, then you'll see this error. This will also happen if CurrencyUtils.jar is placed on the system classpath, but NumberUtils.jar is only included down in your application. You can usually solve this problem by adding an entry to the manifest file inside CurrencyUtils.jar to indicate that it depends on NumberUtils.jar (available at some relative path). Other options are to repackage all of those classes into one JAR, or to move CurrencyUtils.jar down to the same level as NumberUtils.jar .

Tip 

For more information about manifest files, see Sun's Java tutorial online at http://java.sun.com/docs/books/tutorial/jar/basics/manifest.html .

ClassCastException

This exception occurs when some code has attempted to cast an object of one class to another incompatible class. If no obvious problems are found, it may be that the same class was loaded by two classloaders. In particular, if a web application has been configured to load classes from its lib directory before going up the classloader hierarchy (see Chapter 10), then be sure that it doesn't try to use these classes to interact with EJBs that load their own versions of those classes. Also, be careful about passing objects between two different applications through static variables or Singleton classes. If each application loads its own version of the shared classes, they will be incompatible.

For example, suppose you have two web applications that both depend on a Singleton class called CacheManager , which keeps a static HashMap of request keys and content. You place a JAR with this CacheManager implementation at the top level. At runtime, your first application calls into CacheManager to store a Java bean so that it can be used by future requests of the same type. Later, your second application retrieves that object from the CacheManager and tries to cast it to its bean type. Unless that bean implementation class was loaded by a shared classloader (such as the system classloader), the second application will get a ClassCastException error when trying to cast it, even if both applications include the implementation class. Fortunately, this can usually be fixed by not using static variables (which are unsafe across clusters anyway), thereby ensuring that shared classes are only loaded once by a shared class-loader. If you must share content, make sure it's serialized and deserialized along the way.

Tip 

Every time an application is reloaded (that is, "hot deployed"), it gets a new classloader. This means that objects stored by an application in a system-level Singleton may be unrecognizable to a newly deployed version of the same application. Avoid this by using a more traditional form of persistence (database, file, and so on) or by using classes or interfaces loaded at the same level as the Singleton, so that they won't be affected by the reload.

For more information about classloading in OC4J, see the "Classloading in Oracle9 i AS Containers for J2EE" white paper at http://otn.oracle.com/tech/java/oc4j/pdf/ClassLoadingInOC4J_WP.pdf .

Ports and Protocols

The OC4J Standalone server uses a number of configurable ports. These might need to be changed, for example, to run multiple OC4J servers on the same machine. You might also want to allow network access to these ports through a firewall.

Table 3-4: OC4J Default Network Ports

Protocol

Default Port

Configuration File

HTTP

8888

http-web-site.xml (and other *-web-site.xml files)

HTTPS

None

http-web-site.xml (and other *-web-site.xml files)

IIOP

5555

internal-settings.xml

IIOP over SSL

5556

internal-settings.xml

JMS

9127

jms.xml

RMI

23791

rmi.xml

Though these ports are also used in a full Oracle Application Server 10g instance, many of the defaults are different. Furthermore, when using the Oracle HTTP Server, most web traffic will come in through a dedicated port for communications between the web server and OC4J, rather than hitting OC4J's HTTP listeners directly. See Chapter 16 for more information about the ports used in a full Oracle Application Server 10g installation.

Performance and Memory Usage

Though most performance tuning is usually saved for the production environment in which you're running a full Oracle Application Server 10g installation, it's usually worthwhile to tweak JVM parameters in a development environment to improve speed and stability.

In many cases, the easiest way to get a quick performance boost is to increase the size of the heap. This ends up decreasing the frequency of garbage collection and reducing your applications' susceptibility to OutOfMemory errors. (Of course, if these errors are frequent, it may be a sign of memory leaks within those applications.)

You can alter the heap size using the JVM options -Xms and -Xmx . For example, the following command sets the initial heap size to 128 MB and the maximum heap size to 512 MB:

 java -Xms128m -Xmx512m -jar oc4j.jar 

Whenever possible, the maximum should be set to at least 256 MB. However, it should never be set higher than the machine's available memory. If the system isn't heavily taxed, you may also want to raise the initial heap size so that the JVM doesn't need to pause to increase its size in the middle of a request. In production, once your applications are stable and predictable, it's common to set the minimum equal to the maximum so that the JVM starts with all the memory it will ever need.

On UNIX systems, it may also be helpful to set the -server option. Although this increases startup time and memory requirements, it delivers greater performance in the long run. Usually, this means that it's not a great option for developer servers because they're frequently restarted, but it can often be useful for long-running system tests and QA servers. This is the default when OC4J is run within a full Oracle Application Server 10g instance on UNIX.

For more tips about tuning OC4J for performance, see the "Oracle Application Server 10 g Performance Guide" available at http://download-uk.oracle.com/docs/cd/B10464_02/ core .904/b10379/toc.htm .

Compilers

Whenever an EJB is deployed or a JSP is invoked, the server needs to create and compile one or more Java classes. By default, OC4J uses Sun's Java compiler, but launches a separate process for every compilation task. It may improve performance to run the compiler in process or to specify a higher-performance third-party compiler such as Jikes. See Chapter 4 for more details about these compiler configuration options.



Oracle Application Server 10g. J2EE Deployment and Administration
Oracle Application Server 10g: J2EE Deployment and Administration
ISBN: 1590592352
EAN: 2147483647
Year: 2004
Pages: 150

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net