*
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes NX: Remote/IOException in DBServices interface (Ken...?) Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Murach's Java Servlets and JSP this week in the Servlets forum!
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "NX: Remote/IOException in DBServices interface (Ken...?)" Watch "NX: Remote/IOException in DBServices interface (Ken...?)" New topic
Author

NX: Remote/IOException in DBServices interface (Ken...?)

Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319
The following:

and

I gather that this approach caters for both IOException and RemoteException to be handled correctly if the DBServices' methods throw IOException. But now my DBServices interface methods do not throw IOException. Rather it throws my own DataAccessException.
Not sure I'm getting my mind around this properly. Can somebody give me a tip or two about what to do?
Thanx much!


Jacques<br />*******<br />MCP, SCJP, SCJD, SCWCD
Ken Krebs
Ranch Hand

Joined: Nov 27, 2002
Posts: 451
Jacques,
This technique only works if each of the DBServices throw IOException because RemoteException is a subclass of IOException. If a method throws an IOException, it can also throw a RemoteException without modifying the method signature.
If the business methods of DBServices were not IO oriented, I wouldn't recommend using this technique because it would degenerate from an elegant trick into an unnatural and ugly hack, much like wrapping Data's IO oriented exceptions in a RecordNotFoundException.
The other approach, assuming you don't want the DBServices methods to throw IOException, is to simply define RemoteDBServices to extend Remote. In that case you will have to define a set of similar methods for RemoteDBServices.
Having done that, on the client side, you would still have to solve the problem of adapting the stub so that your client code can use either it or a direct DBServices implementation.


kktec<br />SCJP, SCWCD, SCJD<br />"What we observe is not nature itself, but nature exposed to our method of questioning." - Werner Heisenberg
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319
Hi Ken.
Sorry to bother with this, but I obviously don't understand this thing 100%.

The other approach, assuming you don't want the DBServices methods to throw IOException, is to simply define RemoteDBServices to extend Remote. In that case you will have to define a set of similar methods for RemoteDBServices.

OK, so I extend Remote with RemoteDBServicesImpl and let it implement the DBServices interface. I obviously define my methods in RemoteDBServicesImpl to throw the same exceptions as the DBServices interface. So, can I still delegate the real work to DBServicesImpl?
The methods in my RemoteDBServicesImpl class don't *have* to throw RemoteException, do they?
E.g.
DBServices Interface has this:

DBServicesImpl extends it like this:

So RemoteDBServicesImpl has the same method, and delegates to DBServicesImpl.


Having done that, on the client side, you would still have to solve the problem of adapting the stub so that your client code can use either it or a direct DBServices implementation.

Can you expound?
Won't I just be able to catch the DataAccessException on the client GUI side either way?
Thanx!
Ken Krebs
Ranch Hand

Joined: Nov 27, 2002
Posts: 451
Won't I just be able to catch the DataAccessException on the client GUI side either way?

Yes. But what about the RemoteExceptions that need to be thrown by the RemoteDBServicesImpl and stub methods ?
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319
OK. So I'll have to then catch and handle the RemoteExceptions too on the GUI side.
But other than that... There are no further problems?
Here comes a question I should know the answer to, but how can the RemoteDBServicesImpl methods throw a RemoteException if it's not included in the DBServices interface method signature?
Thanx for the help, Ken!
Ken Krebs
Ranch Hand

Joined: Nov 27, 2002
Posts: 451
Well, DBServices can't but what interface does RemoteDBServicesImpl implement ?
[ January 28, 2004: Message edited by: Ken Krebs ]
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319

Well, DBServices can't but what interface does RemoteDBServicesImpl implement?

OK, Remote, I know.
But the Remote interface doesn't know what methods are in the implementing class. Therefore, how can it know to 'add' a RemoteException to their throws clause.
Sorry, I'm just trying to understand this. I think it's all backward in my brain.
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319
And... RemoteException is a checked exception.
So, on the client side, I won't be able to just catch it when using my DBServices interface for both the local and remote access because it doesn't throw it...?
Ken Krebs
Ranch Hand

Joined: Nov 27, 2002
Posts: 451
What would you have to do if RemoteDBServices does NOT extend DBServices ?
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319

What would you have to do if RemoteDBServices does NOT extend DBServices ?

Mmmmm....
I won't be able to use DBServices on the client side for both local and remote. I would have to write double the client code.
???
Ken Krebs
Ranch Hand

Joined: Nov 27, 2002
Posts: 451
Are you sure you won't be able to use DBServices on the client side for both local and remote?
...Having done that, on the client side, you would still have to solve the problem of adapting the stub so that your client code can use either it or a direct DBServices implementation.
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319
Hey bro. You got me with all these funky questions of yours...
How would I adapt it to use the same interface?
By the way, you're up real early! Sorta the time I get up too. But over here it's afternoon now. Where are you? Did you sleep since your last post? Wasn't very long...
Ken Krebs
Ranch Hand

Joined: Nov 27, 2002
Posts: 451
Hey bro. You got me with all these funky questions of yours...
How would I adapt it to use the same interface?

I think it's better to take a que from Socrates rather than spoil all your fun by handing you an answer.
From the classic GoF Design Patterns book (you do have it, don't you ?):
Adapter
Intent: Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
Think composition and delegation and you should be able to roll your own quite easily.
??? Who needs it. Well actually, 5-6 hrs. usually does it for me here in the frozen tundra of Wisconsin (FMAO).
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319

I think it's better to take a que from Socrates rather than spoil all your fun by handing you an answer.

FINE THEN!

From the classic GoF Design Patterns book (you do have it, don't you ?):

Nope, sorry.

Adapter
Intent: Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.

OK, well, that makes sense. Now to just figure it.

Think composition and delegation and you should be able to roll your own quite easily.

OK. I'll see what I can do.

Well actually, 5-6 hrs. usually does it for me here in the frozen tundra of Wisconsin (FMAO).

Ahhh. I need at least 6-7-8 hours here in the boiling heat of Pretoria, South Africa.
Ken Krebs
Ranch Hand

Joined: Nov 27, 2002
Posts: 451
Sounds like you have a temporary case of the "Problem Overload Brain Block" disease.
Dr. Ken's prescription is to forget about it for now; get those 6-8 hours of and let the problem fester in your subconcious for a while. When you come back to it, the answer will magically appear in your mind.
Oh yeah, and I recommend you do yourself a favor and get the book. All of the patterns and possible solutions described are worthy of deep study.
Design Patterns
Elements of Reusable Object-Oriented Software Design
by
Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319

Sounds like you have a temporary case of the "Problem Overload Brain Block" disease.

Yeah man. I think I got it BAD!

...the answer will magically appear in your mind.

I'll see what happens in the morning. I'm hopeful.

Oh yeah, and I recommend you do yourself a favor and get the book. All of the patterns and possible solutions described are worthy of deep study.

I'll look into getting it.
Thanx man.
Flavio Nobili
Ranch Hand

Joined: Jan 28, 2004
Posts: 58
I had the same problem, and solved it by making my database exception extend IOException.
Hope this helps,
Flavio.


Java Developer
SCJP, SCJD, SCWCD, SCBCD
Ken Krebs
Ranch Hand

Joined: Nov 27, 2002
Posts: 451
Flavio,
... solved it by making my database exception extend IOException

That's what Jacques is trying to avoid. Although, in this case, a database operation probably implies an IO operation and respective exceptions, there could easily be circumstances where there is no IO operation. It could be that there is some kind of business rule exception that occurs that needs to be handled. For this, a more general strategy needs to be used rather than this "RemoteException IS an IOException" trick. That is what he's trying to work out.
Derek Canaan
Ranch Hand

Joined: Nov 05, 2003
Posts: 64
Hi Jacques,
I'm thinking about the same issues as you. I thought of 3 ways one can retain this "nice-trick" design even though the Data methods throw DataAccessException (= a Runtime Exception, is this so?):
1. Have all the Services interface methods throw Exception (maximal design)
2. Have all the Services interface methods throw RemoteException (minimal design)
3. Have all the Services interface methods throw IOException (the mid-path design)
In a way, the Services interface design is "forced" because:
1. You want Services interface to be used in both alone and networked mode.
2. The methods in the networked mode have to throw RemoteException
So methods in Services have no choice but to throw RemoteException or its superclass. So the 3 solutions should work.
You could do one of these:
1. Unwrap your DataAccessException in book() that wrapped IOException from Data and re-throw it as IOException to make design looked "natural". I think Ken did this (Ken, am i right?)
2. Don't unwrap. Is there any benefits in unwrapping the IOX and re-throwing it?
If i'm not mistaken, Ken's design uses cache. Search method for cache design does not throw any IOException. So even though the search() method in Services throw IOException, it is never thrown in ServicesImpl's search(). This makes the Services design "unnatural", but what choice do you have if you want it to be used in both alone and networked mode.
Ken, is the analysis right? Comments, anyone?
rgds,
derek
[ January 29, 2004: Message edited by: Derek Canaan ]
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319
In my DBServices interface.
My find method throws DataAccessException.
My book method throws RecordOutOfDateException, RecordNotFoundException, DataAccessException.
(And a DataAccessException is not just from an IOException. It's also thrown when there is locking problems or thread interrupts.)
I feel that all these should be passed to the GUI client. For instance, I don't feel it's elegant to just give the client a DataAccessException when it's actually a RecordNotFoundException.
So I have to accomodate all of these plus RemoteException on the client GUI side.
Derek Canaan
Ranch Hand

Joined: Nov 05, 2003
Posts: 64
Hi Jacques,
And a DataAccessException is not just from an IOException.

Hence, i see no benefits in unwrapping IOX from DataAccessException and re-throwing IOX, because IOX is just as irrecoverable as thread interrupts exception. Both should be handled the same way, imho.
For instance, I don't feel it's elegant to just give the client a DataAccessException when it's actually a RecordNotFoundException.

Sorry, my previous post wasn't clear:

1. Have all the Services interface methods throw Exception + whatever specific checked exception needed for each individual methods (maximal design)
2. Have all the Services interface methods throw RemoteException + whatever specific checked exception needed for each individual methods (minimal design)
3. Have all the Services interface methods throw IOException + whatever specific checked exception needed for each individual methods (the mid-path design)

Handling exceptions (checked and unchecked) appropriately at the gui side:- one way is to handle all the checked exceptions individually, and for the remaining Runtime exceptions (incl DataAccessException) and RemoteException, have a catch (Exception e) block to handle them.
What do you think?
rgds,
derek
[ January 30, 2004: Message edited by: Derek Canaan ]
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319
I finally got to coding this stuff.
I have this now.

But then the following gives me a ClassCastException.

This works though:

Why will it work with Remote, but not with DBServices. Both those interfaces have been implemented. Or is this what we were talking about earlier with the adaptor?
Help me understand.

And Derek, (Hi)

Handling exceptions (checked and unchecked) appropriately at the gui side:- one way is to handle all the checked exceptions individually, and for the remaining Runtime exceptions (incl DataAccessException) and RemoteException, have a catch (Exception e) block to handle them.

I throw neither of my runtime exceptions (RuntimeIOException or RuntimeLockException) up to the client. Both of those are thrown by my Data class and caught in my DBServicesImpl class. DBServicesImpl then throws whatever it has to, as checked exceptions, including DataAccessException, up to the client.
Haven't sorted out my RemoteException thing yet, as you can gather.
[ January 30, 2004: Message edited by: Jacques Bosch ]
Derek Canaan
Ranch Hand

Joined: Nov 05, 2003
Posts: 64
Hi,
I don't know if this work, but try making an interface RemoteDBServices that extends DBServices and Remote and have your RemoteDBServicesImpl implements RemoteDBServices.
Then see if DBServices dbServices = (DBServices)Naming.lookup(url); works.
rgds,
derek
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319
That is what I had before, but I gathered, from Ken, that that wasn't an elegant solution if my DBServices' methods don't throw IOExceptions.
Will try it again.
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319

I don't know if this work, but try making an interface RemoteDBServices that extends DBServices and Remote and have your RemoteDBServicesImpl implements RemoteDBServices.
Then see if DBServices dbServices = (DBServices)Naming.lookup(url); works.

OK I did it like that again, and bind it like this:

And try get it like this:

but I still get a ClassCastException.
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319
OK wait.
Doing the empty interface like above I now get this error from my RMI compiler:

OK DBServices isn't. But I know that. It's not supposed to be.
But RemoteDBServices is. And that's the one I implement with RemoteDBServicesImpl which is the class I'm compiling as a stub.
What am I doing wrong?
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319
OK..... wait, another brain wave.
It's doing that because RemoteDBServicesImpl is delegating the work to DBServicesImpl and DBServicesImpl throws RemoteException not. Nor IOException. So here we are back to the adaptor patern....................
I think I need to another 6 hours first......!
Ken Krebs
Ranch Hand

Joined: Nov 27, 2002
Posts: 451
This is beginning to look like a maze of twisty little passages. I can see my series of questions wasn't very effective. Hmmmm... I'll have to thnk about that.
Let's see how we can sort it out by looking at a very basic RMI pattern and forget about what's shown in Max's example for the moment.
Assume you have an exception class called ServiceException (that is NOT an IOException) and you want to implement some service that throws ServiceException.


Now you decide you want to do the same thing only as a Remote service. Also assume you want your remote implementation to simply wrap the normal service. The first thing is to define the the Remote service. The problem is , you can't extend Service and add a RemoteException to the method signature as Java does not allow that.

The important point is that RemoteService extends Remote but NOT Service.
It does, however, define a method that is the same as that defined by Service except that RemoteException has been added to the throws clause.
So now, you make a UnicastRemoteObject implementation of RemoteService that wraps (i.e. contains and delegates to) a ServiceImpl.

So far, so good. The only real differences between what I am showing here and what you may find in a typical RMI text are that:
1. I'm using interfaces as well as concrete classes to get a "Dependency Inversion". This will come in handy for protecting the client code from possible implementation changes. The client will only need to depend on the more stable interface instead of the more volatile concrete implementation class.
2. I've defined the Remote implementation class as a wrapper for the normal one. Notice that I also defined the wrapped object instance variable as a Service and not the concrete implementation to protect it from changes.

Now, you still have to solve the problem of how to make your client be able to work with either one without having to duplicate a lot of your client code. That's where an Adapter comes in.

From the classic GoF Design Patterns book (you do have it, don't you ?):
Adapter
Intent: Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
Think composition and delegation and you should be able to roll your own quite easily.

[ January 30, 2004: Message edited by: Ken Krebs ]
[ January 30, 2004: Message edited by: Ken Krebs ]
Ken Krebs
Ranch Hand

Joined: Nov 27, 2002
Posts: 451
Originally posted by Derek Canaan:
Hi Jacques,
I'm thinking about the same issues as you. I thought of 3 ways one can retain this "nice-trick" design even though the Data methods throw DataAccessException (= a Runtime Exception, is this so?):
1. Have all the Services interface methods throw Exception (maximal design)
2. Have all the Services interface methods throw RemoteException (minimal design)
3. Have all the Services interface methods throw IOException (the mid-path design)
In a way, the Services interface design is "forced" because:
1. You want Services interface to be used in both alone and networked mode.
2. The methods in the networked mode have to throw RemoteException
So methods in Services have no choice but to throw RemoteException or its superclass. So the 3 solutions should work.
You could do one of these:
1. Unwrap your DataAccessException in book() that wrapped IOException from Data and re-throw it as IOException to make design looked "natural". I think Ken did this (Ken, am i right?)
2. Don't unwrap. Is there any benefits in unwrapping the IOX and re-throwing it?
If i'm not mistaken, Ken's design uses cache. Search method for cache design does not throw any IOException. So even though the search() method in Services throw IOException, it is never thrown in ServicesImpl's search(). This makes the Services design "unnatural", but what choice do you have if you want it to be used in both alone and networked mode.
Ken, is the analysis right? Comments, anyone?
rgds,
derek
[ January 29, 2004: Message edited by: Derek Canaan ]


Derek,
The Services interface methods can throw any Exception you want them to. The only reason for the DataAccessException (a RuntimeException) is to get IOExceptions and such out of the Data class because the Data interface won't let you do so since don't have to declare it in the throws clauses.
Regarding your 3 "solutions":
1. Is way too unfocused by declaring it throws Exception instead of a more useful application specific exception.
2. Is bad because you create an unnecessary dependency on RMI
3. Is OK but then the client is forced to handle the exceptions when they could be usefully handled at the lower level. You could just unwrap them in the Services implementation and throw a more useful exception to the client as you say later on in your post.
Throwing an IOException is not really unnatural here because it is reasonable to think of these operations, including search, as putting data In or getting data Out of a database. That allows you to use the trick without it being something evil.
[ January 30, 2004: Message edited by: Ken Krebs ]
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319
Hi Ken.
Seems like Socrates didn't work for you... Or should I rather say, he didn't work for me...

...I can see my series of questions wasn't very effective.

Mmmm, you know, I was thinking that same thing. But the fault lies with me.
Thanx for this example, Ken. Finally I'm seeing some light at the end of the tunnel. I'm pretty sure it's not an on-coming train... But I might be wrong.
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319
OK I have the server side interfaces working now. DBServices, and RemoteDBServices implementing Remote, and deligating it's work to DBServices.
Now for the adaptor pattern on the client side.
I have read up about it but have some problems:
I can't have the adaptor implement both DBServices and RemoteDBServices, because the two have the same method signatures except for RemoteDBServices also throwing RemoteException.
Or rather, it lets me implement both, but I can only use one of there method signatures in the actual implementation.
I'll have to think about this some more. But I'm putting in a new hard drive today, so have to reload my whole system. FUN...!!! A good 24 hours worth of work to get it to the same point it's now.
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319

Hi Ken, Derek.
All light suddenly came on this afternoon. Somebody finally seems to be home.
I caught the whole adaptor thing and all is working fine (almost - just a few more lines to type).
Thanx for your patience and help, ken.
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319
Yip. All working perfectly now.
It is so incredibly easy actually............... if you understand it.
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319
Hi Ken.
You wrote:

This is what I did on the server side, and then I used the adaptor pattern on the client side adapting RemoteDBServices to work like DBServices.
But my question: Isn't the wrapping on the server side also basically an adaptor pattern?
And also, should my ServiceAdaptor used on the gui side to turn RemoteDBServices back into DBServices be in my gui package, or in my db package. It is currently in gui.
[ February 02, 2004: Message edited by: Jacques Bosch ]
Ken Krebs
Ranch Hand

Joined: Nov 27, 2002
Posts: 451
Jacques,
Isn't the wrapping on the server side also basically an adaptor pattern?

Definitely.
And also, should my ServiceAdaptor used on the gui side to turn RemoteDBServices back into DBServices be in my gui package, or in my db package. It is currently in gui.

Since its purpose is to be a helper to the gui code, I think that is a reasonable choice except that it places a dependency on rmi into the gui package. If you have a separate rmi package that would be a better choice IMO.
[ February 02, 2004: Message edited by: Ken Krebs ]
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319

Since its purpose is to be a helper to the gui code, I think that is a reasonable choice except that it places a dependency on rmi into the gui package. If you have a separate rmi package that would be a better choice IMO.

Yes. That is what I thought too. Did it like that.
Thanx much.
Jacques
Jason Hocker
Ranch Hand

Joined: Jul 23, 2003
Posts: 132
Sorry, I do not see how to apply the adapter pattern. Still having problems with Exceptions. Please give another hint.
Jacques Bosch
Ranch Hand

Joined: Dec 18, 2003
Posts: 319
Hi there Jay.

Check these out. They should help.

http://www.vico.org/pages/PatronsDisseny/Pattern%20Adapter%20Class/
http://home.earthlink.net/~huston2/dp/adapter.html
http://www.dofactory.com/patterns/PatternAdapter.aspx

"Design Patterns" in 2.5 Hours:
http://www.cs.nmsu.edu/~jeffery/courses/579/patterns.html

And read the below short tutorial: (Sorry about the formatting, it was copied from PDF).
---------------------------------------------------

Design Patterns In Java Bob Tarr
The
Adapter
Pattern
Bob Tarr Design Patterns In Java The Adapter Pattern
2
The Adapter Pattern The Adapter Pattern
l Intent
� Convert the interface of a class into another interface clients expect.
Adapter lets classes work together that couldn't otherwise because of
incompatible interfaces.
l Also Known As
� Wrapper
l Motivation
� Sometimes a toolkit or class library can not be used because its interface is
incompatible with the interface required by an application
� We can not change the library interface, since we may not have its source
code
� Even if we did have the source code, we probably should not change the
library for each domain-specific application
Bob Tarr Design Patterns In Java The Adapter Pattern
3
The Adapter Pattern The Adapter Pattern
l Motivation
� Example:
Bob Tarr Design Patterns In Java The Adapter Pattern
4
The Adapter Pattern The Adapter Pattern
l Structure
� A class adapter uses multiple inheritance to adapt one interface to another:
Bob Tarr Design Patterns In Java The Adapter Pattern
5
The Adapter Pattern The Adapter Pattern
l Structure
� An object adapter relies on object composition:
Bob Tarr Design Patterns In Java The Adapter Pattern
6
The Adapter Pattern The Adapter Pattern
l Applicability
Use the Adapter pattern when
� You want to use an existing class, and its interface does not match the one
you need
� You want to create a reusable class that cooperates with unrelated classes
with incompatible interfaces
l Implementation Issues
� How much adapting should be done?
� Simple interface conversion that just changes operation names and order of
arguments
� Totally different set of operations
� Does the adapter provide two-way transparency?
� A two-way adapter supports both the Target and the Adaptee interface. It
allows an adapted object (Adapter) to appear as an Adaptee object or a Target
object
Bob Tarr Design Patterns In Java The Adapter Pattern
7
Adapter Pattern Example 1 Adapter Pattern Example 1
l The classic round pegs and square pegs!
l Here's the SquarePeg class:
/**
* The SquarePeg class.
* This is the Target class.
*/
public class SquarePeg {
public void insert(String str) {
System.out.println("SquarePeg insert(): " + str);
}
}
Bob Tarr Design Patterns In Java The Adapter Pattern
8
Adapter Pattern Example 1 (Continued) Adapter Pattern Example 1 (Continued)
l And the RoundPeg class:
/**
* The RoundPeg class.
* This is the Adaptee class.
*/
public class RoundPeg {
public void insertIntoHole(String msg) {
System.out.println("RoundPeg insertIntoHole(): " + msg);
}
}
l If a client only understands the SquarePeg interface for inserting
pegs using the insert() method, how can it insert round pegs? A
peg adapter!
Bob Tarr Design Patterns In Java The Adapter Pattern
9
Adapter Pattern Example 1 (Continued) Adapter Pattern Example 1 (Continued)
l Here is the PegAdapter class:
/**
* The PegAdapter class.
* This is the Adapter class.
* It adapts a RoundPeg to a SquarePeg.
* Its interface is that of a SquarePeg.
*/
public class PegAdapter extends SquarePeg {
private RoundPeg roundPeg;
public PegAdapter(RoundPeg peg) {this.roundPeg = peg;}
public void insert(String str) {roundPeg.insertIntoHole(str);}
}
Bob Tarr Design Patterns In Java The Adapter Pattern
10 10
Adapter Pattern Example 1 (Continued) Adapter Pattern Example 1 (Continued)
l Typical client program:
// Test program for Pegs.
public class TestPegs {
public static void main(String args[]) {
// Create some pegs.
RoundPeg roundPeg = new RoundPeg();
SquarePeg squarePeg = new SquarePeg();
// Do an insert using the square peg.
squarePeg.insert("Inserting square peg...");
Bob Tarr Design Patterns In Java The Adapter Pattern
11 11
Adapter Pattern Example 1 (Continued) Adapter Pattern Example 1 (Continued)
// Now we'd like to do an insert using the round peg.
// But this client only understands the insert()
// method of pegs, not a insertIntoHole() method.
// The solution: create an adapter that adapts
// a square peg to a round peg!
PegAdapter adapter = new PegAdapter(roundPeg);
adapter.insert("Inserting round peg...");
}
}
l Client program output:
SquarePeg insert(): Inserting square peg...
RoundPeg insertIntoHole(): Inserting round peg...
Bob Tarr Design Patterns In Java The Adapter Pattern
12 12
Adapter Pattern Example 2 Adapter Pattern Example 2
l Notice in Example 1 that the PegAdapter adapts a RoundPeg to a
SquarePeg. The interface for PegAdapter is that of a SquarePeg.
l What if we want to have an adapter that acts as a SquarePeg or a
RoundPeg? Such an adapter is called a two-way adapter.
l One way to implement two-way adapters is to use multiple
inheritance, but we can't do this in Java
l But we can have our adapter class implement two different Java
interfaces!
Bob Tarr Design Patterns In Java The Adapter Pattern
13 13
Adapter Pattern Example 2 (Continued) Adapter Pattern Example 2 (Continued)
l Here are the interfaces for round and square pegs:
/**
*The IRoundPeg interface.
*/
public interface IRoundPeg {
public void insertIntoHole(String msg);
}
/**
*The ISquarePeg interface.
*/
public interface ISquarePeg {
public void insert(String str);
}
Bob Tarr Design Patterns In Java The Adapter Pattern
14 14
Adapter Pattern Example 2 (Continued) Adapter Pattern Example 2 (Continued)
l Here are the new RoundPeg and SquarePeg classes. These are
essentially the same as before except they now implement the
appropriate interface.
// The RoundPeg class.
public class RoundPeg implements IRoundPeg {
public void insertIntoHole(String msg) {
System.out.println("RoundPeg insertIntoHole(): " + msg);
}
}
// The SquarePeg class.
public class SquarePeg implements ISquarePeg {
public void insert(String str) {
System.out.println("SquarePeg insert(): " + str);
}
}
Bob Tarr Design Patterns In Java The Adapter Pattern
15 15
Adapter Pattern Example 2 (Continued) Adapter Pattern Example 2 (Continued)
l And here is the new PegAdapter:
/**
* The PegAdapter class.
* This is the two-way adapter class.
*/
public class PegAdapter implements ISquarePeg, IRoundPeg {
private RoundPeg roundPeg;
private SquarePeg squarePeg;
public PegAdapter(RoundPeg peg) {this.roundPeg = peg;}
public PegAdapter(SquarePeg peg) {this.squarePeg = peg;}
public void insert(String str) {roundPeg.insertIntoHole(str);}
public void insertIntoHole(String msg){squarePeg.insert(msg);}
}
Bob Tarr Design Patterns In Java The Adapter Pattern
16 16
Adapter Pattern Example 2 (Continued) Adapter Pattern Example 2 (Continued)
l A client that uses the two-way adapter:
// Test program for Pegs.
public class TestPegs {
public static void main(String args[]) {
// Create some pegs.
RoundPeg roundPeg = new RoundPeg();
SquarePeg squarePeg = new SquarePeg();
// Do an insert using the square peg.
squarePeg.insert("Inserting square peg...");
// Create a two-way adapter and do an insert with it.
ISquarePeg roundToSquare = new PegAdapter(roundPeg);
roundToSquare.insert("Inserting round peg...");
Bob Tarr Design Patterns In Java The Adapter Pattern
17 17
Adapter Pattern Example 2 (Continued) Adapter Pattern Example 2 (Continued)
// Do an insert using the round peg.
roundPeg.insertIntoHole("Inserting round peg...");
// Create a two-way adapter and do an insert with it.
IRoundPeg squareToRound = new PegAdapter(squarePeg);
squareToRound.insertIntoHole("Inserting square peg...");
}
}
l Client program output:
SquarePeg insert(): Inserting square peg...
RoundPeg insertIntoHole(): Inserting round peg...
RoundPeg insertIntoHole(): Inserting round peg...
SquarePeg insert(): Inserting square peg...
Bob Tarr Design Patterns In Java The Adapter Pattern
18 18
Adapter Pattern Example 3 Adapter Pattern Example 3
l This example comes from Roger Whitney, San Diego State
University
l Situation: A Java class library exists for creating CGI web server
programs. One class in the library is the CGIVariables class
which stores all CGI environment variables in a hash table and
allows access to them via a get(String evName) method. Many
Java CGI programs have been written using this library. The
latest version of the web server supports servlets, which provide
functionality similar to CGI programs, but are considerably more
efficient. The servlet library has an HttpServletRequest class
which has a getX() method for each CGI environment variable.
We want to use servlets. Should we rewrite all of our existing
Java CGI programs??
Bob Tarr Design Patterns In Java The Adapter Pattern
19 19
Adapter Pattern Example 3 Adapter Pattern Example 3
l Solution : Well, we'll have to do some rewriting, but let's attempt
to minimize things. We can design a CGIAdapter class which has
the same interface (a get() method) as the original CGIVariables
class, but which puts a wrapper around the HttpServletRequest
class. Our CGI programs must now use this CGIAdapter class
rather than the original CGIVariables class, but the form of the
get() method invocations need not change.
Bob Tarr Design Patterns In Java The Adapter Pattern
20 20
Adapter Pattern Example 3 (Continued) Adapter Pattern Example 3 (Continued)
l Here's a snippet of the CGIAdapter class:
public class CGIAdapter {
Hashtable CGIVariables = new Hashtable(20);
public CGIAdapter(HttpServletRequest CGIEnvironment) {
CGIVariables.put("AUTH_TYPE", CGIEnvironment.getAuthType());
CGIVariables.put("REMOTE_USER", CGIEnvironment.getRemoteUser());
etc.
}
public Object get(Object key) {return CGIvariables.get(key);}
}
l Note that in this example, the Adapter class (CGIAdapter) itself
constructs the Adaptee class (CGIVariables)
Bob Tarr Design Patterns In Java The Adapter Pattern
21 21
Adapter Pattern Example 4 Adapter Pattern Example 4
l Consider a utility class that has a copy() method which can make
a copy of an vector excluding those objects that meet a certain
criteria. To accomplish this the method assumes that all objects
in the vector implement the Copyable interface providing the
isCopyable() method to determine if the object should be copied
or not.
BankAccount
VectorUtilities
Copyable Interface
isCopyable()
Bob Tarr Design Patterns In Java The Adapter Pattern
22 22
Adapter Pattern Example 4 (Continued) Adapter Pattern Example 4 (Continued)
l Here�s the Copyable interface:
public interface Copyable {
public boolean isCopyable();
}
l And here�s the copy() method of the VectorUtilities class:
public static Vector copy(Vector vin) {
Vector vout = new Vector();
Enumeration e = vin.elements();
while (e.hasMoreElements()) {
Copyable c = (Copyable) e.nextElement();
if (c.isCopyable())
vout.addElemet(c);
}
return vout;
}
Bob Tarr Design Patterns In Java The Adapter Pattern
23 23
Adapter Pattern Example 4 (Continued) Adapter Pattern Example 4 (Continued)
l But what if we have a class, say the Document class, that does not
implement the Copyable interface. We want to be able perform a
selective copy of a vector of Document objects, but we do not
want to modify the Document class at all. Sounds like a job for
(TA-DA) an adapter!
l To make things simple, let�s assume that the Document class has
a nice isValid() method we can invoke to determine whether or
not it should be copied
Bob Tarr Design Patterns In Java The Adapter Pattern
24 24
Adapter Pattern Example 4 (Continued) Adapter Pattern Example 4 (Continued)
l Here�s our new class diagram:
VectorUtilities
Copyable Interface
isCopyable()
Document
isValid()
DocumentAdapter
Bob Tarr Design Patterns In Java The Adapter Pattern
25 25
Adapter Pattern Example 4 (Continued) Adapter Pattern Example 4 (Continued)
l And here is our DocumentAdapter class:
public class DocumentAdapter implements Copyable {
private Document d;
public DocumentAdapter(Document d) {
document = d;
}
public boolean isCopyable() {
return d.isValid();
}
}
Bob Tarr Design Patterns In Java The Adapter Pattern
26 26
Adapter Pattern Example 5 Adapter Pattern Example 5
l Do you see any Adapter pattern here?
public class ButtonDemo {
public ButtonDemo() {
Button button = new Button("Press me");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
doOperation();
}
});
}
public void doOperation() { whatever }
}
Bob Tarr Design Patterns In Java The Adapter Pattern
27 27
Adapter Pattern Example 5 (Continued) Adapter Pattern Example 5 (Continued)
l Button objects expect to be able to invoke the actionPerformed()
method on their associated ActionListener objects. But the
ButtonDemo class does not have this method! It really wants the
button to invoke its doOperation() method. The anonymous inner
class we instantiated acts as an adapter object, adapting
ButtonDemo to ActionListener!
l Recall that there are some AWT listener interfaces that have
several methods which must be implemented by an event listener.
For example, the WindowListener interface has seven such
methods. In many cases, an event listener is really only interested
in one specific event, such as the Window Closing event.
Bob Tarr Design Patterns In Java The Adapter Pattern
28 28
Adapter Pattern Example 5 (Continued) Adapter Pattern Example 5 (Continued)
l Java provides �adapter� classes as a convenience in this situation.
For example, the WindowAdapter class implements the
WindowListener interface, providing �do nothing�
implementation of all seven required methods. An event listener
class can extend WindowAdapter and override only those
methods of interest
l And now we see why they are called adapter classes!
[ June 20, 2004: Message edited by: Jacques Bosch ]
 
 
subject: NX: Remote/IOException in DBServices interface (Ken...?)
 
Similar Threads
NX: Binding / server object / stub (Ken again...)