Raj Nagappan

Ranch Hand
+ Follow
since May 26, 2004
Merit badge: grant badges
For More
Cows and Likes
Cows
Total received
In last 30 days
0
Forums and Threads

Recent posts by Raj Nagappan

Thanks Ulf I'll give it a try
15 years ago
Hi David,

Yes I understand that. But I am specifically given a text file which is exactly what the Post request will look like. I need to test directly against this text file that contains all the fields. I have other unit tests that test isolated parts. But I really need this automated acceptance test that says "send this Post message text to me (to simulate a page transmission over the net) and I will respond correctly". How can I do this?
15 years ago
Hi everyone,

I am trying write a junit style test to invoke a Struts 2 action class, using Spring 2.5. I have been given a message body of an HTTP Post request that will be sent to our web site from an external source. This message body is plain text exactly of the Post request itself. I want to write a test against this.

I have been looking at the different Java web testing frameworks like JWebUnit, HtmlUnit and HttpUnit but none seem to do what I want.

I do not want either:

or

What I want is:

where myMessageBody is a plain-text concatenation of all the fields, which my test (Tomcat / Struts / Spring) has to unpack and deal with. Why do I want it this way? Because that is the API specification I am given and what I must program against.

Any ideas?
15 years ago

The DatabaseAdapter instances are spawned by the RMI server when a new client connects. At least, this is what I think...



Not true, at least in the default case. The RMI server will spawn a new *thread* to run on the *same* instance for each client. I have not worked out how to make RMI generate a new instance for each client.

Two reasons why you might want to use a factory pattern to enforce a shared instance of Data rather than a singleton:
1. Singletons implemented using static can cause problems in JUnit testing.
2. Can your singleton allow connections to fileA and fileB at the same time? Imagine if the system was expanded to provide hotels and flights via different databases, will your architecture extend?

Raj.

What happened with locking?


I have no idea, but I have not looked very hard to try and find out since I got my results back.
20 years ago
Hi Anton,


Both findDeletedRow() and findNonExistentRow() loop over
1. finding a suitable row
2. trying to lock it by calling attemptLock:
20 years ago
Hi all,

Finally got my results:

General Considerations (maximum = 100): 99
Documentation (maximum = 70): 70
O-O Design (maximum = 30): 30
GUI (maximum = 40): 37
Locking (maximum = 80): 44
Data store (maximum = 40): 40
Network server (maximum = 40): 40

Total 360/400

Overall I think it's a pretty good score, but I'm annoyed that I got caught by that damn 44/80 locking bug! I had a whole heap of JUnit tests for the locking mechanism too! If not for that then it would been near perfect. Still 90% is a score that I would be "over the moon" with back in my university days, I suppose I'm getting pickier with old age

I'd like to thank you all for your advice and spirited discussion (even when I didn't agree with you ). My advice for anyone taking the assigment now is to:
1. keep participating in this forum!
2. keep the back-end stuff simple, I think my over-complicated data access system masked the locking problem to some extent
3. don't neglect the GUI, documentation, etc as that is where you can make or lose a lot of marks and seems to be more open to interpretation

Next stop for me is most likely SCEA, but it won't be until well into next year before I begin.

The following is a heavily abridged version of my design choices file, so that you can see the design I used. I have omitted justifications - you'll need to think through the situations yourselves to see if the techniques are suitable for your solution! Also I have omitted some trivial things like interpretation of 48hr rule.

Time for that beer, you still up for it Andrew?
Raj.


GENERAL CONSIDERATIONS
======================

Additional Materials
--------------------
I include the following additional materials that I used to develop this application:
- JUnit tests for server and data tiers
- Client testing mode functionality, see "User Interface"
These are provided on an as-is basis, do not form part of the core assignment solution; the JUnit test suite can take up to approx 30 secs to run as it runs up to 500 threads at a time.

DOCUMENTATION
=============
User Guide
----------
The user guide / help guide is an HTML file and an embedded image.

Javadoc
-------
In the interests of maintainence I have written Javadoc for coderanch, protected, package level constructs and for private methods.

OBJECT-ORIENTED DESIGN
======================
Overall Design
--------------
This is a three tier solution. The client tier is a generic viewer that can be used to display and book data from an arbitrary database. The server tier provides a connection portal and enforces all business logic. The data access tier provides a logical database service and implements this through a physical file on disk.

The business logic server - client connection is structured in an API-like manner. This enables development of new user interfaces directly on top of the existing server/database system. For example, a desired future direction of the company is to move to web-based presentation...

The server - database connection is similarly structured in an API-like manner.

Data Access Architecture
------------------------
Data access is provided by a Factory object pattern. Database table structure is read by a stream based SchemaSource to instantiate a DBSchema object. Physical record access is provided by an implementation of the DataSource interface (currently RandomAccessFileDataSource) that performs file seeks, reads and writes; it uses DBSchema to understand the file's structure. Data executes logical record manipulations, but delegates the physical read/write to DataSource. LockManager implementations provide row-level locking permission for Data to perform each logical access; Data directly waits on locking permission before executing DataSource operations. Finally, the whole subsystem is wrapped behind a DataFactory instance that coordinates creation of all these objects. See the section "Data" for an in-depth discussion.

User Interface
--------------
I follow the standard Model-View-Controller pattern for the UI. The UI is separated into a top-level frame and several sub-panels: CriteriaPanel for selecting ways to retrieve records, ResultsPanel for showing matching records and optionally extra information about a selected record, and BookPanel for making a booking on a given record.

I use a seperate DataModel that coordinates and controls access to the models underlying each GUI element such as JTable and JComboBox. This ensures that data is centrally coherent; the inbuilt event mechanisms of each model automatically notify the corresponding GUI elements of updates.


USER INTERFACE
==============
Server UI
----------
The server GUI is a relatively simple application. Further issues of the server are discussed in "Server" below.

Client UI
---------
The client GUI has been designed for ease of use by adhering to common GUI design guidelines. Normal flow of interaction is designed in the optimal left-to-right, top-to-bottom style (same as a page of text). From top to bottom the major components of the GUI are:
1. Standard menu bar
2. Criteria pane with several tabbed criteria modes: get all and search
3. Results pane (selectable JTable)
4. Information pane that shows auxiliary information
5. Book pane that allows placement of bookings
6. Status bar (not currently used)

The specification noted that the system may be altered or extended in the future, so the GUI specifically makes allowances for additions (8 possible additions listed...).

The requirements do not explicity state that users should be able to cancel an operation that is executing. The user has to wait until the operation completes or fails, and this can be easily handled by executing the operation in the AWT event thread and showing a wait cursor.

Flexible Query Tools
--------------------
One of the most striking features of the client UI is the tabbed pane containing query modes. I chose this so that other modes of selecting records could be seamlessly added in the future without disturbing the current UI.

The search tab is particularly useable. The search bar is a single row JTable that contains the possible choices for searchable columns. The search bar columns line up with the results table columns underneath and dynamically resize to match their column widths. Searchability is defined in the server tier, so you can add more searchable fields (e.g. a specific price) simply by changing the array in UrlybirdHotelSchema.searchableFields.

Client Test Mode
----------------
The client (both standalone and network versions) can be invoked in test mode using the -test flag:
java -jar runme.jar -test
java -jar runme.jar alone -test

LOCKING
=======
Lock Management
---------------
An interface and 2 implementations are provided for locking records. The LockManager does not need to ensure that a record exists before attempting to lock it; ensuring existence is the responsibility of the calling Data object.

LockManager creation is done via the factory object pattern within DataFactory. DataFactory ensures only one LockManager is created per database file. Different LockManagers are provided for network and standalone modes as discussed below.

Auto-Lock and Manual Lock Methods
---------------------------------
Methods in the Data class that specify a row index to access are not auto locked; these are read(), update() and delete(). Methods that do not specify a row index are auto-locked; these are find() and create(). It is the responsibility of manual locking methods to remove any locks they place. Delete() and update() will throw exceptions if the requested record is not locked for the requesting client.

DATA CLASS
==========
Data Access Architecture
------------------------
There are three elements to the design: data schema, locking, and record level access. These are provided by the DBSchema class, LockManager interface and Data class respectively. The whole system is governed by a factory object pattern.

DBSchema is used to hold the database structural details (number of fields, field names, offsets, etc). Any data access must consult the Schema instance to determine where to seek to, what to read/write and how many bytes are involved. When a database file is loaded a SchemaSource object builds a DBSchema; the DBSchema is then retained for all Data access in that session.

Every Data object is bound to a corresponding DataSource object upon creation.I use a delegation pattern to encapsulate all physical (file related) activities of data access into DataSource. The same pattern holds for DBSchema and SchemaSource.

DataFactory provides a facade for creating Data instances that are correctly connected to the relevant schemas, locks and sources. Neither the DataFactory, DBSchema or LockManager are singletons. This allows for distinct Data-DBSchema-LockManager object clusters to exist for each database file.

Data objects and threading
--------------------------
My solution uses a single instance of Data that can concurrently run from multiple threads. However, the design can also extend (and has been tested) to run as multiple Data instances in seperate threads that simultaneously read and write different sections of the database file.

Creating new rows
-----------------
Create(), like the other methods in DBMain, is multithreaded. This poses significant race problems for identifying and locking candidate rows for new data. The search for candidate row and lock if not already locked (lockFirstVacantRow()) is synchronised. This ensures that each create() thread can find and lock a row for its new data uninterrupted by other create() threads. It also allows two or more create() threads to write sequential new rows beyond EOF at the same time without error.

SERVER
======

Server Design
-------------
The business logic server consists of two main classes that form a natural synergy with the data layer. UrlybirdHotelServer acts as a business logic server for records transactions through DBMain. UrlybirdHotelSchema acts a business logic structure layer that provides a presentation ready version of the database structure in DBSchema. Servable is the RMI interface for UrlybirdHotelServer, and UrlybirdHotelServer delegates client structure requests to UrlybirdHotelSchema.

The Servable interface is fairly generic; the specific business logic is coded into UrlybirdHotelServer and UrlybirdHotelSchema. This means that the same client can be used with the same Servable interface to access another database with different business rules. Each implementation of Servable is registered with the RMI service through a launcher, raising the possibility that other databases/business servers can come online with the same service and the client can connect to either of them equally.

RMI Networking
--------------
I chose to use RMI for the networking component due to the programmatic ease that it offers.
20 years ago
Hi Jared,

I used a different design which you might like to consider. I placed each selection combobox in a single horizontal line. Every search field lines up vertically with its column in the results table below. Adding a new search field is easy because you just place it above its position in the table.

Raj.

Originally posted by Mark Thomson:

1. I want to have multiple instance of my Data Access class. Each instance will have 2 static members. A RandomAccessFile and a collection ( to store my locked records)

I am also a little unsure of implementing the Data layer in this way ( multiple instances ) as I am ultimately locking on a single instance of my RandomAccessFile. ( not allowing concurrent reads / writes etc )



You should be careful with this approach. If you are using RMI then only one instance of the server object (let's call it Data for the sake of simplicity) will be created. It will be run concurrently from multiple threads; one for each client connection.

I originally had a similar design except that each Data instance had its own RAF and no two RAFs could access the same record at the same time. Was all very safe, etc, but RMI kept executing the same shared Data instance.

Raj.
Congratulations Anton

I am sitting my essay exam in a couple of hours' time.

Raj.
20 years ago

Originally posted by peter wooster:
It was possible to deselect all of them by pressing one button half way in. This behaviour isn't possible on my current tuner.



Agreed, I remember those old tuners

IMHO it takes the same screen real estate to post a "none" radio button as it does to post a "clear" button, but the user interface is much cleaner.

I also don't know why you'd need it for the assignment...
I'd suggest an alternative, namely that you cater for the fact that one *has* to be selected. You could have a checkbox that disables the whole button group or another visual radio button for "none". This will fit in with both the programmatic model and the learned behaviour of radio buttons by your users.
Hi Inuka,

No I'm not caching records. I've haven't exprienced any problems using RAF that necessitate flushing output or closing the file and
reopening. I would think that constantly closing and reopening introduces lots
more points where an IOException or FileNotFoundException could complicate your code.

Yes I am using RMI. The class count is because my solution is very modular and allows different things to be dropped in and out at will.

Raj.
Hi,

I'm about to submit my assigment, any last minute advice on boundary conditions to test, things to package in the submission, etc?

Here are my assignment stats:
46 classes, interfaces and inner classes (not incl anonymous classes)
9 packages
7000 lines of Javadoc'ed code, approx 4000 lines of non-comment code
45 JUnit tests comprising 1700 lines of code

Thanks,
Raj.
Hi,

I'm writing up my javadoc at the moment and I notice that most of my doc for the GUI stuff is very brief. I put this down to the code being mostly unremarkable form builder stuff and registering of event listeners, etc.

Is this terseness ok or am I just being too lazy? It seems straightforward to me what a gui form does in contrast to a non-gui method that provides some sort service to client code.

Did the other candidates who got full marks for documentation provide detailed or terse javadoc for their gui code?

Raj.