aspose file tools*
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes FBN: changing lock method's IOException Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "FBN: changing lock method Watch "FBN: changing lock method New topic
Author

FBN: changing lock method's IOException

Ronald Oltmans
Greenhorn

Joined: Aug 17, 2003
Posts: 12
I have put all the public method's of the Data class in the interface DataInterface. All public method's of the Data class throw a DatabaseException except for the lock method.

Because I execute all the locking and unlocking by means of a LockManager in the server code, I want my lock and unlock code in the Data class only to check if the supplied record number is in the range of valid values.
The IOException doesn't play a role in here. Is it a good idea to change the IOException to a DatabaseException ?
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11460
    
  94

Hi Ronald
Welcome to JavaRanch.
My personal feeling is that it should not be changed.
My reasoning is that Sun provided us with specific classes and a pre populated database. If this were a real client, then we should assume that they somehow got the data into the database, therefore logically they must have at least one other application that can read / write to that file, probably through the Data class. If we change the Data class's method signatures, then we may break the other application(s). I don't think any client would be happy if we did this.
The new assignments (Bodgitt & Scarper (contractors) and UrlyBird (Hotel)) have a statement that automated testing tools will be used to verify the submission. Although there is no such statement in FBNS, they could have automated tools to test the modifications to the Data class or the networked interface. So this fits in with my earlier statement about not changing signatures: if we do that, we could stop the automated tools from working.
All my reasoning is dubious, but do you want to risk it?
Regards, Andrew


The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
Ronald Oltmans
Greenhorn

Joined: Aug 17, 2003
Posts: 12
Andrew,
Thank you for your reply. I also don't like changing the signature of a class provided by Sun.
But what is puzzling me is the javadoc.

I read this as "check if the recordnumber is valid (in the range of recordnumbers in the DB) and if not throw an IOException". Maybe it's my interpretation that is wrong. How do you read this ?
On the other hand in the Data method getRecord(int recNum), I have the following code:

This is mostly the code I want to use in my lock method, but it throws a DatabaseException. Not very consistent with the IOException of the lock method, which in my interpretation does the same.
All the other public methods in Data class wrap the IOException and throw a DatabaseException, so it's a shame that we can't convert lock to throw a DatabaseException.
Is it my interpretation that is wrong or is the code of Sun inconsistent (by which purpose ?)?
Kind regards,
Ronald
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11460
    
  94

Hi Ronald
You are correct: the code supplied by Sun is inconsistant.
They may have done this deliberately in order to see whether we can meet requirements that we don't like or do not agree with.
Alternatively they may be wanting to see how we deal with inconsistancies.
Regards, Andrew
Damian Ryan
Ranch Hand

Joined: May 09, 2003
Posts: 117
Ronald
I had the same question when I did the FBN assignment and I decided, contrary to what Andrew has said, to go ahead and change the lock method to throw a DatabaseException instead of an IOException.
My justification is that an IOException gives the wrong message. It suggests to a client object what the underlying implementation might be (which is not good - this is none of the client object's business) and is also quite likely to be misleading, as it is perfectly possible to lock records without performing any I/O operations. Additionally, having this method not throw a DatabaseException is inconsistent with the rest of the class's methods.
I made an argument along these lines in my design choices (I can't remember exactly what I said, but that was the gist of it) and did not lose any marks because of it.
As Andrew said, a good deal of what you are being assessed on is how you deal with the inconsistencies and other problems facing you in the design and implementation you inherit. Remember, there is no right or wrong answer; what should impress the assessor is your ability to justify the choices you have made and to be consistent in the way you have made those choices.


Always proofread carefully to see if you any words out.
Ronald Oltmans
Greenhorn

Joined: Aug 17, 2003
Posts: 12
Damian thanks,
I agree with you that it is perfectly possible to lock records without performing any I/O operations. I think that leaves to options:
1. putting no code in the lock and unlock method's of the Data class at all and leaving the IOException as is. This breaks the requirement that the lock and unlock methods should be implemented.
2. Give the lock and unlock methods an implementation (although it is validation and no explicit locking code, because locking is done in my lock manager) and changing the IOException to a DatabaseException. This breaks the "implicit" requirement that we should not change the signature of code provided by Sun.
What is the best choice ?
Damian, did you also add a DatabaseException to the unlock method of the Data class to do the same validation as in the lock method ?
Kind regards,
Ronald
Bharat Ruparel
Ranch Hand

Joined: Jul 30, 2003
Posts: 493
Hello Ron,
This is how I am handling the exception restriction in my assignment (URLyBird 1.3.1):
public void lock(int recNo) throws RecordNotFoundException {
....
try {
lockedRecords.wait();
} catch (InterruptedException e) {
throw new RecordNotFoundException(e.getMessage());
}
....
}

In the above code snippet, you see that I am required to throw RecordNotFound exception in my lock method. The wait method throws InterruptedException which either needs to be caught or declared. We cannot declare it for the obvious reasons, therefore catch it and rethrow it as RecordNotFoundException. You can do the same for DatabaseException.
Regards.
Bharat


SCJP,SCJD,SCWCD,SCBCD,SCDJWS,SCEA
Ronald Oltmans
Greenhorn

Joined: Aug 17, 2003
Posts: 12
Hello Bharat,
Although our assignments are different I see your point. The difference is that I got an IOException in the signature of my lock method and wrapping for example an InterruptedException in an IOException isn't in my opinion the way to go.
But you are raising another good question about InterruptedExceptions that plays in my mind and probably worth another thread:
I have a lock manager class in my server code that handles the locking and the lock method of the lock manager has the same code you wrote:

I wanted my remote implementation of the lock method first call the "local" lock method of Data to do some validation and then call the lock manager's lock method to do the actual locking. If the "local" lock method of the Data class would throw a DatabaseException (the reason I started this thread), I could also easily let the lockmanager's lock method throw a DatabaseException in which I wrap the InterruptedException the same way you do. In this way only DatabaseExceptions will be exposed to the clients and I think that is a consistent implementation.
I am vary curious why you choose to throw the RecordNotFoundException in the catch of the InterruptedException. Why didn't you leave it blank or throw a RuntimeException for example ? (What I said this should be really the subject of another thread )
Kind regards,
Ronald
Tony Collins
Ranch Hand

Joined: Jul 03, 2003
Posts: 435
I assert false for an Interuptted Exception it should never happen.
Bharat Ruparel
Ranch Hand

Joined: Jul 30, 2003
Posts: 493
Hello Ron,
Glad to be of help.
Your quote is as follows:

I wanted my remote implementation of the lock method first call the "local" lock method of Data to do some validation and then call the lock manager's lock method to do the actual locking. If the "local" lock method of the Data class would throw a DatabaseException (the reason I started this thread), I could also easily let the lockmanager's lock method throw a DatabaseException in which I wrap the InterruptedException the same way you do. In this way only DatabaseExceptions will be exposed to the clients and I think that is a consistent implementation.
I am vary curious why you choose to throw the RecordNotFoundException in the catch of the InterruptedException. Why didn't you leave it blank or throw a RuntimeException for example ? (What I said this should be really the subject of another thread )

I am wrapping the InterruptedException in RecordNotFoundException for the same reason as you mention above. This is a part of my assignment's interface contract. I suspect that run wants us to expose a consistent interface to the client.
My assignement's interface lists public methods with the RecordNotFoundInterface (do be defined by us) such as:
public void update(int recNo, String [] data) throws RecordNotFoundException;
You can see that this is my only alternative given the specs. Somehow, I have trouble throwing RuntimeException from a method. I prefer throwing a user defined checked exception. I may be wrong though.
Regards.
Bharat
Ronald Oltmans
Greenhorn

Joined: Aug 17, 2003
Posts: 12
Bharat,
Your solution is certainly not wrong. I only wanted to know the reason behind your choice. I think it is even the best solution.
I think there are three main options:
1. Leaving the catch empty, so if an interrupt occurs, you are ignoring it and stil trying to catch the lock.
2. Throwing a RuntimeException, not supporting any interrupts
(What about Thread.currentThread.interrupt() ??), or
3. supporting interrupts by wrapping the exception and throwing some kind of new exception to the client. In a next iteration of the project we can
support interruption in this way.
Is there anybody that can provide me with pro's and con's ?
Tony, can you elobarate on this ?
Kind regards,
Ronald
Damian Ryan
Ranch Hand

Joined: May 09, 2003
Posts: 117
Ronald,
I didn't use a lock manager - I provided the implementation for locking and locking within the empty methods provided by Sun. But this is not an important detail, I think. Whether you provide the implementation in a separate class and delegate the locking to that from the lock and unlock methods of Data shouldn't matter, IMHO.
I'm not quite sure though if this is how you're doing it. Does your client still invoke the lock/unlock methods of whatever interface it uses to access the services of the database? Or do you have a client explicity interact with a separate lock manager class? I would go for the first option, personally, because this preserves most of the intention of the provided API.
To answer your second question, I didn't change the unlock method, no. I was happy to leave it that if an unlock was called legally (i.e. by a client that held a lock on the record) then things proceeded as expected, and if an unlock was requested on a record that was not locked the request was ignored (as per the documentation provided).
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11460
    
  94

Hi Ronald,
I think there are three main options:
1. Leaving the catch empty, so if an interrupt occurs, you are ignoring it and stil trying to catch the lock.
2. Throwing a RuntimeException, not supporting any interrupts
(What about Thread.currentThread.interrupt() ??), or
3. supporting interrupts by wrapping the exception and throwing some kind of new exception to the client. In a next iteration of the project we can
support interruption in this way.
Is there anybody that can provide me with pro's and con's ?

If you go with Damian's suggestion, and change the signature of lock() to throw DatabaseException, then you could wrap the InterruptedException inside a DatabaseException.
Personally I agree with Tony: InterruptedException should never occur and should not need to be supported. Using an assertion as Tony did makes it clear to the junior programmer that you don't believe that it needs to be supported.
After all the instructions tell us that a call to lock() should block until the lock is granted - nothing about interrupting it in any way.
Regards, Andrew
Damian Ryan
Ranch Hand

Joined: May 09, 2003
Posts: 117
I agree absolutley with Andrew on the issue of InterruptedException. The API documentation states that lock should block until the requested lock is achieved, so I don't think this should be embedded into a DatabaseException. I also agree with his comments about asserting that no such exception should occur.
To just explain again why I took the decision to replace the existing IOException with a DatabaseException: I think it makes sense for a database to throw a DatabaseException when some precondition is not met or its services fail. Throwing more specialised exceptions yields clues (that can potentially mislead) about implementation which is not good OO design. If your implementation were indeed to use some form of I/O to perform locking/unlocking (though I can't see why anyone would do it in such a way) then I would maintain that a DatabaseException be thrown, with the IOException chained.
Max Habibi
town drunk
( and author)
Sheriff

Joined: Jun 27, 2002
Posts: 4118
Updated: I'm notwith Damian(sorry):
I misread the original. I'm with Andrew now
IMO, it's bad policy to change the method signaturesL: if Sun failed you on the spot because you didn't code to the methods given there would really be nothing you could say. Of course, they probably won't, but I don't advocate risking it. just MO.
I though Damian was talking about throwing a Business level DataException, from the middle of the application to the GUI. As it, it sounds he's talking about a two-tier application: one for the business logic and database access, and another for GUI stuff. I've always been an advocate of Three Tier designs: Thus, one layer for the system level stuff(the DB access, etc). Another layer just for business rules, and a third for presentation( in this case, the GUI). It sounds like I convinced myself that Damian was saying that he was following the latter paradigm, and that he throwing an IOException from the system layer to the business layer, and throwing a DataBase Exception from the Business layer to the GUI layer. This I agree with, but it's not @ all what Damian wrote. Sorry for causing any confusion.
M
[ August 20, 2003: Message edited by: Max Habibi ]

Java Regular Expressions
Ronald Oltmans
Greenhorn

Joined: Aug 17, 2003
Posts: 12
Thank you guys for all your responses !
By an assertion do you mean the keyword assert like in the following statement (just asking to assure I interpret your english in the right way):

Damian wrote:
Does your client still invoke the lock/unlock methods of whatever interface it uses to access the services of the database?

This is exactly what I am doing.
I provided the implementation for locking and locking within the empty methods provided by Sun.

How did you assure that only the client that has locked a record may unlock the record ? Did you do this by providing each Client one instance of the RemoteData class and one instance of the Data class or by providing each client one instance of the RemoteData (some call it Connection) class and a shared instance of the Data class for all the clients. In the latter case there is only one instance of the Data class for all the clients ?
Max wrote:
I'm with Damian.

Max, do you mean on both subjects, the interface subject and the InterruptedException subject ?
Max, I read your book and I must admit that it has strongly pushed me in the right direction because it marks out the requirements of the exam very well. my compliments.
Then it leaves me to congratulate Andrew what his bartenderness.
I hope he will provides us with lots of cool drinks in these hot days !
Regards,
Ronald
[ August 26, 2003: Message edited by: Andrew Monkhouse ]
Damian Ryan
Ranch Hand

Joined: May 09, 2003
Posts: 117
By an assertion do you mean the keyword assert like in the following statement (just asking to assure I interpret your english in the right way):

Yes.
How did you assure that only the client that has locked a record may unlock the record ?

I'm afraid my approach wouldn't be applicable for your situation, because I didn't use RMI (I like to be different ). Instead, I used object serialization over sockets, with a dedicated thread per client server side. Thus I could guarantee that if a thread (representing a client) tried to unlock a record, it only could if it had been the thread that had previously gained the lock. This is fairly trivial to do by storing thread references in a hashtable. However, from what I understand of RMI (and that's not all I could or should ), the RMI runtime is resposnsible for allocating threads on the server side to handle clients' remote method invocations, and you can't guarantee that it'd be the same thread handling the unlock invocation as the lock invocation.
There are other ways around the problem, however. Some people use a unique client ID system, where the client passes in its ID when it requests a lock, and only a client with an ID matching the one stored in the lock can unlock a record. This then requires a mechanism for generating unique client IDs and distributing them (for instance, a client can be assigned a unique ID by the server when it first connects).
Other people (ok, 99%+ of people here ) who used RMI in their assignment or who are RMI gurus anyway may be better able to advise you.
Ronald Oltmans
Greenhorn

Joined: Aug 17, 2003
Posts: 12
Damian,
I now clearly see one of the advantages of using sockets.
It gives you a dedicated thread per client server side. I make use of the RMI factory pattern and have a dedicated Connection object per client server side.
You can link a thread to a recordnumber in the lock method of Data, because it is there for free.
But I can't without changing my method signature, because somehow I must associate my Connection object with the recordnumber. That's way I wanted to do the locking on a higher level in my server package by means of a lock manager. I am still wondering though if it is possible to use the RMI factory pattern and make the association between the connection object and the recordnumber in the lock method of Data.
Did you also have a Data object for each client or one Data object for every client ?
Kind Regards,
Ronald
Damian Ryan
Ranch Hand

Joined: May 09, 2003
Posts: 117
Only a single Data object for everyone. A singleton, in fact. That way only one instance ever tries to access the underlying datafile at a time, because only one instance can exist per VM. (Or course this doesn't get around what would happen if someone were to start two (or more) VM's on the same machine, but hey, that's outside the scope of the assignment).
[ August 20, 2003: Message edited by: Damian Ryan ]
Bharat Ruparel
Ranch Hand

Joined: Jul 30, 2003
Posts: 493
Hello Ron,
Please see the following post for the question that you are asking Damian in the current post (I dare not use the word "thread" here! Too many treads!!!).
NX: About data consistent
In this thread, both Davidd and I are asking Andrew and Max the same question, but we don't seem to be getting it. Max has replied to my question and Andrew to Davidd's question. I am going to mull over what Max wrote today and get back to him/Andrew/Davidd tomorrow.
It seems like we are all wrestling with same issues.
My background in RMI is not that good. I have Ricard Oberg's "Mastering RMI" book that I am planning to blitz through.
Regards.
Bharat
Max Habibi
town drunk
( and author)
Sheriff

Joined: Jun 27, 2002
Posts: 4118
Updated: I'm notwith Damian(sorry):
I misread the original. I'm with Andrew now
IMO, it's bad policy to change the method signatures: if Sun failed you on the spot because you didn't code to the methods given there would really be nothing you could say. Of course, they probably won't, but I don't advocate risking it. just MO.
I though Damian was talking about throwing a Business level DataException, from the middle of the application to the GUI. As it, it sounds he's talking about a two-tier application: one for the business logic and database access, and another for GUI stuff. I've always been an advocate of Three Tier designs: Thus, one layer for the system level stuff(the DB access, etc). Another layer just for business rules, and a third for presentation( in this case, the GUI). It sounds like I convinced myself that Damian was saying that he was following the latter paradigm, and that he throwing an IOException from the system layer to the business layer, and throwing a DataBase Exception from the Business layer to the GUI layer. This I agree with, but it's not @ all what Damian wrote. Sorry for causing any confusion.
M
[ August 20, 2003: Message edited by: Max Habibi ]
Ronald Oltmans
Greenhorn

Joined: Aug 17, 2003
Posts: 12
Bharat,
I think you're right and I will post my question(s) in the thread you mentioned.
Thanks so far,
Ronald
Damian Ryan
Ranch Hand

Joined: May 09, 2003
Posts: 117
Just to clarify matters: I agree completely with Max when he describes his preference for the three-tier architecture he describes. This is in fact how I implemented my solution.
It seems we just disagree about whether or not it's acceptable to alter the signature of the methods provided by Sun. I respect Max's (and Andrew's) opinion that one should not alter the signatures. I just don't feel as strongly about it.
I would argue as follows (and all I can do is reiterate that the examiner who marked my assignment didn't mark me down for it): we know that the code we are provided is flawed. It makes deprecated method calls, it contains logical flaws, it isn't thread safe, some of the class names are obtuse (DataInfo for a record? Oh, puh-lease).
I chose to address the shortcomings in the Data class by modifying it rather than subclassing it, as others may have chosen to do. [One of my justifications, among others, for this is that the deprecated method calls took place in private methods that couldn't therefore be overridden in a subclass. Not without the cardinal sin of cut/paste editing anyway].
Under these circumstances, altering the signature of a single method doesn't really seem like a big deal to me. I cannot see any justification for insisting that the lock(int) method should throw an IOException. None. It doesn't make any implementation or business sense to me, and I have argued as much (v.s.)
So instead of declaring that the lock(int) method throws an exception that in my implementation could never arise, I chose to have it throw a DatabaseException that signalled when the database had been unable to comply with the lock request (which could happen, for instance, if the record number was bad).
I really think that if a candidate can provide a reasoned argument for their design choice that isn't just plain wrong (and I humbly suggest that mine isn't) then they should be on firm ground. After all, isn't that a great part of what the SCJD is testing - the candidate's ability to take consistent, justifiable decisions in the face of subomptimal constraints, when there is usually no black and white, right or wrong answer?
Ok, I promise to shut up now
[ August 21, 2003: Message edited by: Damian Ryan ]
Max Habibi
town drunk
( and author)
Sheriff

Joined: Jun 27, 2002
Posts: 4118
Originally posted by Damian Ryan:
Just to clarify matters: I agree completely with Max when he describes his preference for the three-tier architecture he describes. This is in fact how I implemented my solution.
It seems we just disagree about whether or not it's acceptable to alter the signature of the methods provided by Sun. I respect Max's (and Andrew's) opinion that one should not alter the signatures. I just don't feel as strongly about it.
I would argue as follows (and all I can do is reiterate that the examiner who marked my assignment didn't mark me down for it): we know that the code we are provided is flawed. It makes deprecated method calls, it contains logical flaws, it isn't thread safe, some of the class names are obtuse (DataInfo for a record? Oh, puh-lease).
I chose to address the shortcomings in the Data class by modifying it rather than subclassing it, as others may have chosen to do. [One of my justifications, among others, for this is that the deprecated method calls took place in private methods that couldn't therefore be overridden in a subclass. Not without the cardinal sin of cut/paste editing anyway].
Under these circumstances, altering the signature of a single method doesn't really seem like a big deal to me. I cannot see any justification for insisting that the lock(int) method should throw an IOException. None. It doesn't make any implementation or business sense to me, and I have argued as much (v.s.)
So instead of declaring that the lock(int) method throws an exception that in my implementation could never arise, I chose to have it throw a DatabaseException that signalled when the database had been unable to comply with the lock request (which could happen, for instance, if the record number was bad).
I really think that if a candidate can provide a reasoned argument for their design choice that isn't just plain wrong (and I humbly suggest that mine isn't) then they should be on firm ground. After all, isn't that a great part of what the SCJD is testing - the candidate's ability to take consistent, justifiable decisions in the face of subomptimal constraints, when there is usually no black and white, right or wrong answer?
Ok, I promise to shut up now
[ August 21, 2003: Message edited by: Damian Ryan ]

Not at all Damian: you're making excellent points. In a real project, I would probably argue the same points that you did, and suggest that the client reconsider. OTOH, in a real project, if my client had told me what they expected down to the method level, and that was the last conversation, then I would code it.
Or think of it this way. I'm running a couple of remote off shore projects right now, where I've designed the architecture, and given corresponding classes(along with method signatures) to different groups for implementation. To the various teams, they may seem like separate projects: but I'm designing them a specific way for a reason, and I expect my designs to be implemented. You can bet that any deviation from the specifications would break the entire application, no matter how well intentioned the programmer.
How do you think I'm going to respond if even a single Developer on the remote team changes my specs? How happy will I be? And how helpful will the programmer have been? For that matter, how much of their obligation to me will they have met? IMO, the software engineer is a craftsman, not an artist.
The general point, of course, is that this a development project, not an architecture project. Your client(Sun) told you what they want to do develop, and what they wanted you create. To a large degree, The SCJD is a demonstration of your ability to color inside the line.
That's the general case: the specific case is that you did change the signature, and you did pass. I have to say, I'm really glad that it worked out for you. However, there really is nothing you could have said if they had failed you on the spot because you didn't follow directions. I'm glad they didn't, but it just seems, IMO, too much a risk to advocate, given the amount of time, effort, and money involved in this certification. Just my opinion,
All best,
M
Damian Ryan
Ranch Hand

Joined: May 09, 2003
Posts: 117
Max,
thanks for your reply. I'll make a couple of final points and then leave this alone. I promise!
I take well the points you make in your exemplary story. And again, I find myself in complete agreement with your logic. You know there's a "but" coming, though...
I cannot speak about what Ronald, or anyone else who has received the FBN assignment got as their exact instructions, because I do not know how much each candidate's instructions will have differed from mine. But I want to come back at some of your points (and specifically the horror avowed by almost everyone else at the prospect of altering provided method signatures. Please note: I am NOT trying to carry the argument I make below across to the new format assignments, where I understand candidates are ONLY provided with interfaces, and no implementations. I wholeheartedly agree in this situation with being a good developer and programming to the interface that the designer has provided with the benefit of a global perspective on the system that might not be apparent in the narrower context within which the developer works).
In the preamble, "What this application is about" my instructions told me that my job was to develop a system from some code a student had developed while on work experience. Not a system developed with complete foresight by an experienced developer. In other words, the instructions are preparing you for the fact that you are inheriting code that is quite likely to be suboptimal in several aspects because of its provenance.
Further on, in the section "Extending Data", the first statement made is "Part of your assignment will be to enhance the Data class. You may do this by modification or subclassing, but you should document the approach and reason for your choice."
Nowhere do the instructions prohibit alteration of the signatures of the extant methods. I would argue rather that the mention of modification is an invitation to consider such a change if it is considered necessary and justifiable by the developer. And within the context of the assignment's instructions, that the developer is completely responsible for developing the system (not having to inter-operate with subsystems developed by third parties who would rely on a stable published interface) there is no absolute constraint preventing alteration of the existing code's public interface.
Like I said before, I can't comment on other people's assignments, because their instructions may have been subtly or even markedly different from mine. But I just wanted to put the contrarian point of view so that other FBN candidates (not new exam candidates - see my comments above) coming to this forum have the opportunity to see something other than the "never change the method signatures" line so that they can make their own minds up rather than just accepting orthodoxy.
Sorry to go on. I just felt that after seeing so many posts (in this thread but mainly in others where similar questions have been asked) saying "don't alter the signatures!" I had to put my two penn'orth in.
Max Habibi
town drunk
( and author)
Sheriff

Joined: Jun 27, 2002
Posts: 4118
/*
Originally posted by Damian Ryan:
Max,
thanks for your reply. I'll make a couple of final points and then leave this alone. I promise!


Don't!
I enjoy gabbing about this stuff: it's one of the reasons I'm neglecting the aforementioned project to volunteer here.
As to your point: you're correct, I am making assumptions about your assignment. One of my assumptions is that part of your FNB assignment said: "You much implement the lock... method given. failure to do so will result in immediate failure". or words to that effect. Did your assignment not have words to this effect? This isn't some Socratic trap: I'm @ the office right now, so I don't have my copy of FBN.
M
Damian Ryan
Ranch Hand

Joined: May 09, 2003
Posts: 117
Max,
here's what my version of the instructions said (under the section "Extending suncertify.db.Data"):
public void lock(int record)
public void unlock(int record)

Record locking must be implemented using the methods public void lock(int) and public void unlock(int). These methods are required to allow concurrent use of the database when booking flights from multiple clients. Note that the locking required is effectively a "write" lock only. If updates occur to a record that is being displayed on another client, then no change occurs at the other client. However, if two clients attempt to perform the sequence lock, read, modify, write, unlock concurrently, then both modification attempts will be handled correctly. The aim is to ensure that if two customers attempt to book a seat on the same flight concurrently, then the number of available seats is definitely reduced by two, unless there was only one seat, in which case, one customer will be advised at booking time that no more seats are available.
The lock method should block until the requested lock can be applied. The integer argument indicates the record to be locked. If the method is called with an argument of -1, the entire database should be locked.
The unlock method simply removes the lock from the specified record. If an attempt is made to unlock a record that has not been locked by this connection, then no action is be taken.

I interpreted these instructions as I have said because:
  • this part of the instructions explicity relating to the lock and unlock methods make no mention of the thrown exceptions, so I did not consider these to be set in stone;
  • the instructions do NOT explicitly prohibit alteration of the signatures. I would even take this as far as suggesting that (as I believe some candidates have done) extra parameters could be added, like a unique clientID (I didn't do this), as long as the candidate could provide convincing justification


  • And further, I would argue that the comments
    A clear design, such as will be readily understood by junior programmers, will be preferred to a complex one

    and, under "Marking Criteria" (General considerations):

    coding standards and readability (23)
    clarity and Maintainability maintainability of the design and implementation (12)

    positively cries out for the developer to leave the code in a "better" shape than he or she found it, to ease the task of future programmers who must understand the code before they can alter or build on it.
    (And one of the ways I felt I could make the code clearer to someone else was to remove a daft IOException from a method that had no need to throw it).
    And to reiterate, I felt justified altering the signature because I interpreted the context described in my instructions as stating that I was THE developer tasked with developing 100% of the system, and that therefore alteration of a published interface wasn't going to upset the project, because I was the only consumer of that public interface.
    You'll have gathered by now no doubt how I tend to write quite a lot when I'm trying to explain a point and I apologise for the lack of concision in my arguments. I think (well, I hope) I managed to be a bit more concise when I submitted my documentation (with the benefit of a bit more time to edit it ) but I want to make the point that I think it's very important to supply every assumption you've made so that your examiner can use this as a basis to judge your offered justifications (assuming of course, that your assumptions are not considered invalid).
    [ August 22, 2003: Message edited by: Damian Ryan ]
    Ronald Oltmans
    Greenhorn

    Joined: Aug 17, 2003
    Posts: 12
    Hello Damian, Max and the others following this discussion,
    I think my instructions for the FBNS are the same as Damian stated, so we can take this as a starting point for further discussion.
    I like the arguments Damian brought in about a junior programmer having made the code base for the project. I think he's right in saying that the code we can expect is suboptimal.
    I don't like the idea of changing the signature of the lock and unlock method to add an extra parameter like the clientId.
    I think the following statement explicitly prohibits this:

    Although I must admit that there are people that have passed with this strategy.
    It is also this statement that brings me in a deadlock situation
    On one hand we have the restriction that the client who locked the record should also unlock it. I am making use of the RMI factory approach and have a connection object per client to identify the client.
    On the other hand we have the restriction above that record locking must be implemented with the lock/unlock methods in Data.
    In the approach I was thinking of locking is done by means of a lock manager in the server package. It is responsible for holding recordnumber - client pairs. But in this approach locking isn't done in the lock and unlock method's of Data (it can be even empty). We are breaking the restriction that record locking must be implemented in Data.
    Then you could think of supplying a Data instance for every client that connects and using this as client identification. In this case we have to modify the Data class to such an extent that we break another restriction imposed by Sun that the Data class is fully functional (except for lock, unlock and criteriaFind) and that we shouldn't modify it.
    Modifying the signature of the lock and unlock methods to accept a clientId isn't also an option.
    Voila, a dead lock situation in the FBNS swamp. (Or is there another approach I'm missing ?) I think we are forced to break the instructions and justify our approach in the documentation (Least of two evil).
    I hope Max can provide me with one of his famous brainwaves .
    Damian, more and more I begin to believe the socket implementation fits all instructions, maybe I should reconsider using RMI .
    Regards,
    Ronald
    Damian Ryan
    Ranch Hand

    Joined: May 09, 2003
    Posts: 117
    I don't like the idea of changing the signature of the lock and unlock method to add an extra parameter like the clientId.

    Neither do I Ronald, and indeed there are plenty of ways of implementing locking that wouldn't require this. I was merely being illustrative.
    Then you could think of supplying a Data instance for every client that connects and using this as client identification. In this case we have to modify the Data class to such an extent that we break another restriction imposed by Sun that the Data class is fully functional (except for lock, unlock and criteriaFind) and that we shouldn't modify it.

    As I stated earlier, my instructions specifically allowed consideration of modifying the existing version of suncertify.db.Data. Unless your instructions were different, I would think the bit of your quote I have highlighted above doesn't apply.
    I'd make another point while I'm here. Obviously I don't know the details of how you've implemented your lock manager, but I don't see that using the services of a separate class (the lock manager) has to mean that the lock and unlock methods of Data are left empty. Could you not just have the Data.lock(int) and Data.unlock(int) methods delegate the implementation of the locking mechanism to the lock manager class you have written? I know this means that you would have redundant locking performed in the standalone version with only one local client, but I don't see this as a big problem personally.
    Damian, more and more I begin to believe the socket implementation fits all instructions, maybe I should reconsider using RMI.

    Ronald, don't let anyone else hear you say this. They'll accuse me of leading you astray But seriously, I don't think you should give up on your implementation. It sounds as if you're almost all the way there.
    [ August 22, 2003: Message edited by: Damian Ryan ]
    Max Habibi
    town drunk
    ( and author)
    Sheriff

    Joined: Jun 27, 2002
    Posts: 4118
    Originally posted by Damian Ryan:
    Max,
    here's what my version of the instructions said (under the section "Extending suncertify.db.Data"):

    positively cries out for the developer to leave the code in a "better" shape than he or she found it, to ease the task of future programmers who must understand the code before they can alter or build on it.
    (And one of the ways I felt I could make the code clearer to someone else was to remove a daft IOException from a method that had no need to throw it).
    And to reiterate, I felt justified altering the signature because I interpreted the context described in my instructions as stating that I was THE developer tasked with developing 100% of the system, and that therefore alteration of a published interface wasn't going to upset the project, because I was the only consumer of that public interface.
    You'll have gathered by now no doubt how I tend to write quite a lot when I'm trying to explain a point and I apologise for the lack of concision in my arguments. I think (well, I hope) I managed to be a bit more concise when I submitted my documentation (with the benefit of a bit more time to edit it ) but I want to make the point that I think it's very important to supply every assumption you've made so that your examiner can use this as a basis to judge your offered justifications (assuming of course, that your assumptions are not considered invalid).
    [ August 22, 2003: Message edited by: Damian Ryan ]


    I was thinking of the section under Supplied Code and Required Enhancements that stated

    The classes and code provided to you include some comments, including some in javadoc format. You should refer to these and consider the source itself for a full understanding of the provided code.

    This, coupled with the signature of the lock method

    /**
    * Lock the record, and associate the locked record with current
    * thread.If the argument is -1, lock the whole database.
    * @param recno The record number to lock.
    * @exception IOException If the record position is invalid.
    */

    emphasis added.
    My point is that, as stated, there seems to be little ambiguously that we need to consider the comments when implementing the methods. And if this is true, then it's also clear that lock methods requires only and only type of specific exception: the IOException. And if that's true, then the directions are clear.
    Again, I don't disagree that it's possible that the reviewer could decide to accept your justification. However, it's also true that they could glance it, declare(with justification) you didn't meet the letter of the requirements, fail you on the spot, and go to lunch: mayby sushi.
    Given the way that some ppl on this forum have failed the exam, even when they had done nothing wrong(and some were reinstated after protesting: others weren't), this is not a competently remote possibility. I guess the question is, are you comfortable taking that risk? And are you comfortable with suggesting that other people take that risk? Especially since it's just as easy(and, IMO, architecturally sound) to step around it. If yes, then I think we've found our branching paths, as it were
    M
    [ August 22, 2003: Message edited by: Max Habibi ]
    Damian Ryan
    Ranch Hand

    Joined: May 09, 2003
    Posts: 117
    Max,
    I'm afraid that I'm happy to stick with my interpretation of the instructions as I have expounded at (perhaps too) great length.
    Nothing you have just said about about considering the javadoc comments convinces me that my point of view is incorrect, and I think we have to agree to disagree.
    But I'm ready to throw the towel in now. I agree that the safest bet is not to rock the boat.
    I did rock the boat (I refactored existing class names, I altered the signature of the lock method, I didn't use RMI even though the prevailing opinion seems to be that it's just THE way to do it, I coded defensively against malicious clients thus adding complexity to the server that was arguably unnecessary, I used worker threads in my client GUI to decouple database access from the AWT dispatch thread. The list of choices I made that have been advised against in this forum goes on and on) and I still passed comfortably. But you are right, I cannot guarantee to any other candidate that a different examiner would assess them consistently with the way I was assessed.
    I just wanted to say to those who have yet to submit their assignments that they should have the courage of their convictions if they believe thay have made sound, justifiable choices, even if these don't always meet with the approval of the great and good here. As Andrew, Mark, yourself and others have said more than once, we should bear in mind that there is no single right way to do most things, and IMHO THE major objective of the SCJD is to determine a candidate's ability to make and justify sometimes difficult choices in less than perfect circumstances.
    And here endeth my sermon
    [ August 23, 2003: Message edited by: Damian Ryan ]
    Max Habibi
    town drunk
    ( and author)
    Sheriff

    Joined: Jun 27, 2002
    Posts: 4118
    Hi Damian,
    It sounds like you like to take an individualistic approach to issues, and solve them in your own way, regardless of what other think. Quite honestly, I think this is often a sign of truly gifted people. I would never fault you for it, and I'm really glad that you did so well. I've had many private students do equally well using hider own, or more orthodox, approaches. And yes, I agree that you should express yourself through your work: however, I think you should also maximize your changes of passing.
    By and large, the people who volunteer to help here are also individualistic in nature. Mark, Andrew and I disagree about a great many issues, including the LockManager. Yes, we all happen to agree that changing the method signatures isn't the best path, and we agree that RMI is the easier approach. However, we're happy to support people who are taking their own path through these woods, like Vlad and Phillipe. By and large we just want to see people succeed with the SCJD. I personally think it's the software world's premier certification, I like seeing people earn it.
    anyway, I'm not sure there's a point to my rant, but I hope you haven't decided that the SCJD forum is the borg, intent on sucking out the creative impulse in the future generation of SCJD developers
    M
    Damian Ryan
    Ranch Hand

    Joined: May 09, 2003
    Posts: 117
    anyway, I'm not sure there's a point to my rant, but I hope you haven't decided that the SCJD forum is the borg, intent on sucking out the creative impulse in the future generation of SCJD developers

    Not at all! It'd be really boring if everyone agreed on everything .
    Part of what I really love about writing code is that there are usually so many ways to approach each problem and picking a "good" one then implementing it is a buzz. (And I think this is what makes a good developer an artist as well as a craftsman - some solutions are just beautiful and elegant "art" in their own right ). This forum a really good opportunity to pick up on the odd technique or solution that I haven't thought of myself or encountered before, and I am sure it is the same for the many others who come here to ask questions, provide answers or just browse.
    I mainly come to do the last one, but sometimes can't resist the temptation to put my oar in
    [ August 23, 2003: Message edited by: Damian Ryan ]
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11460
        
      94

    Thank you Damian for giving your interpretation of the instructions. It is great to see alternatives, especially when they are as well argued as you have done.
    I didn't use RMI even though the prevailing opinion seems to be that it's just THE way to do it

    I am not convinced that RMI is the way to do it. However I (like many others) approached this assignment as a learning experience, and I have done enough with sockets over the past few years, so I decided to use RMI.
    I just wanted to say to those who have yet to submit their assignments that they should have the courage of their convictions if they believe thay have made sound, justifiable choices, even if these don't always meet with the approval of the great and good here.

    I agree.
    There is a risk with this sort of forum that people will end up ignoring their own instincts because of something that has been said here. Fortunately there is enough differences in opinions on any given topic that ranchers do have to work out what works best for them.
    I mainly come to do the last one, but sometimes can't resist the temptation to put my oar in

    Please, please put your oar in more often. The more people who are willing to discuss alternatives the better.
    Regards, Andrew
    Damian Ryan
    Ranch Hand

    Joined: May 09, 2003
    Posts: 117
    Andrew: I am not convinced that RMI is the way to do it. However I (like many others) approached this assignment as a learning experience, and I have done enough with sockets over the past few years, so I decided to use RMI.

    That's a very good point, Andrew.
    I didn't use RMI because I have an irrational antipathy to it, and that's my problem. I didn't mean to sound petulant when I threw in the comment about everyone else picking that way of doing things. I know that popular opinion has it that RMI is easier, especially for newcomers to distributed programming, but I must just be contrary, because I find it exactly the other way around
    I guess it's that way about some things for a lot of other people too, which is why I guess choice is so important and why it's helpful for us to have a frank exchange of views
    [ August 23, 2003: Message edited by: Damian Ryan ]
    Ronald Oltmans
    Greenhorn

    Joined: Aug 17, 2003
    Posts: 12
    Damian wrote:

    I don't see that using the services of a separate class (the lock manager) has to mean that the lock and unlock methods of Data are left empty. Could you not just have the Data.lock(int) and Data.unlock(int) methods delegate the implementation of the locking mechanism to the lock manager class you have written?

    I can't, Damian. I can have only one Data instance for all the clients.
    And because I have only one Data instance, I can't keep track of the client who wants to lock a record in the Data class, because the Data class' lock and unlock methods don't allow me to supply a client identifier.

    For this reason I have to keep track of the client - recordnumber relationship in the remote code where I have one separate Connection (RemoteData) object per client. So in my remote lock and unlock implementations I delegate the method calls to a lock manager to keep track of the locks owned by a client (Connection object).
    This also implies that my lock and unlock methods don't perform any locking and are problably empty or do some kind of validating. This is a little bit against the instructions that state that the lock method of Data must be implemented to do the locking. I think I have to live with it, because I don't see any another solution.
    Maybe it's an option to add two methods to the data class that introduce a client identifier to the lock and unlock method, like lock(recNum, client), but I am also not happy with that, because Data is fully functional, except for lock, unlock and criteriaFind.
    Andrew wrote:
    You might be interested in reading No need for a locking manager? - it is very long, and some of the ideas that I suggested in there I am no longer convinced about, but you will see quite a few comments talking about how to track ownership of locks for FBNS.

    Indeed very long, Andrew, it took me the whole weekend...
    I think I am on the right way to track the ownership of locks, but that means that my lock and unlock methods of Data are empty. And that means that I am not strictly adhering to the instructions to implement locking in lock and unlock of Data. But as stated above, I don't see any other solution.
    All the best,
    Ronald
    [ August 24, 2003: Message edited by: Max Habibi ]
    [ August 24, 2003: Message edited by: Andrew Monkhouse ]
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11460
        
      94

    Hi Ronald,
    I think I am on the right way to track the ownership of locks, but that means that my lock and unlock methods of Data are empty. And that means that I am not strictly adhering to the instructions to implement locking in lock and unlock of Data. But as stated above, I don't see any other solution.

    My solution was to track which records were locked in the Connection object but have the actual locks granted by the Data.lock() method. I had to take a very loose interpretation of the instructions to convince myself that this was OK - Max believes that I did not meet the requirements, and I can certainly understand his point, but like you I was stumped on how to fix it without breaking some other instruction.
    One idea I have been toying with is the concept that Data must have a lock(int) method, and Connection must have a lock(int) method, but there is nothing to say that Connection.lock(int) has to call Data.lock(int). Is it possible to have Connection.lock(int) call an overloaded lock method in Data? You would have to decide for yourself whether this is allowable and whether it will help.
    Regards, Andrew
    Ronald Oltmans
    Greenhorn

    Joined: Aug 17, 2003
    Posts: 12
    Hi Andrew,
    I try to understand your solution. Is it true that you store the locks at two places ? One storage (client-nr combination) in the Connection object and one general storage (nr) in the Data object.

    Is it possible to have Connection.lock(int) call an overloaded lock method in Data?

    I think it is surely possible. (ex. lock(int, this)).

    You would have to decide for yourself whether this is allowable and whether it will help.

    If I understand your possible suggestion of overloading the lock method in Data, I think the lock(int) method is still empty and no actual locking is performed in this method, but in lock(int, Object) of Data.
    Is this true or am I missing your point?
    If this is true I think we still don't meet the requirements that locking must be implemented in lock(int).

    Max believes that I did not meet the requirements

    I hope there is a solution that meets all he requirements, but I haven't seen the light yet. Hopefully Max can shine his light on this.
    Thanks for your help so far, Andrew,
    regards,
    Ronald
    [Andrew: moved quotes out of [code] blocks and into
    blocks]
    [ August 26, 2003: Message edited by: Andrew Monkhouse ]
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11460
        
      94

    Hi Ronald,
    Please put quotes from other people inside [QUOTE ] tags and not [code ] tags. [code ] tags are used for displaying source code, and lines will not wrap if they exceed screen width. [quote ] tags will allow quoted comments to wrap if they exceed screen width.
    Is it true that you store the locks at two places ? One storage (client-nr combination) in the Connection object and one general storage (nr) in the Data object.

    Close, but not quite. I stored the record numbers of the records that each connection had successfully locked in the Connection object. The Data object was where the actual lock was held, since it had to know whether it could grant a lock to anyone else.
    Regards, Andrew
    [ August 26, 2003: Message edited by: Andrew Monkhouse ]
     
    It is sorta covered in the JavaRanch Style Guide.
     
    subject: FBN: changing lock method's IOException