aspose file tools*
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes Contradictory requirements 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 "Contradictory requirements" Watch "Contradictory requirements" New topic
Author

Contradictory requirements

Arvind Prabhu
Greenhorn

Joined: Aug 09, 2001
Posts: 18
I've been working on the assignment off and on for a while and I'm still having problems with deciphering the requirements. On one hand, the requirements are pretty clear in stating the exact signatures of the "lock" and "unlock" methods. The signatures as given neither accept any sort of client identification nor do they return anything. However, on the other hand, the requirements also clearly state that no action is to be taken if a client tries to unlock a record which the client has not locked (Please correct me if I'm wrong).
Since these two seem contradictory, I guess I could just choose one to follow and finish off this assignment. However, I'm not satisfied with just doing that.
In addition, the signatures for lock() and unlock() seem incomplete anyway, since both of them should be "synchronized" because wait() and notifyAll() are called within.
I've read many discussion threads on this topic and there doesn't seem to be a strong thrust either way (concerning client IDs). If anyone can provide some insight on this apparent contradiction in requirements I would really appreciate it. Thanks.
------------------
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
Originally posted by Arvind Prabhu:
On one hand, the requirements are pretty clear in stating the exact signatures of the "lock" and "unlock" methods. The signatures as given neither accept any sort of client identification nor do they return anything. However, on the other hand, the requirements also clearly state that no action is to be taken if a client tries to unlock a record which the client has not locked (Please correct me if I'm wrong).
No, you're absolutely spot-on.
Since these two seem contradictory [...]
But are they?
They aren't contradictory at all. Having said that, many people modify the signatures and pass. Others just ignore the "no action" requirement and pass too. If you manage to think of a way to satisfy both requirements, you'll probably pass with a higher mark.
I'm not really happy discussing my own solution in much detail, as having gone through the design process is one of the things that make a SCJ2D. Either question your implicit assumption that there is just a single instance of the remote Data implementation, or consider using an adapter class that translates between identity-less and identity-aware lock signatures.
In addition, the signatures for lock() and unlock() seem incomplete anyway, since both of them should be "synchronized" because wait() and notifyAll() are called within.
Why? In a local database, there's no need for locking at all. I'd say that the "implementations" in the Data class are fine as-is. There's certainly no need to synchronize them
Of course the remote version of Data is another matter...
- Peter
Arvind Prabhu
Greenhorn

Joined: Aug 09, 2001
Posts: 18
Thanks for your input Peter. I've decided to go with adding a client ID parameter to both the lock and unlock methods. After this, I started to work on the Data Server (which is an RMI object in my case) and noticed a couple of issues.
1. The lock and unlock methods of the DBServer class could take in a client ID and perform client ID specific checks and call the lock and unlock (without a client ID) in the Data class. But the drawback here is that the locking mechanism would have to be placed in both the classes - NOT good. Basically I would need a HashMap in both the DBServer and Data classes.
2. Another issue deals with the method that actually books a specified number of seats on a specified flight. I could place this method in either the client or the server. The method basically finds the record, locks it, tries to modify it, and unlocks it. Instead of making these individual calls from the client to the server, I thought I would put this sequence of calls within a single method in the server. Too much network overhead if this method is placed in the client. Any thoughts?
3. In addition, since most of the methods in the Data class are synchronized, would any of the methods in the server class need to be synchronized? I don't see the need. Note that the server class just acts as a proxy to the Data class.
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
Originally posted by Arvind Prabhu:
1. The lock and unlock methods of the DBServer class could take in a client ID and perform client ID specific checks and call the lock and unlock (without a client ID) in the Data class. But the drawback here is that the locking mechanism would have to be placed in both the classes - NOT good. Basically I would need a HashMap in both the DBServer and Data classes.
Can you explain to me exactly why you would need a HashMap in Data?
2. Another issue deals with the method that actually books a specified number of seats on a specified flight. I could place this method in either the client or the server. The method basically finds the record, locks it, tries to modify it, and unlocks it. Instead of making these individual calls from the client to the server, I thought I would put this sequence of calls within a single method in the server. Too much network overhead if this method is placed in the client. Any thoughts?
This approach does not sit easily with the requirements, which appear to ask you to create a network-enabled version of Data that could be reused in other projects. Putting client-specific code in the server appears to step outside both requirements to some extent. Having said that, judging from what I've seen, if you argue why this is the best way to do this you'd pass.
In addition, since most of the methods in the Data class are synchronized, would any of the methods in the server class need to be synchronized? I don't see the need. Note that the server class just acts as a proxy to the Data class.
Ah, now that depends entirely on what the methods in the server actually do! So that's a question only you yourself can answer, for each method individually, while you are coding them.
- Peter
Matthew Comer
Ranch Hand

Joined: Aug 10, 2001
Posts: 37
You dont have to modify the lock() and unlock() method signatures to satisfy both requirements...
Design a "Connection" object that implements Remote. This object also implements your data interface. Now, you have a proxy object that serves two purposes - a) it allows remote connectivity to your data object, and b) it allows you to do some clever things BEFORE and AFTER you pass the request on to your data class. Specifically, now you can register that a given thread is working on behalf of a given connection in some sort of "thread connection registry" that you will implement. So, in your connection class:
public void lock(int recnum) throws...
{
try
{
ThreadConnectionRegistry.registerThreadConnection(this);
data.lock(recnum);
}
finally
{
ThreadConnectionRegistry.unregisterThreadConnection();
}
}
and in this "thread connection registry" thingy:
public static void registerThreadConnection(Connection c)
{
threadconnections.put(Thread.currentThread(), c);
}
public static void unregisterThreadConnection()
{
threadconnections.remove(Thread.currentThread());
}
public static Connection getThreadConnection()
{
return threadconnections.get(Thread.currentThread());
}
so now wherever you are in your code you can always call:
Connection currentcon = ThreadConnectionRegistry.getThreadConnection();
Voila! You know who you are WITHOUT having to pass a connection id around all over the place...
You could even generalize this further to create a "thread context" so that you could carry arbitrary stuff around on a thread if you needed to...
Someone please tell me if this reply overreaches the bounds of what is appropriate for this forum. I know that the idea is to help without cheapening the test... Feedback appreciated.
[This message has been edited by Matthew Comer (edited August 11, 2001).]
BTW - not sure what I'm doing wrong with the formatting above. For some reason it is eating all of my leading spaces...
[This message has been edited by Matthew Comer (edited August 11, 2001).]
Also... (IMPORTANT) I've disregarded all thread-safety issues in the code examples above. Real code should not!
[This message has been edited by Matthew Comer (edited August 11, 2001).]
Arvind Prabhu
Greenhorn

Joined: Aug 09, 2001
Posts: 18
Thanks for the follow up Peter. Sorry for the late reply, but I was taking a break over the weekend and I felt lazy on Monday!
Originally posted by Peter den Haan:
Can you explain to me exactly why you would need a HashMap in Data?

Well, actually, I meant that I would need locking and unlocking logic in both classes (in the DBServer and Data classes). Since I don't have any associations in the Data class I would not need a HashMap, but I would need something else. In the DBServer class I would need a HashMap though. Regardless the locking and unlocking logic would be duplicated, right?
This approach does not sit easily with the requirements, which appear to ask you to create a network-enabled version of Data that could be reused in other projects. Putting client-specific code in the server appears to step outside both requirements to some extent. Having said that, judging from what I've seen, if you argue why this is the best way to do this you'd pass.

Actually, you're right, I should keep client-specific code out of the server. Taking your advice, I moved the method into the Data Client. Thanks.
Ah, now that depends entirely on what the methods in the server actually do! So that's a question only you yourself can answer, for each method individually, while you are coding them.

Yes - I was talking to a friend of mine and he had a totally different approach which was intersting (slightly off the topic from above, but interesting):
Instead of creating a DBServer class, he created a DBServer interface and modified the Data class to implement that interface. So, now his server implementation class IS the Data class. I guess he had to go through and change the signature of all the public methods to throw RemoteException - I don't think that's a problem. How does that sound? I can't really find anything wrong with this approach. Actually it seems a bit better since it removes an unnecessary layer. Any thoughts?
Thanks for all your help. I'm working on the GUI right now, but I think I might need to go back and re-think some aspects.
-Arvind
Arvind Prabhu
Greenhorn

Joined: Aug 09, 2001
Posts: 18
Thanks for your reply Matthew, my comments are below.
Originally posted by Matthew Comer:
You dont have to modify the lock() and unlock() method signatures to satisfy both requirements...
Design a "Connection" object that implements Remote. This object also implements your data interface. Now, you have a proxy object that serves two purposes - a) it allows remote connectivity to your data object, and b) it allows you to do some clever things BEFORE and AFTER you pass the request on to your data class. Specifically, now you can register that a given thread is working on behalf of a given connection in some sort of "thread connection registry" that you will implement. So, in your connection class:

You've got a good idea there. Actually, I've read similar solutions in other topics in this forum; however, I've also read that RMI does not guarantee that the same thread will be used from one method invocation to the next. Thus, for example, a client could be running in Thread A when calling lock and the same client could be running in Thread B when calling unlock and this would cause an inconsistency. Don't know if I'm making sense - please do reply if you get a chance.
Thanks.
-Arvind
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
Arvind,
Matthew's solution is exactly the one I chose myself. The fact that different threads may be used between invocations is absolutely immaterial. Remember, what identifies the client is the Connection object he's talking to; not the Thread he happens to be executing in.
The Connection object approach has a number of advantages. You can satisfy both the lock signature and the identification requirements. You can leverage RMI distributed garbage collection to clean up after dead clients, with virtually no programming on your part.
Regarding your earlier response: you don't need any locking code in Data. It is worth thinking of your objects in terms of responsibilities and collaborations here. Data's responsibility is looking after a local database. Locks aren't part of that.
"I guess he had to go through and change the signature of all the public methods to throw RemoteException" - I bet he didn't (if he did it right). Data should never throw RemoteException. The interface should, so that the RMI proxy can throw these exceptions, but the implementation shouldn't. Having said that, I personally don't like it. Again, think of responsibilities. The new Data would be responsible for too many disparate things. Read Fowler's Refactoring if you have time.
- Peter
Matthew Comer
Ranch Hand

Joined: Aug 10, 2001
Posts: 37
Originally posted by Arvind Prabhu:
...I've also read that RMI does not guarantee that the same thread will be used from one method invocation to the next.
-Arvind

Yes, this is true. I am only using the Thread->Connection relationship for the LIFE OF THE METHOD INVOCATION. IN other words, I say "this THREAD is working on behalf of this CONNECTION right NOW". It is the Connection object that holds the locks, not the Thread... This is also why I unregister the Thread->Connection relationship when I'm done. I don't know if the JDK's implementation of RMI re-uses method-invokation-servicing-threads, but in case it does I want to say "this THREAD is no longer working on behalf of this CONNECTION".
Matt
Arvind Prabhu
Greenhorn

Joined: Aug 09, 2001
Posts: 18
Thanks for the help and clarification guys. I'll look into the Connection object as a way of tracking clients. For now, I think I'll continue with my client ID approach and work on the client GUI program for a while.
Had a question about the client. The requirements state that we should using Swing for the GUI. Does this mean that we SHOULD NOT use any of the AWT constructs. For example, I'm designing a dialog using JDialog and I'd like to set its layout manager to GridBagLayout - but GridBagLayout is an AWT construct. Would I be wrong to use it? Also, I'm making use of several AWT event listeners - am I also banned from using them?
In the future, when I have similar questions how I can determine if I can use a certain class or not? Thanks.
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
Don't worry, GridBagLayout is as much part of Swing (by adoption rather than birth) as it is of AWT.
- Peter
Jon Trussler
Greenhorn

Joined: Jul 05, 2001
Posts: 9
Matthew, Peter, etc,
I am missing something big here. Please help me out but without cheapening the test as Matthew expressed.
My RMI object is a RemoteDatabase that, naturally, extends UnicastRemoteObject and implements my RemoteDatabaseInterface which extends a generic DatabaseInterface and Remote
If we were to have as you mentioned above:
public void lock(int recnum) throws...
{
try
{
ThreadConnectionRegistry.registerThreadConnection(this);
data.lock(recnum);
}
finally
{
ThreadConnectionRegistry.unregisterThreadConnection();
}
}
Wouldn't "this" be the "Connection" object that you refer to, which is RemoteDatabase in my case? And in that case, isn't the connection object the same for all clients connecting remotely? Obviously it cannot be since you identify the client holding the locks by connection object.
Basically I am having difficulty with the notion that everyone has to share the same locking structure while at the same time has a different connection object when only 1 object is bound to the registry.
I basically have a solution that I am confident will get me a passing score, as many people have passed without tracking client locks. However, I would like to be as thorough as possible. And as we all should know, a certification isn't the only reason for completing the assignment.
I would appreciate any further advice on connection tracking without modifying method signatures.
Thanks,
Jon
Andras Nemeth
Ranch Hand

Joined: Jul 31, 2001
Posts: 80
Originally posted by Jon Trussler:
Matthew, Peter, etc,
public void lock(int recnum) throws...
{
try
{
ThreadConnectionRegistry.registerThreadConnection(this);
data.lock(recnum);
}
finally
{
ThreadConnectionRegistry.unregisterThreadConnection();
}
}

Hello I can not see the point why do you unregister the Connection object after locking... Wouldn't you need it
for unlock?

Wouldn't "this" be the "Connection" object that you refer to, which is RemoteDatabase in my case? And in that case, isn't the connection object the same for all clients connecting remotely? Obviously it cannot be since you identify the client holding the locks by connection object.

Well, it depends on your implementation... I think in Matthew's
solution every client has a Connection object which provide
the db functions and support the object lock...
Anyhow, I am sure he will explain us.
Bye,
Ban
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
The Big Trick[tm] is that RemoteDatabase is the Connection object; each client gets its own personal copy of RemoteDatabase. Obviously, all these RemoteDatabases delegate their calls to the same lock manager and the same Data instance.
Intuitively you might think that this implementation is fairly heavyweight because RemoteDatabase is a "big" object. Not so. It has plenty of behaviour (methods) but it's an object without any state (instance variables) whatsoever; it is as lightweight as Java objects come. You can easily afford to give each clients their own database to talk to and use those databases to keep track of the client's identity.
By the way, if you consider walking this road, re-think Matthews use of Thread for identification; it's a bit too kludgy for my liking and you can certainly do fine without it.
- Peter
Matthew Comer
Ranch Hand

Joined: Aug 10, 2001
Posts: 37
I'm still not sure you guys are seeing what I was talking about.
The ID is the Connection object. Each client gets its own Connection - all of the Connection objects make use of a SINGLE Data instance. Can't really do UML here unfortunately...
My use of Thread is saying "this THREAD is working on behalf of this CONNECTION right NOW". This means that in my implementation if a client decides to use a single Connection (which it gets from a ConnectionFactory object) but has several threads running, then a lock that Thread A requests can also be used by Thread B, as long as both threads use the same Connection. It is the Connection that has the lock, not the Thread.
My purpose for registering the Thread->Connection relationship is only so that I don't have to pass a connection id around. Any code that needs to know what the current connection is (i.e. which connection the current thread is working on behalf of) can just call ThreadConnectionRegistry.getCurrentConnection().
Matt
Andras Nemeth
Ranch Hand

Joined: Jul 31, 2001
Posts: 80
Hi Matt, Peter and every1,
Originally posted by Matthew Comer:
I'm still not sure you guys are seeing what I was talking about.

I got it. It wasn't easy, but at least I managed to understand.

My purpose for registering the Thread->Connection relationship is only so that I don't have to pass a connection id around. Any code that needs to know what the current connection is (i.e. which connection the current thread is working on behalf of) can just call ThreadConnectionRegistry.getCurrentConnection().
Matt

What do you think the following approach:
I have an instance variable, called ClientID, in the Connection
class. It is an UID or ObjID and it got a value every time when
the ConnectionFactory create an instance of the Connection.
The lock and unlock will use this ClientID, but I do not have
to modify the signatures of them, because the Connection object
hold this ClientID.
Questions:
I have a (Let's say one.) GUIClient and an FBNServices object,
which of these should have an connect method to return the
Connection object... (I assume the second one.)
Do you use this connect method to the local mode also? (make an
instance of Data class)
Do you use a different interface for provide
connect function or is it included in the
interface of Data?
Thanks.
Ban
[This message has been edited by Andras Nemeth (edited August 20, 2001).]
Andras Nemeth
Ranch Hand

Joined: Jul 31, 2001
Posts: 80
Hi,
I have another idea about Connection object.
My server will export only an object which implements DBConnection interface. This interface has one method, connect, which returns a Connection object. This Connection object the same what I wrote before, so implements an DBInterface with all public methods of Data class.
The client side ConnectionFactory will create DBInterface type
object depending it is in local (from Data) or network (via calling connect remote method) mode.
Any comment or notion against or with?
So long,
Ban
Marre Mask
Greenhorn

Joined: May 04, 2001
Posts: 19
What it all comes down to is how you justify your choice. I had to "break" on of the requirements but I made it anyway with a pretty good score (151/155).
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
Originally posted by Andras Nemeth:
I have an instance variable, called ClientID, in the Connection class. It is an UID or ObjID and it got a value every time when the ConnectionFactory create an instance of the Connection.
Don't. You don't need it. The Connection object itself is a perfectly valid UID.
I have a (Let's say one.) GUIClient and an FBNServices object, which of these should have an connect method to return the Connection object... (I assume the second one.)

What most do is craete a single method in the client that returns a DataInterface. The method will either instantiate a Data and return that, or connect to a RMI-registered connection factory and obtain a connection from there, depending on the mode.
- Peter
Shailendra Guggali
Ranch Hand

Joined: Feb 01, 2001
Posts: 86
I have used the same method to CREATE ClientID for both the Socket and RMI networking : WORKS FINE ::: PLS COMMENT
I have a method called getClientID() which is present in the DataIMPL class( it extends the Data class)
This method creates a unique ID based on the
System.currentTimeMillis() method. A variable is created in this class to check whether the new ID created is same as the one created earlier - else increment it - convert to String and return to the CLIENT.
Now my reasoning is that since all client get the ID from the Server - the time is also in the same TIMEZONE - there is check at one place so it has to be unique.
When this is used by the CLIENT in all the methods it calls it remains uniform.
Seems too good to be actually true and working - PLS BLOW HOLES IN IT !!!
Thanx
Jon Trussler
Greenhorn

Joined: Jul 05, 2001
Posts: 9
Peter, Matthew, etc....
Now I have a system where each client gets its own server side object to talk to. Now it is very easy to maintain record locks without changing my method signatures. Thanks for the guidance. I just have one question.
1. If a client aborts without unlocking his records, what is the best way to automate that unlocking process? I have implemented the Unreferenced interface and that works but not in a timely manner. Sometimes it takes 10 minutes to detect this. Granted, aborting without unlocking is a rare exception assuming a properly behaved client. Others have used a timing mechanism. Any suggestions?
Thanks,
Jon
---------------
Nevermind. If you clean up after yourself there is no delay in calling unreferenced as long as the program is exited normally. For abnormal exits, you will have to wait. I have experimented with decreasing the java.rmi.dgc.leaseValue but that seems to create a lot of overhead with renewing leases. Any comments are appreciated.
[This message has been edited by Jon Trussler (edited August 22, 2001).]
Peter Crowley
Greenhorn

Joined: Nov 06, 2001
Posts: 14
Originally posted by Peter den Haan:
Remember, what identifies the client is the Connection object he's talking to; not the Thread he happens to be executing in.
Regarding your earlier response: you don't need any locking code in Data. It is worth thinking of your objects in terms of responsibilities and collaborations here. Data's responsibility is looking after a local database. Locks aren't part of that.

So if I understand this correctly,
  • Data is not using any locking at all and the methods are empty.
  • Clients in local mode will use Data directly and avoid locking alltogether.
  • Locking happens only in the Connection object that meets the RemoteData interface
    and wraps a single Data instance on the server.
  • This connection object come from a ConnectionFactory that makes a new Connection instance for each client.
  • The Connection has the reference to a Lock Manager instance for the Data instance.
  • There is only one Lock Manager for each Data.

  • Is this correct? If it is, is there any reason why not to implement the lock-read-modify-unlock code in the Connection object instead of the client. This cuts down on a lot of network traffic, and you can still send the exceptions (if any) back to the client to handle. That way the client isn't bothered with any multi threaded or locking code, and a client in local mode won't do either.
    -Peter Crowley
    [This message has been edited by Peter Crowley (edited November 27, 2001).]


-Peter Crowley,<BR>who is looking for work in North Florida
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
Data is not using any locking at all and the methods are empty.
That is what I think is a good way to go about it; others don't agree. Let me put it this way: it won't prevent you from passing with a fine score.
Clients in local mode will use Data directly and avoid locking alltogether.
I wouldn't put it that way. The client should work with an abstract DataInterface that might be remote, maybe not, and go through all the motions of lock-read-modify-unlock, not caring if this is implemented or not. The client simply relies on the implementation to do the right thing. That's what polymorphism is all about.
This is probably what you meant anyway, but I'd like to avoid misunderstanding.
Locking happens only in the Connection object that meets the RemoteData interface and wraps a single Data instance on the server.
Yes, although the Connection may delegate that responsibility.
This connection object come from a ConnectionFactory that makes a new Connection instance for each client.
That's correct. This is only one possible solution of course!
The Connection has the reference to a Lock Manager instance for the Data instance.
Or it is an inner class of the ConnectionFactory, and the factory contains the references to both Data and the LockManager. Or a dozen other variations on the theme.
There is only one Lock Manager for each Data.
Absolutely.
Is this correct? If it is, is there any reason why not to implement the lock-read-modify-unlock code in the Connection object instead of the client.
Somewhere in your application, you have to make a "cut" (read: interface) between back end and front end. The back end has two implementations, a local one and a networked one. By explicitly requesting that you implement another class that exposes the same interface as Data, Sun effectively tells you where that cut should be. The DataInterface.
What you are proposing is moving the cut to a higher level, business interface. That could well be a valid approach in other situations, but not here, for two reasons. First, because of the instructions provided; with this approach the two Data implementations don't really make sense anymore. Second, because you are coding for reuse. The Data interface is generic and both local and networked databases would be completely reusable. A business-level interface, on the other hand, is application-specific and not reusable. (You could of course make two cuts at two levels but that would complicate matters, which flies in the face of instructions to keep things clear and simple).
Note that the above is all IMHO, YMMV.
- Peter
[This message has been edited by Peter den Haan (edited November 27, 2001).]
Todd Harney
Greenhorn

Joined: Jan 25, 2002
Posts: 23
Hello all:
My design is very similar to the one just discussed where I have a RemoteDataConnection class that is a remote object, but not bound to the RMI registry...so each client asks the connection factory in the registry for a remote connection and is issued a reference to a new RemoteDataConnection(data,lockManager) which lives on the server. (data and lockManager are instance variables that come from the connection factory). So, I am having two issues that I would like some insight into:
1) It has been mentioned that we don't need to change the method signatures for lock/unlock to include a "client id" (specifically if we use the connection per client model) Isn't true however that since there is only one locking instance for each data instance that there will need to be some adapter code to map the record number to the connection object? (like in a HashMap?)
2) It has also been mentioned that a business interface is a bad idea as it is not re-usable. In my design, the GUI speaks only to a business interface that defines methods like bookFlight, searchFlights, etc which in turn invoke the appropriate methods on a DataAccess interface (either local or remote). Is this against the requirements set forth by Sun? Should I remove this interface and go with a DataClient that implements DataAccess, but adds methods like bookFlight, searchFlight, etc?
Any comments/suggestions would be appreciated!
Thanks,
Todd Harney
Arvind Prabhu
Greenhorn

Joined: Aug 09, 2001
Posts: 18
I had forgot about this question that I had posted here. Just got an email about a reply and thought I'd investigate.
Anyway, just wanted to thank everyone for their help here. I am certified now! I got a 145/155. I wasn't able to get to the point break-up though. I fininshed the assignment last year and took the test late last year. The results came back fairly quickly. I'm not that thrilled about the grade since I had put in a lot of time and effort - but I guess I should happy that I passed. The essay exam was a piece of cake - there is no need to study unless you didn't write your design choices document.
Well, thanks to everyone again!! Good luck to everyone that is currently going for their certification.
 
 
subject: Contradictory requirements