Sunday, September 30, 2007

PHP learning--Part 5

Variables


+ Variable names follow the same rules as other labels in PHP. A valid variable name starts with a letter or underscore, followed by any number of letters, numbers, or underscores. As a regular expression, it would be expressed thus: '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'

Note: For our purposes here, a letter is a-z, A-Z, and the ASCII characters from 127 through 255 (0x7f-0xff).

Varible assignment
+ Assigned by value:  That is to say, when you assign an expression to a variable, the entire value of the original expression is copied into the destination variable. This means, for instance, that after assigning one variable's value to another, changing one of those variables will have no effect on the other
+ Assigned by reference: This means that the new variable simply references (in other words, "becomes an alias for" or "points to") the original variable.Changes to the new variable affect the original, and vice versa.

To assign by reference, simply prepend an ampersand (&) to the beginning of the variable which is being assigned (the source variable)
Example:

$bar = &$foo;

Note:

PHP.Net: Relying on the default value of an uninitialized variable is problematic in the case of including one file into another which uses the same variable name. It is also a major security risk with register_globals turned on. E_NOTICE level error is issued in case of working with uninitialized variables, however not in the case of appending elements to the uninitialized array. isset() language construct can be used to detect if a variable has been already initialized.

Comment: The good behaviour is always initialize a varible before using it. It is always recommended on every programming language not only for PHP.

Variable scope

The scope of a variable is the context within which it is defined. For the most part all PHP variables only have a single scope. This single scope spans included and required files as well.

Example:

<?php
$a
= 1;
include
'b.inc';
?>

Varible $a will be available within the included b.inc script.

+ Any variable used inside a function is by default limited to the local function scope. For example:

<?php
$a
= 1; /* global scope */

function Test()
{
    echo
$a; /* reference to local scope variable */
}

Test();
?>

This script will not produce any output because the echo statement refers to a local version of the $a variable, and it has not been assigned a value within this scope


To used a global variable in the function we used the global keyword

Example:

<?php
$a
= 1;
$b = 2;

function
Sum()
{
    global
$a, $b;

   
$b = $a + $b;
}

Sum();
echo
$b;
?>

Variable a, b in function is declared as global variable, all the references to either variable will refer to the global function.

The second way to access varibles from global scope is to use the special PHP-defined $GLOBALS Array. This $GLOBALS variable is the superglobal and can be used in any scope.

Static variable:
The static varible is available in local function scope but it is does notlose its value when program excution leaves this scope. Consider the following example:

<?php
function Test()
{
    static
$a = 0; //just for defined static variable.
    echo
$a;
   
$a++;
}
?>

When we call Test the first times, it output: 0.
The second times, it output 1;

References with global and static variables

This can lead to unexpected behaviour which the following example addresses. So do not use it.

Next part will be in next day.
I want thank to php.net with the manual. This part what i learn from their manual.

Saturday, September 29, 2007

PHP learning--part 4

PHP Types:

About the primitive types, PHP has 4 primitive type:
+ boolean
+ integer
+ float
+ string

Two compound types:
+ array
An array in PHP is actually an ordered map. A map is a type that maps values to keys. This type is optimized in several ways, so you can use it as a real array, or a list (vector), hashtable (which is an implementation of a map), dictionary, collection, stack, queue and probably more. Because you can have another PHP array as a value, you can also quite easily simulate trees.
Note: It is so powerful, but complex, not easy to understand.

Example1: 1-dimension array ( or map)
<?php
$arr
= array("foo" => "bar", 12 => true);
echo
$arr["foo"]; // bar
echo $arr[12]; // 1
?>

Example 2: 2 dimension array

<?php
$arr
= array("somearray" => array(6 => 5, 13 => 9, "a" => 42));
echo
$arr["somearray"][6]; // 5
echo $arr["somearray"][13]; // 9
echo $arr["somearray"]["a"]; // 42
?>

Array do's and don'ts

Why is $foo[bar] wrong?

If there are no constant define bar, PHP will automatically change bar into 'bar' and use that.
You will mismatch value define.


error_reporting
(E_ALL);
ini_set('display_errors', true);
ini_set('html_errors', false);
// Simple array:
$array = array(1, 2);
$count = count($array);
for (
$i = 0; $i < $count; $i++) {
echo
"\nChecking $i: \n";
echo
"Bad: " . $array['$i'] . "\n";
echo
"Good: " . $array[$i] . "\n";
echo
"Bad: {$array['$i']}\n";
echo
"Good: {$array[$i]}\n";
}
?>

The above example will output:

Checking 0:  Notice: Undefined index:  $i in /path/to/script.html on line 9 Bad:  Good: 1 Notice: Undefined index:  $i in /path/to/script.html on line 11 Bad:  Good: 1  Checking 1:  Notice: Undefined index:  $i in /path/to/script.html on line 9 Bad:  Good: 2 Notice: Undefined index:  $i in /path/to/script.html on line 11 Bad:  Good: 2 So array is flexible, but using it carefully.

+ Object

Object Initialization
<?php
class foo
{
function
do_foo()
{
echo
"Doing foo.";
}
}

$bar = new foo;
$bar->do_foo();
?>

Converting to object:

Rule: If an object is converted to an object, it is not modified. If a value of any other type is converted to an object, a new instance of the stdClass built in class is created. If the value was NULL, the new instance will be empty. Array converts to an object with properties named by array keys and with corresponding values. For any other value, a member variable named scalar will contain the value.

Example:

Convert string to object.

<?php
$obj
= (object) 'ciao';
echo
$obj->scalar; // outputs 'ciao'
?>

Resource

A resource is a special variable, holding a reference to an external resource. Resources are created and used by special functions


Converting to resource

As resource types hold special handlers to opened files, database connections, image canvas areas and the like, you cannot convert any value to a resource.

NULL

The special NULL value represents that a variable has no value

The type of a variable is usually not set by the programmer; rather, it is decided at runtime by PHP depending on the context in which that variable is used.-->Varible type in PHP equal type variant in many other programming language.

That's all. We will go to detail in next day.

Sunday, September 23, 2007

PHP learning--part 3

PHP syntax:



PHP code have to be put in
<?php code ?>
Example:
<?php echo 'While this is going to be parsed.'; ?>


There are 2 layer when parse a php file. First the PHP file compile with PHP parser. The output is HTML. Then the HTML output will be parse by HTML parser and then output into browser client. It is complex process behind.

When PHP parses a file, it looks for opening and closing tags, which tell PHP to start and stop interpreting the code between them. Parsing in this manner allows php to be embedded in all sorts of different documents, as everything outside of a pair of opening and closing tags is ignored by the PHP parser. Most of the time you will see php embedded in HTML documents, as in this example.

<?php
if ($expression) {
   
?>
    <strong>This is true.</strong>
    <?php
} else {
   
?>
    <strong>This is false.</strong>
    <?php
}
?>

How this work?

I will explain:
First, when PHP parser meet first open tag <?php, it will start compile php code until it meet
close tag ?>. So the statment if ($expression) { will be put into parser. But the if statement is not completed. So it will wait until the if structure complete and output. Because the
$expression is default false, so the block: <strong>This is true.</strong> will be ignore. The compiler is enough intelligent to do this. When it meet else part, it will ouput <strong>This is false.</strong> to html parser. Then html parser will do its job: output to client browser.
Hope it is clear.

There are four different pairs of opening and closing tags which can be used in php. Two of those, <?php ?> and <script language="php"> </script>, are always available. The other two are short tags and ASP style tags, and can be turned on and off from the php.ini configuration file. As such, while some people find short tags and ASP style tags convenient, they are less portable, and generally not recommended.

Note: Also note that if you are embedding PHP within XML or XHTML you will need to use the <?php ?> tags to remain compliant with standards.

All types of php opening and closing tags:

1. <?php echo 'if you want to serve XHTML or XML documents, do like this'; ?>

2.  <script language="php">
       
echo 'some editors (like FrontPage) don\'t
              like processing instructions'
;
   
</script>

3.  <? echo 'this is the simplest, an SGML processing instruction'; ?>
    <?= expression ?> This is a shortcut for "<? echo expression ?>"

4.  <% echo 'You may optionally use ASP-style tags'; %>
    <%= $variable; # This is a shortcut for "<% echo . . ." %>

PHP learning -- Part 2

The second things i want to know: which do we need to develop a PHP program?

1. Web server: Apache(recommend) or IIS(not recommend)
2. DBMS such as Mysql(recommend) or others
3. PHP engine (Of course). Download at php.net

But i recommend on WAMP. It wrapped all module in one. It is easier for you to develop.


After install WAMP at port 80, i want to run the first hello world to have a look at PHP.

Although now we do not understand what its mean, it will give us an overview.

First hello world program written in PHP.

File: hello.php


<html>
<head>
<title>PHP Test</title>
</head>
<body>
<?php echo '<p>Hello World</p>'; ?>
</body>
</html>

To make in run, we start wamp server. Put this file into sub folder www in wamp folder.
Open browser, and enter URL: localhost/hello.php

The example will appear:
Hello World


Cool. We did a very simple program. Now we start look inside PHP in next post

PHP Learning--Part 1

Today, i learn PHP language. I know a lot about C/C++, Delphi, Java but nothing about web programming(such as PHP). So now i will self-study PHP. I know it is difficult when you are starting learning new language. But when you have base knowledge. It will be easier.
First glance at PHP:

PHP, which stands for "PHP: Hypertext Preprocessor" is a widely-used Open Source general-purpose scripting language that is especially suited for Web development and can be embedded into HTML. Its syntax draws upon C, Java, and Perl, and is easy to learn. The main goal of the language is to allow web developers to write dynamically generated web pages quickly, but you can do much more with PHP.

That is definition in PHP.net. But in my opinion, in short way, PHP just a server side script run in server side. That's all.

Now i want to know the key feature of PHP. Let's start by study:
1. Server-side scripting:

This is the most traditional and main target field for PHP. You need three things to make this work. The PHP parser (CGI or server module), a web server and a web browser. You need to run the web server, with a connected PHP installation. You can access the PHP program output with a web browser, viewing the PHP page through the server. All these can run on your home machine if you are just experimenting with PHP programming

2.Command line scripting:

You can make a PHP script to run it without any server or browser. You only need the PHP parser to use it this way. This type of usage is ideal for scripts regularly executed using cron (on *nix or Linux) or Task Scheduler (on Windows). These scripts can also be used for simple text processing tasks
Note: It is like batch processing or Shell Programming. Good for system task such as make server log, backup....

3.Writing desktop applications. PHP is probably not the very best language to create a desktop application with a graphical user interface, but if you know PHP very well, and would like to use some advanced PHP features in your client-side applications you can also use PHP-GTK to write such programs. You also have the ability to write cross-platform applications this way. PHP-GTK is an extension to PHP, not available in the main distribution. If you are interested in PHP-GTK, visit http://gtk.php.net/.
Note: So cool. I do not know about this. Maybe i tried. ^_^ I only know that PHP is for Web development.

4. Database support:
Adabas D InterBase PostgreSQL
dBase FrontBase SQLite
Empress mSQL Solid
FilePro (read-only) Direct MS-SQL Sybase
Hyperwave MySQL Velocis
IBM DB2 ODBC Unix dbm
Informix Oracle (OCI7 and OCI8)
Ingres Ovrimos

We only need some key database server like MySQL, Oracle, Innobase, DB2, SQL Server(not see in the list. I will find the way to work around.).

Friday, September 21, 2007

The taming of the thread

A process-driven approach to avoid thread death

Threads can be nasty beasts. This is partly attributed to their delicate nature. Threads can die. If the causes of thread death are not in your code, then MutableThread may keep your code running. This article explores a solution using an object-oriented, problem-solution method.

The problem

The first question to ask in the problem-solution method is, of course: What is the problem? The problem statement is easy to generate in existing systems since the problem generally causes the trouble. In this case, the problem is: The threads die, and the application stops running. No exception is thrown since the cause of thread death is external to the application.
The what and the how

It is extremely important to isolate the objective from the technical aspects of a possible solution. If design concerns influence the requirements early on, creative solutions might be prevented. It is a designer's nature to think about how to do everything and therefore his temptation to avoid challenges that might result in a superior solution by declaring them problematic, too ambitious, or even impossible.

The it-would-be-wonderful-if statement is a liberating way to imagine an ideal world. It produces the ideal what without regard to design limitations.

Let's define our what: Objects do not depend upon particular threads. If a thread should fail, the thread is recreated, and the object continues to run. This should be as unobtrusive as possible.
Scenarios can clarify the requirement and save time

Following the what review exercise, run through some scenarios the particular what will do. This first test can be done without spending a dime on design.

To generate some scenarios, simply imagine the potential objects created by the what and consider the possibilities that could happen. Try to think outside the box.

So, let's say we have an object that runs in a thread. We know the thread might die, and we need to deal with the consequences.

We must provide memory management to prevent so-called memory leaks. However, memory management has nothing directly to do with our thread-oriented requirement—it's beyond the scope of the what.

The crucial issue is that we want to maintain thread operation. There are a few possible subscenarios:

1. Sunny day: All is well. Just restart the thread and keep running.
2. Rainy day: Bad things happen. The object is somehow corrupted.
3. Typhoon: Really bad things happen. The JVM may be unstable.

Thinking more carefully, Scenario 2 describing corrupted data and Scenario 3 describing an unstable JVM might not affect this application. For this application, failure is the worst possibility. For others, it may be necessary to validate data or even JVM integrity. But for our simple case, the sunny day scenario suffices. Therefore, this design will not include data checking or object recreation in a new JVM. In a more robust design, the object persistence might be refreshed to validate data. In a worst-case scenario, the entire JVM should shutdown and restart.

The how: Identify objects and create a design

We must identify the objects involved in the design. First, there should be a detection object; we can call this object the watchdog. In our particular design, the watchdog watches all other threads. The watchdog runs in its own thread and has a collection of references to other threads so it can monitor them and make sure they're all alive. Conveniently, the Thread class provides an isAlive() method to determine if a thread is alive. The watchdog uses this method to detect each thread in its collection. If a thread fails, it's the watchdog's responsibility to report it.

For more robustness, this design will include a second "dog," the beta dog (the watchdog is the alpha dog). The beta dog's purpose is simply to check that the alpha dog is alive. The alpha dog also detects the beta dog.
Watchdogs

The ThreadWatchDog is a particular MutableThread instance that monitors threads, and monitored threads must be either MutableThread or Thread (or their descendants). The watchdog runs through the collection of threads and invokes the isAlive() method. When it notices that a thread is dead, it uses reCreate() to recreate the thread if it is a mutable thread. Otherwise, it simply reports the failure.

Here's how this looks (in the ThreadWatchDog test program associated with this article):


if (lTestThread instanceof MutableThread)
{
if (!((MutableThread)lTestThread).isAlive())


This tests the mutable thread to see if it is alive. In the case of a MutableThread, it reports an exception and then attempts to restart the thread, if possible, with the following code:

ReportingExceptionHandler.processException( new ReportingException("Mutable Thread " + lThreadKey + " is dead"));
try {
// Attempt to restart the thread by clearing and restarting
((MutableThread)lTestThread).createThread();
((MutableThread)lTestThread).start();



For a MutableThread, the ThreadKey is the name assigned to the thread when it is created. The application sets up the threads and assigns them to the watchdog on startup. This is done as follows:

TestThread threadOne = new TestThread();
threadOne.setName("threadOne");
TestThread threadTwo = new TestThread();
threadTwo.setName("threadTwo");
TestMutableThread threadMutable = new TestMutableThread();
threadMutable.setName("threadMutable");
ThreadWatchDog.getInstance().put(threadOne);
ThreadWatchDog.getInstance().put(threadTwo);
ThreadWatchDog.getInstance().put(threadMutable);
threadOne.start();
System.out.println("TEST: Thread One started");
threadTwo.start();
System.out.println("TEST: Thread Two started");
threadMutable.start();
MutableThread lWatchDog = ThreadWatchDog.getInstance();
System.out.println("TEST: Starting the watchdog");
lWatchDog.start();



This starts up the watchdog(s), and thread monitoring is now active. Note clearly that the threads should be started up before initializing the watchdogs, or things will get really confusing.

Note that the put() method adds threads to the ThreadWatchDog. This adds the thread to the collection. The put() method is also overloaded with a put(MutableThread mutableThread). This is because MutableThread isn't really a Thread; rather it implements the MutableRunnable interface, much as Thread implements the Runnable interface.

The MutableThread includes a handle to the actual Thread, and this can be recreated, which replaces the thread owned by the mutable thread:

public void createThread() {
mThisThread = new Thread(this, mThreadName);
mThisThread.setPriority(mPriority);
}



Note that the mThisThread is created by passing the this through the thread constructor. That allows the current object to be assigned to the new thread.

The actual thread is encapsulated within the MutableThread and can be recreated and restarted.

The deprecated Thread.stop() method is used in the test program to show what happens when threads die:

System.out.println("TEST: Stopping threadOne");
threadOne.stop();
System.out.println("TEST: Stopping threadMutable");
threadMutable.stop();



Later in the test program, we even kill the alpha watchdog to make sure the failure is detected and reported. The watchdogs are named internally and do not need to be named as do the application threads.
More on MutableThread

The MutableThread class does not use thread groups, but this function can be added. The thread owned by the MutableThread is not accessible by any other class because the thread should not be referenced anywhere else. Users of this class should not be affected if the thread is replaced. The class is abstract because it does not implement the run() method. This must be implemented by any class that wants to be an instance of MutableThread.

Note that the MutableThread implements the Runnable interface, and the internal thread created with the new Thread(Runnable, String) then invokes the run() method within the thread's implementing Runnable class. The string passed is the name. All necessary attributes are retained within the MutableThread object so that the thread name and priority are assigned to a new thread when the createThread() method is invoked.
Explore mutation

That's about it. Download the source code file that accompanies this article and extract various bits to explore the notion of mutable threads and watchdogs on your own.

mutablethread.jar contains all the code for MutableThread and the watchdogs. I've included a PC batch file, run.bat, to help you invoke the test program. Simply type run in the same directory as the mutablethread.jar and run.bat files. The code includes a logger class that logs to the console, but this can be easily modified to a logging system such as log4j. There is also a ReportingException that handles nesting and reports the exception that a thread has died.

Finally, don't forget to summarize requirements and separate the requirements from design concerns. Following this analysis and design approach can be a big advantage in creating more reliable and extensible systems.

Sunday, September 16, 2007

Detect and remove hardware problem with BUGDOCTOR.COM

BUGDOCTOR.COM the antidote to all your computer error woes. New Bug-Detecting and Removal Software Bringing Back Your Computer's Pulse

March 9, 2005 - Are you one of the billions of computer user’s whose PC is infected with a pesky infection? SOFTWARE DOCTOR INC. today announced the worldwide public release of BugDoctor, the most advanced error-removal software on the market. BugDoctor is a new computer tool that seamlessly scans for, detects and deletes a comprehensive range of hard drive bugs. It roots out potentially crash-inducing errors at their source, ferreting deep into PC application sections-such as Active X Com, device drivers, corrupt help files, and Windows startup applications and shortcuts-where these parasites hide. The program is available for complimentary download at BugDoctor.com and an initial error scan is available free of charge.

According to a National Cyber Security study conducted in June 2003, 9 out of 10 PCs connected to the Internet contain spyware. Even more startling, 94% of PCs are infected with spyware-associated bugs and errors that if not repaired properly can put them at extreme risk for system failure. While many adware and spyware removal programs are effective in eradicating the annoying popups that such malicious programs carry with them, they leave behind registry keys that not only slow down system performance but also pose the potential for an outright system crash.

If you are noticing such computer problems as slow startups, troublesome shut-downs, unresponsive programs, or runtime, 404 or msg errors, then your computer could be at high risk for permanent failure. Before tossing thousands of money into a new system, however, you owe it to yourself to give BugDoctor a try. Chris V., a satisfied client, is glad he did: "I was going to invest over $2,500 in a new computer, but I decided to try BugDoctor first and I’m glad I did. Now my PC runs like new again, saving me hundreds of dollars and tons of time."

Not only will BugDoctor repair every type of aforementioned computer error, but it will also boost your system’s speed and performance by as much as 300%. The program is easy and safe to use and regular scanning and deletion will result in a more stable and faster running Windows environment.

To download the new BugDoctor error-removal software and to scan your own PC before it’s too late, visit the company online at www.BugDoctor.com. For more information on how BugDoctor can protect and save your computer from debilitating system bugs, contact Mike Delrue at support@bugdoctor.com.

###
This press release has been posted by Software Submit.NET, website and software submission on-line service, avaliable worldwide. For details contact Software Submit.NET at http://www.softwaresubmit.net

About This Release
If you have any questions regarding information in these press releases please contact the organization listed in the press release. Issuers of press releases and not PR Leap are solely responsible for the accuracy of the content.

Saturday, September 15, 2007

Builder pattern

Today i want to introduce Builder Pattern.

1. First we need to know the Builder Pattern class diagram:
Class diagram:



Now we will explain the meaning of those class:

Builder: An interface used to create complex object.

Concrete Builder: An implementation of Builder. Builder give us the way to construct object. And Concrete Builder show us how to do in detail.

Director: The Director class is responsible for managing the correct sequence of object creation. It receives a Concrete Builder as a parameter and executes the necessary operations on it.

Explanation:
We have a complex object with many part. To create object, we have to create many sub item in it. For example: We have a pizza. There are many type of pizza. Each type has its own way to do pizza.
For Hawaiian pizza: it make from cross, mild, ham+pineapple
For Spicy pizza: it make from pan baked, hot, pepperoni+salami


So we design as below:
+ Builder define how to create pizza. It provide the mean to create pizza:
public void setDough(String dough)
public void setSauce(String sauce)
public void setTopping(String topping)

For each kind of pizza( a concrete builder) , we will give pizza a suitable thing




/** "Product" */
class Pizza
{
private String dough = "";
private String sauce = "";
private String topping = "";

public void setDough(String dough)
{ this.dough = dough; }
public void setSauce(String sauce)
{ this.sauce = sauce; }
public void setTopping(String topping)
{ this.topping = topping; }
}

/** "Abstract Builder" */
abstract class PizzaBuilder
{
protected Pizza pizza;

public Pizza getPizza()
{
return pizza;
}
public void createNewPizzaProduct()
{
pizza = new Pizza();
}

public abstract void buildDough();
public abstract void buildSauce();
public abstract void buildTopping();
}

/** "ConcreteBuilder" */
class HawaiianPizzaBuilder extends PizzaBuilder
{
public void buildDough()
{
pizza.setDough("cross");
}
public void buildSauce()
{
pizza.setSauce("mild");
}
public void buildTopping()
{
pizza.setTopping("ham+pineapple");
}
}

/** "ConcreteBuilder" */
class SpicyPizzaBuilder extends PizzaBuilder
{
public void buildDough()
{
pizza.setDough("pan baked");
}
public void buildSauce()
{
pizza.setSauce("hot");
}
public void buildTopping()
{
pizza.setTopping("pepperoni+salami");
}
}

But we need to describe the sequence to do pizza(step by step)
so we need to implement Director and give it Builder as parameter


class Waiter
{
private PizzaBuilder pizzaBuilder;

public void setPizzaBuilder(PizzaBuilder pb)
{
pizzaBuilder = pb;
}
public Pizza getPizza()
{
return pizzaBuilder.getPizza();
}

public void constructPizza()
{
pizzaBuilder.createNewPizzaProduct();
pizzaBuilder.buildDough();
pizzaBuilder.buildSauce();
pizzaBuilder.buildTopping();
}
}


Finally: We use it:

class BuilderExample
{
public static void main(String[] args)
{
Waiter waiter = new Waiter();
PizzaBuilder hawaiianPizzaBuilder = new HawaiianPizzaBuilder();
PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder();

waiter.setPizzaBuilder( hawaiianPizzaBuilder );
waiter.constructPizza();

Pizza pizza = waiter.getPizza();
}
}

Hope it can help you to understand builder pattern

Friday, September 7, 2007

EJB best practices

EJB best practices: Build a better exception-handling framework

Deliver more useful exceptions without sacrificing clean code



Level: Intermediate

Brett McLaughlin (brett@newInstance.com), Author and Editor, O'Reilly Media Inc.

01 Jan 2003

Enterprise applications are often built with little attention given to exception handling, which can result in over-reliance on low-level exceptions such as java.rmi.RemoteException and javax.naming.NamingException. In this installment of EJB Best Practices, Brett McLaughlin explains why a little attention goes a long way when it comes to exception handling, and shows you two simple techniques that will set you on the path to building more robust and useful exception handling frameworks.

In previous tips in this series, exception handling has been peripheral to our core discussion. One thing you may have picked up, however, is that we've consistently distanced low-level exceptions from the Web tier. Rather than have the Web tier handle exceptions such as java.rmi.RemoteException or javax.naming.NamingException, we've supplied exceptions like ApplicationException and InvalidDataException to the client.

Remote and naming exceptions are system-level exceptions, whereas application and invalid-data exceptions are business-level exceptions, because they deliver more applicable business information. When determining what type of exception to throw, you should always first consider the tier that will handle the reported exception. The Web tier is generally driven by end users performing business tasks, so it's better equipped to handle business-level exceptions. In the EJB layer, however, you're performing system-level tasks such as working with JNDI or databases. While these tasks will eventually be incorporated into business logic, they're best represented by system-level exceptions like RemoteException.

Theoretically, you could have all of your Web tier methods expect and respond to a single application exception, as we did in some of our previous examples. But that approach wouldn't hold up over the long run. A far better exception-handling scheme would be to have your delegate methods throw more specific exceptions, which are ultimately more useful to the receiving client. In this tip, we'll discuss two techniques that will help you create more informative, less generalized exceptions, without generating a lot of unnecessary code.

Nested exceptions

The first thing to think about when designing a solid exception-handling scheme is the abstraction of what I call low-level or system-level exceptions. These are generally core Java exceptions that report errors in network traffic, problems with JNDI or RMI, or other technical problems in an application. RemoteException, EJBException, and NamingException are common examples of low-level exceptions in enterprise Java programming.

These exceptions are fairly meaningless, and can be especially confusing when received by a client in the Web tier. A client that invokes purchase() and receives back a NamingException has little to work with when it comes to resolving the exception. At the same time, your application code may need to access the information within these exceptions, so you can't simply throw out or ignore them.

The answer is to provide a more useful type of exception that also contains a lower-level exception. Listing 1 shows a simple ApplicationException that does just this:


Listing 1. A nested exception
package com.ibm;

import java.io.PrintStream;
import java.io.PrintWriter;

public class ApplicationException extends Exception {

/** A wrapped Throwable */
protected Throwable cause;

public ApplicationException() {
super("Error occurred in application.");
}

public ApplicationException(String message) {
super(message);
}

public ApplicationException(String message, Throwable cause) {
super(message);
this.cause = cause;
}

// Created to match the JDK 1.4 Throwable method.
public Throwable initCause(Throwable cause) {
this.cause = cause;
return cause;
}

public String getMessage() {
// Get this exception's message.
String msg = super.getMessage();

Throwable parent = this;
Throwable child;

// Look for nested exceptions.
while((child = getNestedException(parent)) != null) {
// Get the child's message.
String msg2 = child.getMessage();

// If we found a message for the child exception,
// we append it.
if (msg2 != null) {
if (msg != null) {
msg += ": " + msg2;
} else {
msg = msg2;
}
}

// Any nested ApplicationException will append its own
// children, so we need to break out of here.
if (child instanceof ApplicationException) {
break;
}
parent = child;
}

// Return the completed message.
return msg;
}

public void printStackTrace() {
// Print the stack trace for this exception.
super.printStackTrace();

Throwable parent = this;
Throwable child;

// Print the stack trace for each nested exception.
while((child = getNestedException(parent)) != null) {
if (child != null) {
System.err.print("Caused by: ");
child.printStackTrace();

if (child instanceof ApplicationException) {
break;
}
parent = child;
}
}
}

public void printStackTrace(PrintStream s) {
// Print the stack trace for this exception.
super.printStackTrace(s);

Throwable parent = this;
Throwable child;

// Print the stack trace for each nested exception.
while((child = getNestedException(parent)) != null) {
if (child != null) {
s.print("Caused by: ");
child.printStackTrace(s);

if (child instanceof ApplicationException) {
break;
}
parent = child;
}
}
}

public void printStackTrace(PrintWriter w) {
// Print the stack trace for this exception.
super.printStackTrace(w);

Throwable parent = this;
Throwable child;

// Print the stack trace for each nested exception.
while((child = getNestedException(parent)) != null) {
if (child != null) {
w.print("Caused by: ");
child.printStackTrace(w);

if (child instanceof ApplicationException) {
break;
}
parent = child;
}
}
}

public Throwable getCause() {
return cause;
}
}

The code in Listing 1 is fairly straightforward; we've simply chained together multiple exceptions to create a single, nested exception. The real benefit, however, is in using this technique as the starting point to create an application-specific hierarchy of exceptions. An exception hierarchy will let your EJB clients receive both business-specific exceptions and system-specific information, without requiring you to write a lot of extra code.





A hierarchy of exceptions

Your exception hierarchy should begin with something fairly robust and generic, like ApplicationException. If you make your top-level exception too specific you'll end up having to restructure your hierarchy later to fit in something more generic.

So, let's say that your application called for a NoSuchBookException, an InsufficientFundsException, and a SystemUnavailableException. Rather than create individual exceptions for each, you could set up each exception to extend ApplicationException, providing only the few additional constructors needed to create a formatted message. Listing 2 is an example of such an exception hierarchy:


Listing 2. An exception hierarchy
package com.ibm.library;

import com.ibm.ApplicationException;

public class NoSuchBookException extends ApplicationException {

public NoSuchBookException(String bookName, String libraryName) {
super("The book '" + bookName + "' was not found in the '" +
libraryName + "' library.");
}
}

The exception hierarchy makes things much simpler when it comes to writing numerous specialized exceptions. Adding a constructor or two for each exception class rarely takes more than a few minutes per exception. You will also often need to provide subclasses of these more specific exceptions (which are in turn subclasses of the main application exception), providing even more specific exceptions. For example, you might need an InvalidTitleException and a BackorderedException to extend NoSuchBookException.

Enterprise applications are often built with almost no attention given to exception handling. While it's easy -- and sometimes tempting -- to rely on low-level exceptions like RemoteException and NamingException, you'll get a lot more mileage out of your application if you start with a solid, well-thought-out exception model. Creating a nested, hierarchical exception framework will improve both your code's readability and its usability.

EJB best practices

EJB best practices: Industrial-strength JNDI optimization

Use caching and a generic factory class to automate JNDI lookups
developerWorks

Integrate new tools and architectures into your environment -- fast!

Level: Intermediate

Brett McLaughlin (brett@newInstance.com), Author and Editor, O'Reilly Media Inc.

01 Sep 2002

Brett McLaughlin continues his EJB best practices with an examination of JNDI lookups, which are an essential and frequent part of almost all EJB interactions. Unfortunately, JNDI operations almost always exact a performance toll. In this tip, Brett shows you how a home-interface factory can reduce the overhead of JNDI lookups in your EJB applications.

Every kind of EJB component (session, entity, and message driven) has a home interface. The home interface is a bean's base of operations; once you've found it, you have access to that bean's functionality. EJB applications rely on JNDI lookups to access their beans' home interfaces. Because EJB apps tend to run multiple beans, and because JNDI lookups are often present in many components, much of an application's performance overhead can be spent on these lookups.

In this tip, we'll look at some of the most common JNDI optimizations. In particular, I'll show you how to combine caching and a generic helper class to create a factory-style solution to JNDI overhead.

Reducing context instances

Listing 1 shows a typical piece of EJB code, requiring multiple JNDI lookups. Study the code for a moment, and then we'll work on optimizing it for better performance.

public boolean buyItems(PaymentInfo paymentInfo, String storeName,
List items) {
// Load up the initial context
Context ctx = new InitialContext();

// Look up a bean's home interface
Object obj = ctx.lookup("java:comp/env/ejb/PurchaseHome");
PurchaseHome purchaseHome =
(PurchaseHome)PortableRemoteObject.narrow(obj, PurchaseHome.class);
Purchase purchase = purchaseHome.create(paymentInfo);

// Work on the bean
for (Iterator i = items.iterator(); i.hasNext(); ) {
purchase.addItem((Item)i.next());
}

// Look up another bean
Object obj = ctx.lookup("java:comp/env/ejb/InventoryHome");
InventoryHome inventoryHome =
(InventoryHome)PortableRemoteObject.narrow(obj, InventoryHome.class);
Inventory inventory = inventoryHome.findByStoreName(storeName);

// Work on the bean
for (Iterator i = items.iterator(); i.hasNext(); )
inventory.markAsSold((Item)i.next());
}

// Do some other stuff
}


While this example is somewhat contrived, it does reveal some of the most glaring problems with using JNDI. For starters, you might ask yourself if the new InitialContext object is necessary. It's likely that this context has already been loaded elsewhere in the application code, yet we've created a new one here. Caching the InitialContext instances would result in an immediate performance boost, as shown in Listing 2:

public static Context getInitialContext() {
if (initialContext == null) {
initialContext = new InitialContext();
}

return initialContext;
}


By using a helper class with the getInitialContext() instead of instantiating a new InitialContext for every operation, we've cut down the number of contexts floating around in our application to one.

Uh oh -- what about threading?
If you're worried about the effects of threading on the solution proposed here, don't be. It is absolutely possible that two threads could go to work on at the same time (thus creating two contexts at once) but this type of error would happen only on the first invocation of the method. Because the problem won't come up more than once, synchronization is unnecessary, and would in fact introduce more complexities than it would resolve.

Optimizing lookups

Caching the context instances is a step in the right direction, but we're not done optimizing yet. Every time we call the lookup() method it will perform a new lookup, and return a new instance of a bean's home interface. At least, that's the way JNDI lookups are usually coded. But wouldn't it be better to have just one home-interface per bean, shared across components?

Rather than looking up the home interface for PurchaseHome or InventoryHome again and again, we could cache each individual bean reference; that's one solution. But what we really want is a more general mechanism for caching home interfaces in our EJB applications.

The answer is to create a generic helper class to both obtain the initial context and look up the home interface for every bean in the application. In addition, this class should be able to manage each bean's context for various application components. The generic helper class shown in Listing 3 will act as a factory for EJB home interfaces:

package com.ibm.ejb;

import java.util.Map;
import javax.ejb.EJBHome;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EJBHomeFactory {

private static EJBHomeFactory instance;

private Map homeInterfaces;
private Context context;

// This is private, and can't be instantiated directly
private EJBHomeFactory() throws NamingException {
homeInterfaces = new HashMap();

// Get the context for caching purposes
context = new InitialContext();

/**
* In non-J2EE applications, you might need to load up
* a properties file and get this context manually. I've
* kept this simple for demonstration purposes.
*/
}

public static EJBHomeFactory getInstance() throws NamingException {
// Not completely thread-safe, but good enough
// (see note in article)
if (instance == null) {
instance = new EJBHomeFactory();
}
return instance;
}

public EJBHome lookup(String jndiName, Class homeInterfaceClass)
throws NamingException {

// See if we already have this interface cached
EJBHome homeInterface =
(EJBHome)homeInterfaces.get(homeInterfaceClass);
// If not, look up with the supplied JNDI name
if (homeInterface == null) {
Object obj = context.lookup(jndiName);
homeInterface =
(EJBHome)PortableRemoteObject.narrow(obj, homeInterfaceClass);

// If this is a new ref, save for caching purposes
homeInterfaces.put(homeInterfaceClass, homeInterface);
}
return homeInterface;
}
}

Inside the EJBHomeFactory class

The key to the home-interface factory is in the homeInterfaces map. The map stores each bean's home interface for use; as such, one home-interface instance can be used over and over again. You should also note that the key in the map is not the JNDI name passed into the lookup() method. It's quite common to have the same home interface bound to different JNDI names, but doing so can result in duplicates in your map. By relying on the class itself, you ensure that you won't end up with multiple home interfaces for the same bean.

Inserting the new home-interface factory class into the original code from Listing 1 will result in the optimized EJB lookup shown in Listing 4:

public boolean buyItems(PaymentInfo paymentInfo, String storeName,
List items) {

EJBHomeFactory f = EJBHomeFactory.getInstance();

PurchaseHome purchaseHome =
(PurchaseHome)f.lookup("java:comp/env/ejb/PurchaseHome",
PurchaseHome.class);
Purchase purchase = purchaseHome.create(paymentInfo);

// Work on the bean
for (Iterator i = items.iterator(); i.hasNext(); ) {
purchase.addItem((Item)i.next());
}

InventoryHome inventoryHome =
(InventoryHome)f.lookup("java:comp/env/ejb/InventoryHome",
InventoryHome.class);
Inventory inventory = inventoryHome.findByStoreName(storeName);

// Work on the bean
for (Iterator i = items.iterator(); i.hasNext(); ) {
inventory.markAsSold((Item)i.next());
}

// Do some other stuff
}


In addition to being more clear (at least in my opinion) the factory-optimized EJB lookup above will perform much faster over time. The first time you use the new class, you'll incur all the usual lookup penalties (assuming another portion of the application hasn't already paid them) but all future JNDI lookups should hum right along. It's also worth pointing out that the home-interface factory will not interfere with your container's bean management. Containers manage bean instances, not the home interfaces of those instances. Your container will still be in charge of instance swapping, as well as any other optimizations you want it to perform.

In the next installment of EJB best practices, I'll show you how you can enable administrative access to entity beans, without directly exposing them to your application's Web tier. Until then, I'll see you online.

Wednesday, September 5, 2007

JAVA Strengths

JAVA Strengths

Java is an excellent programming language. For most programming it's better than older programming languages like C or C++.

  1. Productivity The top reason Java has become popular is because of the increased productivity of Java programmers. It is claimed, and my experience is in agreement, that Java programmers have about double the productivity of C/C++ programmers.
  1. GUI Java a good, portable library for a Graphical User Interface (GUI). Most programming languages supply only a text mode interface.
  • Internet Java lets you easily use the Internet. Most languages were designed before the Internet was born!
  1. Portability Java programs can run on many different machines (Intel, Sparc, PowerPC, ...) and many different operating systems (Windows, Unix, Macintosh, ...). You can move a C program if it is written very carefully, but it is usually difficult or impossible. In contrast, it easy to move most Java programs.
  1. Reliability Java programs are more reliable because Java doesn't have very dangerous things like C/C++'s pointer arithmetic. Java also checks array bounds and other error-prone operations. Memory management is much safer because Java does automatic garbage collection.
  1. Libraries Java has a very large number of packages which extend the language. Therefore it is unnecessary to call the operating system directly.
  1. OOP Object-oriented programming features (inheritance, encapsulation, and polymorphism) make many programs, especially large programs, easier to write.
Large Programs Java supports large programming projects with object-oriented programming, packages, and components (JavaBeans).

Tuesday, September 4, 2007

Buffer overflows likely to be around for another decade

Buffer overflows likely to be around for another decade

By Edward Hurley, News Writer

Few classes of security flaws in software cause as many headaches as buffer overflows. Yet given the present programming paradigm, buffer overflows will be around for some time to come, experts say.

Buffer overflows in both Unix and Windows systems were common occurrences in the recently released SANS/FBI Top 20 List of Web vulnerabilities. Buffer overflows open gaping holes that attackers can exploit, as the recent Slapper worm showed. The worm took advantage of a buffer overflow in OpenSSL running on Linux Apache Web servers to set up peer-to-peer networks and to commandeer other computers for possible use in launching distributed denial-of-service attacks.

Often buffer overflow vulnerabilities are hard to find in the minutiae of computer code. Additionally, the nature of the popular C programming language makes them an easy programming error to make, experts said.

In essence, a buffer overflow occurs when too much data is stuffed into a memory space. They are common in applications written in C.

Gerhard Eschelbeck, vice president of engineering at Redwood Shores, Calif.-based Qualys Inc., compares buffer overflows to people filling in handwritten forms that allow one space for each letter of a person's name. A buffer overflow is similar to what happens when the writer does not having enough blocks for one's last name, he said.

The extra "letters" or data aren't lost but written into other places in memory. This could cause the application to act oddly or shut down, creating a denial-of-service condition. It can also allow an attacker to run malicious code on the system. "The code looks the same to the computer," Eschelbeck said.

Buffer overflows can occur in both the stack and heap areas of memory. Stack memory is a pool that all programs can share. When a buffer overflow occurs, the extra data is put into stack memory, much like a card is added to a deck, said Ted Doty, director of product management at Waltham, Mass.-based Okena Inc. The system doesn't realize that data may be malicious.

Buffer overflows in heap memory are similar, except that heap memory is specifically allocated to a program, Doty said.

Buffer overflows are hard to find, and that's why many make their way into finished software products. Basically, one has to squeeze large amounts of data into every area of a program that can accept it to find them, Doty said.

Once an attacker is able to find a buffer overflow, exploiting it is often quite simple.

Finding buffer overflows is especially hard in large server applications that may have as many as 40 million lines of code, Doty said. Software vendors are under too much pressure to get new versions out to market to audit every line of code, he added.

At their most basic, buffer overflow vulnerabilities are programming errors. Error-checking for a too-long string of data wasn't included in the program.

One reason for this is that the C programming language doesn't have boundary checking. It's assumed that someone programming in C would include error-checking in their code, Doty said.

Other languages such as Perl and Java have the utility, hence buffer overflows don't occur, Eschelbeck said. On the other hand, Perl and Java don't offer access to the system that is as deep as some programs need. "The C programming language is very powerful. You can go as deep as you need," he said.

Better programmer training and education would minimize buffer overflows. Certain C functions such as string copy need to be avoided in order to minimize buffer overflows. There are code-auditing tools that look for such flaws, but they are still pretty early in their development, Eschelbeck said.

Software users, however, need to keep on buffer overflows in the applications they run. This means keeping tabs on advisories released by the Computer Emergency Response Team at Carnegie Mellon University or by vendors. Installing the released patches is also a must.

While they occur in many applications, buffer overflows are most damaging in core infrastructure such as domain name servers and Web servers.

Even if all programs started today were written buffer-overflow free, the vulnerabilities will continue to be found for the next few years because of the millions of lines of code that have not been audited. "There's no doubt in my mind that we'll be dealing with buffer overflows for at least the next 10 years," Eschelbeck added.

Monday, September 3, 2007

Looking up an EJB home with JNDI

Example: Looking up an EJB home with JNDI

Most applications that use JNDI run in a container. Some do not. The name used to look up an object depends on whether or not the application is running in a container. Sometimes it is more convenient for an application to use a corbaname URL as the lookup name. Container-based JNDI clients and thin Java clients can use a corbaname URL.

The following examples show how to perform JNDI lookups from different types of applications.

JNDI lookup from an application running in a container

Applications that run in a container can use java: lookup names. Lookup names of this form provide a level of indirection such that the lookup name used to look up an object is not dependent on the object's name as it is bound in the name server's name space. The deployment descriptors for the application provide the mapping from the java: name and the name server lookup name. The container sets up the java: name space based on the deployment descriptor information so that the java: name is correctly mapped to the corresponding object.

The following example shows a lookup of an EJB home. The actual home lookup name is determined by the application's deployment descriptors. The enterprise bean (EJB) resides in an EJB container, which provides an interface between the bean and the application server on which it resides.

// Get the initial context as shown in a previous example
...
// Look up the home interface using the JNDI name
try {
java.lang.Object ejbHome =
initialContext.lookup(
"java:comp/env/com/mycompany/accounting/AccountEJB");
accountHome = (AccountHome)javax.rmi.PortableRemoteObject.narrow(
(org.omg.CORBA.Object) ejbHome, AccountHome.class);
}
catch (NamingException e) { // Error getting the home interface
...
}

JNDI lookup from an application that does not run in a container

Applications that do not run in a container cannot use java: lookup names because it is the container which sets the java: name space up for the application. Instead, an application of this type must look the object up directly from the name server. Each application server contains a name server. System artifacts such as EJB homes are bound relative to the server root context in that name server. The various name servers are federated by means of a system name space structure. The recommended way to look up objects on different servers is to qualify the name so that the name resolves from any initial context in the cell. If a relative name is used, the initial context must be the same server root context as the one under which the object is bound. The form of the qualified name depends on whether the qualified name is a topology-based name or a fixed name. Examples of each form of qualified name follow.

  • Topology-based qualified names

    Topology-based qualified names traverse through the system name space to the server root context under which the target object is bound. A topology-based qualified name resolves from any initial context in the cell.

    Single server
    The following example shows a lookup of an EJB home that is running in the single server, MyServer, configured in the node, Node1.
    // Get the initial context as shown in a previous example
    // Using the form of lookup name below, it doesn't matter which
    // server in the cell is used to obtain the initial context.
    ...
    // Look up the home interface using the JNDI name
    try {
    java.lang.Object ejbHome = initialContext.lookup(
    "cell/nodes/Node1/servers/MyServer/com/mycompany/accounting/AccountEJB");
    accountHome = (AccountHome)javax.rmi.PortableRemoteObject.narrow(
    (org.omg.CORBA.Object) ejbHome, AccountHome.class);
    }
    catch (NamingException e) { // Error getting the home interface
    ...
    }
  • Fixed qualified names

    If the target object has a cell-scoped fixed name defined for it, you can use its qualified form instead of the topology-based qualified name. Even though the topology-based name works, the fixed name does not change with the specific cell topology or with the movement of the target object to a different server. An example lookup with a qualified fixed name is shown below.

    // Get the initial context as shown in a previous example
    // Using the form of lookup name below, it doesn't matter which
    // server in the cell is used to obtain the initial context.
    ...
    // Look up the home interface using the JNDI name
    try {
    java.lang.Object ejbHome = initialContext.lookup(
    "cell/persistent/com/mycompany/accounting/AccountEJB");
    accountHome = (AccountHome)javax.rmi.PortableRemoteObject.narrow(
    (org.omg.CORBA.Object) ejbHome, AccountHome.class);
    }
    catch (NamingException e) { // Error getting the home interface
    ...
    }

JNDI lookup with a corbaname URL

A corbaname can be useful at times as a lookup name. If, for example, the target object is not a member of the federated name space and cannot be located with a qualifiied name, a corbaname can be a convenient way to look up the object. A lookup with a corbaname URL follows.

// Get the initial context as shown in a previous example
...
// Look up the home interface using a corbaname URL
try {
java.lang.Object ejbHome = initialContext.lookup(
"corbaname:iiop:someHost:2809#com/mycompany/accounting/AccountEJB");
accountHome = (AccountHome)javax.rmi.PortableRemoteObject.narrow(
(org.omg.CORBA.Object) ejbHome, AccountHome.class);
}
catch (NamingException e) { // Error getting the home interface
...
}

Sunday, September 2, 2007

EJB and the limitation

According to EJB specification, EJB can not directly use file. So we have to find a way to read/write file indirectly. There are some solution for this.
1. We can use RMI technology.
2. We can use JCA to read file.

Solution 1:

RMI is the way to read file. It is also easy to implemented. All we have to do is make a server which provide a service: read/write file. EJB will implement a client to communicate with this server. All data when read/write file between the EJB and RMi Server is in byte array. But one of the drawback is that RMI is so heavy and big.

Solution 2:
The J2EE Connector architecture is based on the technologies defined and standardized in the Java 2 Platform, Enterprise Edition (J2EE) and is part of the J2EE platform.

As more businesses move towards an e-business strategy, integration with existing enterprise information systems (EIS) becomes the key to success. Enterprises with successful e-businesses need to integrate their existing EIS systems with new web-based applications. They also need to extend the reach of their EIS systems to support business-to-business (B2B) transactions.

Before the the J2EE Connector architecture was defined, no specification for the Java platform addressed the problem of providing a standard architecture for integrating heterogeneous EIS systems. Most EIS vendors and application server vendors use non-standard vendor-specific architectures to provide connectivity between application servers and enterprise information systems. The following diagram illustrates the complexity of a heterogenous environment.



The Java 2 Platform, Enterprise Edition provides containers for client applications, web components based on Servlets and JavaServer Pages (JSP) technologies, and Enterprise JavaBeans (EJB) components. These containers provide deployment and runtime support for application components. They also provide a federated view of the services provided by the underlying application server for the application components.

Containers run on existing systems: web servers for the web containers, application servers, transaction processing (TP) monitors, and database systems for EJB containers. This enables enterprises to leverage both the advantages of their existing systems and those with J2EE technology. Enterprises can write (or rewrite) new applications using J2EE technology capabilities and can also encapsulate parts of existing applications with Enterprise JavaBeans or JavaServer Pages (JSP) technologies.

Enterprise applications access functions and data associated with applications running on EISs. Application servers extend their containers and support connectivity to heterogeneous EISs. Enterprise tools and Enterprise Application Integration (EAI) vendors add value by providing tools and frameworks to simplify the EIS integration task.

The J2EE Connector architecture defines a standard architecture for connecting the J2EE platform to heterogeneous EIS systems. Examples of EIS systems include ERP, mainframe transaction processing, database systems, and legacy applications not written in the Java programming language. By defining a a set of scalable, secure, and transactional mechanisms, the J2EE Connector architecture enables the integration of EISs with application servers and enterprise applications.

The J2EE Connector architecture enables an EIS vendor to provide a standard resource adapter for its EIS. The resource adapter plugs into an application server, providing connectivity between the EIS, the application server, and the enterprise application. If an application server vendor has extended its system to support the J2EE Connector architecture, it is assured of seamless connectivity to multiple EISs. An EIS vendor needs to provide just one standard resource adapter which has the capability to plug in to any application server that supports the J2EE Connector architecture.

Multiple resource adapters (that is, one resource adapter per type of EIS) are pluggable into an application server. This capability enables application components deployed on the application server to access the underlying EIS systems.

Now all we have is implemented ResourceAdapter to provide a File Service to EJB. It is so tricky. But it works.

Google