Win a copy of The Little Book of Impediments (e-book only) this week in the Agile and Other Processes forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

getConnection throwing NotSerializableException

 
dean tomlinson
Ranch Hand
Posts: 94
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
i'm getting a NotSerializableException with regards to Data, from my connectionfactory's getConnection method.
i didn't think the shared database (data) would need to be serializable, becasue both the connctionfactory (which instatiates the data object) and connection objects (that get passed the data object in their constructor) both live on the server.
any ideas ? thanks a lot - dean
 
Sai Prasad
Ranch Hand
Posts: 560
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
In your case, since the connection object has an instance of Data and the RMI system has to marshall the connection object correctly, it needs to serialized. But remember, what you get is a copy of Data and not the reference. So if you invoke methods in Data, it is always going to use the local database.
I would create a private getDataInstance() method in the connection object and make the connection object stateless. The getDataInstance() will get the Data instance through some other Factory class. In this case, you don't have to serialize the Data class.
 
dean tomlinson
Ranch Hand
Posts: 94
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi sai- thanks for your help.
In your case, since the connection object has an instance of Data

what you get is a copy of Data and not the reference

i must have misunderstood the meaning of passing a reference to the shared data object, to each of the connection objects.
can you explain how i would hold a reference to the shared data object, without passing it in the constructor, and then holding it as a member of the connection object ?
thanks a lot - dean
 
Sai Prasad
Ranch Hand
Posts: 560
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Make your remote connection object stateless. It shouldn't hold any instance of any object which you don't want to Serialize as a member variable. Whenever you need a reference to the shared Data instance in the connection object, you call a synchronized method in a Factory class to return you the shared Data instance. Hope that helps.
If you want a reference of a remote object at the gui client, that remote object's class should implement java.rmi.Remote interface and extend UnicastRemoteObject. I am sure you have done this on your connection and connection factory classes.
[ May 11, 2002: Message edited by: Sai Prasad ]
 
dean tomlinson
Ranch Hand
Posts: 94
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
thanks again sai - i'll give it a go
 
dean tomlinson
Ranch Hand
Posts: 94
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi sai,
i've changed the constructor for my connection object so it now only has a reference to the connectionfactory/dataserver.
should i refer to this object by it's implementation class or it's rmi interface type ?
when object's such as these that both reside in the same server jvm - is it possible to bypass rmi and access them via their implementation class and not the remote interface they are implementing. or once an object is flagged as remote, does the jre always expect to use the object via it's remote interface ?
if have to use the connectionfactroy/dataserver via it's rmi interface, in the connection object, i will have to expose the getDataBase, getLockManager methods in this public interface, which could then be called out of context by a future application developer?
cheers - dean
 
Sai Prasad
Ranch Hand
Posts: 560
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi sai,
i've changed the constructor for my connection object so it now only has a reference to the connectionfactory/dataserver.

Why your connection object has to know about the connection factory instance?

should i refer to this object by it's implementation class or it's rmi interface type ?

RMI interface type.

when object's such as these that both reside in the same server jvm - is it possible to bypass rmi and access them via their implementation class and not the remote interface they are implementing. or once an object is flagged as remote, does the jre always expect to use the object via it's remote interface ?

You can instantiate it just like any Java objects as long as they all live in the same VM. When you refer the remote objects outside their VM, you should use the Remote interface.

if have to use the connectionfactroy/dataserver via it's rmi interface, in the connection object, i will have to expose the getDataBase, getLockManager methods in this public interface, which could then be called out of context by a future application developer?
You don't have to include all the methods in the public interface. So don't include those methods in the public interface.
 
dean tomlinson
Ranch Hand
Posts: 94
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi sai,
Whenever you need a reference to the shared Data instance in the connection object, you call a synchronized method in a Factory class to return you the shared Data instance.

my interpretation of this was that i should hold a reference to the connectionfactory in my connection objects. i would then add the synchronised methods getDataBase and getLockManager to the connectionfactory - like you suggest. in my design the connectionfactroy is the data server.
i hope this answers your question ...
Why your connection object has to know about the connection factory instance?

but at the same time your response has made me think, again, i am missing something... any clues ?
 
Sai Prasad
Ranch Hand
Posts: 560
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Dean,
I don't know why you need getDataBase() in your
data server which is also referred by you as connection factory. Think about the flow below.
ConnectionFactory -> Connection -> LockManager ->Data

ConnectionFactory is a Singleton, Connection instance is unique to a client, LockManager is a Singleton and Data is a Singleton per table.
Connection object uses a factory called DataFactory which has a static method to return you the Data instance based on the database file name. You then pass the Data instance to the LockManager to do lock/unlock/modify/delete.
In the local mode, your client side Facade uses the same DataFactory to give you the Data instance. So I would put DataFactory and Data in the suncertify.db package.
One more clue...The only member variable in the Connection class is the database file name which is passed as the configuration parameter from the command line.
[ May 11, 2002: Message edited by: Sai Prasad ]
 
dean tomlinson
Ranch Hand
Posts: 94
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi sai - thanks a lot for your advise - i went away and had a think abuot what you have said. here's my understanding...
becasue the Connection object is a return value from the (remote) ConnectionFactory's getConnection method, the Connection object must be serializable (so must all method parameters).
also any objects we pass to the Connection object in it's constructor will be passed by value not reference, so if we did try and pass the shared Data instance to the Connection object, for internal storage, it would no longer be the actual shared database.
OK - I'm now using the DataAccessFactroy on the server side too, everytime i want to access the shared database. I have the private method in my connection class, that attempts to get a handle to the shared database using the following...

/**
* you cannot hold anything as a member, that you do not want to serialize
* and pass over the wire. therefore, i use this private method within
* each of my public methods to get a handle to the shared database.
*/
private DataAccess getSharedDatabase() throws DataAccessException
{
String operatingMode = "S";
String databaseFileName = "db.db";
DataAccessFactory factory = DataAccessFactory.getFactory();

return factory.getDataAccessInstance(operatingMode,databaseFileName);
}

however this seems to be running in the client JVM and not the server JVM? as i am getting classes / db.db not found on the client side
any ideas ?
 
Sai Prasad
Ranch Hand
Posts: 560
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Dean,
becasue the Connection object is a return value from the (remote) ConnectionFactory's getConnection method, the Connection object must be serializable (so must all method parameters).

Not really. Connection class can extend UnicastRemoteObject and implement java.rmi.Remote to be returned to the client as a reference.

also any objects we pass to the Connection object in it's constructor will be passed by value not reference, so if we did try and pass the shared Data instance to the Connection object, for internal storage, it would no longer be the actual shared database.

Why do you pass the Data instance to the Connection object constructor? Instead, pass the db file name from the connection factory to the Connection object constructor. Then you use the private getDataInstance() in the Connection object to get the appropriate Data instance using a Factory.

however this seems to be running in the client JVM and not the server JVM? as i am getting classes / db.db not found on the client side
any ideas?

Since you made the Connection object Serializable, it is getting passed as a copy and
not as a reference. That's why local db is used.
[ May 12, 2002: Message edited by: Sai Prasad ]
[ May 12, 2002: Message edited by: Sai Prasad ]
 
dean tomlinson
Ranch Hand
Posts: 94
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi sai - you can ignore my last question if you wish - it now works !
the problem seems to have been due to the fact that my connection object was not extending unicastremoteobject.
i blame the mastering rmi book i've got in front of me. it says in there - if you do not plan to use your remote objects in hashtable, where proper implementation of equals, hashcode, tostring is crucial, you do not need to subclass unicastremoteobject.
anyway thanks for all your help this weekend. i was planning to finih it off this weekend, but haven't really achieved too much. every weekend, the more i learn, the more i feel like i'm gonna be working on this all summer
cheers dean
 
dean tomlinson
Ranch Hand
Posts: 94
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi sai,
does your dataaccessfactroy hold an instance of the shared data object? i have not done this yet and everytime i call the private getDatabase method in my connection object, it inturn calls the dataaccessfactroy, which inturn create's a new instance. (i know that object instantiation is one of the things to try and minimise to improve application speed).
is the dataaccessfactroy the best place to hold the instance of the shared data object ?
something inside me still think's that it is more logical to hold the shared data instance within the data server (i use the term interchangably with connection factory in my design).
i think now that my connection extends the unicastremoteobject, and is therefore being properly recoginsed and treated as a remote object, i can pass the shared data object to the connection objects constructor's ?
i know you have tried to stear me away from this throughout your replies, but assuming my above understanding is correct (which it probably aint : ) ), i think interacting with the dataaccessfactroy every time you need to call a method on data is going to cause much more execution cycles.
in my flightservicesfacade.getFlights method for example, it needs to make many method calls on data such as getRecordCount, and then getRecord for every recrod in the table - therefroe 25 calls to the dataaccessfactroy !
what's your take on this ? cheers mate
 
Sai Prasad
Ranch Hand
Posts: 560
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I had a static Hashtable to keep the instance(s) of Data. In the future, if more tables are added, this Hashtable can expand to suit the needs. Also when someone needs a list of all the Data instances, you can return a immutable Enumeration version of the Hashtable so no one can alter it. That is the only reason to use Hashtable instead of recent Collection classes.
It is ok to call the getDataInstance() method as many times as you want. User will not see any slow down in the application performance since it is a local call.
 
dean tomlinson
Ranch Hand
Posts: 94
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi sai,
first of all - thanks for all your help this weekend. i know you have been on here pretty much all weekend helping. where are you based by the way? i'm in bournemouth on the south coast of england.
can i ask you to comment on the following - just so i can be totally sure of the casue of my earlier problems with rmi...
i think now that my connection extends the unicastremoteobject, and is therefore being properly recoginsed and treated as a remote object, i can pass the shared data object to the connection objects constructor's ?

cheers - dean
 
Sai Prasad
Ranch Hand
Posts: 560
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Dean,
You are welcome. I am preparing for the tomorrow's dev exam. I am based in Des Moines, IA, USA. I enjoy doing this.
You can pass the shared Data instance to the Connection object constructor. But remember, that your Data instance has to be Serialized and RMI has to marshal the Data instance as well to the client which I think is unnecessay. During the marshaling only the copy of Data is transfered to the client. The real instance of Data resides on the server.
Also the real instance of ConnectionFactory and Connection resides in the server machine. The client uses _Stub instances to talk to the remote objects which lives on the server. Each of the _Stub instance has the IP address and port information to locate the corresponding remote object.
 
dean tomlinson
Ranch Hand
Posts: 94
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi sai,
good luck with the exam tommorow ! but i'm sure it will be a walk in the park for you. how's Des Moines been today ? it's been sunny over here - unfortunatlely my laptop screen goes really dark outdoors - so i've been stuck inside.
You can pass the shared Data instance to the Connection object constructor. But remember, that your Data instance has to be Serialized and RMI has to marshal the Data instance as well to the client which I think is unnecessay. During the marshaling only the copy of Data is transfered to the client. The real instance of Data resides on the server.

i have come across a section titled "Remote Object Replacement" in my RMI book. it says the following...
marshalling in rmi uses regular serialization to a great extent, but there is one exception, namely how remote objects are handled.
For example, if a method parameter or result value of a method invocation in RMI is a remote object, that is, it implements a remote interface and is exported by the RMI implementation, you would not want it to be serialized.
What you really want to do is send the stub instead of the remote object, which can be used at the otherend to call methods on your remote object.

it then goes on to sy that rmi basically does this automatically when remote objects are involved as method parameters, return values.
does this mean that when my dataaccessfactroy calls the dataserver's getconnection method, and it returns the connection object's stub, that the connection object was not serialized ?
if it wasn't serialized, does this mean that the shared data instance held by the connection object, would be the actual shared database and not a copy ??
if you can answer this one - i promise i wont ask you any more questions about rmi. as you can no doubt guess - this is the first time i've used rmi.
cheers - dean
 
Sai Prasad
Ranch Hand
Posts: 560
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Dean,
You need to read the RMI Specification. Except for the Activation part, I learnt a lot from the specification.
When a class implements the java.rmi.Remote marker interface, it is flagged as a Remote object so that client can invoke methods on it. Remote object also extends UnicastRemoteObject to be able to export itself so that it can be marshaled correctly.
A client can get an instance of the remote object either by looking up in the RMI Registry or return from a method call. Either way, if the object *only* implements java.io.Serializable, the client gets only the copy of the object and not the reference.
In your case, the RMI runtime at the client can use the _Stub which is available locally (I didn't use dynamic downloading using codebase) and populate the _Stub instance with the serialized data from the server. This _Stub class also implements your remote interface. So for your client it is as good as the remote object. _Stub instance is a proxy to the remote instance.
Coming to your question, your connection object lives only in the server which holds an instance of the Data. This Data instance is neither a copy nor _Stub but the real reference. When you invoke a method on the remote connectino object (actually the _Stub), it communicates with the server and makes the call on the remote object running on ther server. In that case, the Data instance residing in the server is used and not the local Data instance.
You normally Serialize the class if you want to populate the values and send it over the wire during a remote call on a remote object which implements java.rmi.Remote and extends the UnicastRemoteObject.
Hope that helps.
 
dean tomlinson
Ranch Hand
Posts: 94
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi sai,
Coming to your question, your connection object lives only in the server which holds an instance of the Data. This Data instance is neither a copy nor _Stub but the real reference. When you invoke a method on the remote connectino object (actually the _Stub), it communicates with the server and makes the call on the remote object running on ther server. In that case, the Data instance residing in the server is used and not the local Data instance.

from this i read that i Can hold a reference to the SharedData object in each of my Connection object's, and the Connection objects will be holding a referecne to the actual shared data object and not copies of it.
how did your exam go ? if you've nottaken it just yet - best of luck
 
Sai Prasad
Ranch Hand
Posts: 560
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes. Connection object will have a reference and not a copy. The exam was easy compared to the assignment!
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic