Classes that maintain the psedo queue and allow for interaction with the queue. This package provides most of the functionality of NINJa, since NINJa can, in its simplest terms, be described as a queue of print jobs.

NINJa provides two interfaces. The first interface is a PrintService. This provides the functionality of printing to the queue (i.e. inserting a document onto the queue). Printing to a queue is the same as printing to a physical printer. A DocPrintJob is created from the queue and the job is printed with a certain document and attributes. Once the job is printed to the queue, this service is useless as far as the job is concerned. The job is considered complete just as a physical printer had printed a piece of paper.

The second interface is a JobQueue service. The JobQueue fulfills requests such as removing and starting jobs. These jobs correspond to the jobs which were printed to the queue, but they are not the same jobs. An example is inserting a job onto the queue. A job that has printed to the queue will have the JobState of COMPLETED. The newly created job created by the insertion will have the JobState of PENDING. The printServices are located by the provided PrintServiceLookup and can be set by the user.

These two interfaces are published via Jini as one service. A single proxy is used as an entry point into these interfaces. The proxy has the responsibility of hiding the remoteness of the service. As such, the proxy must account for lost RemoteEvents, RMI exceptions. The proxy acts as a local version of a PrintService and a JobQueue.

The proxy has the additional role of liason between remote and local objects. If a local object wants to listen to a DocPrintJob sitting on a remote queue, several things must happen. The proxy must have a local representation of the remote DocPrintJob. The proxy must listen to events generated by the remote DocPrintJob. The proxy must forward received events to the local representation of the DocPrintJob. If any events are lost, the proxy must account for the missing events if necessary. The local DocPrintJob must then notify the local listener of the event. There are several reasons for this approach as opposed to rmi stubbing. RMI stubs do not share the same interfaces as their local counterparts because they must account for RMI exceptions. For example, a programmer could not implement printing to a NINJa queue in the exact same way as printing to a normal printer. RMI would not be able to account for lost events. A "job completed" event could go unnoticed by the local listener. The stub must also have a mapping between local objects and their server counterparts. An alternative implementation would have proxies and RMI exported objects for each server object. Instead of having the proxy handle DocPrintJobs, this could be delegated to rmi. A local object could add a listener to a print job proxy which would forward any events directly to the listener without any mapping. However, this would limit the scalability due to allocating resources per DocPrintJobs as opposed to per service.