Throughout this section of the documentatinon we will refer to the java directory inside the templates directory $JTBASE. The source code for the Java templates is located in $JTBASE/src. There should be four subdirectories in $JTBASE/src: common, generator, science, and validator.
We will first examine the work unit generator template, located in the $JTBASE/src/generator directory. The class that needs to be edited to create a functional work unit generator is the WorkUnitGenerator class, which can be found in the file $JTBASE/src/generator/WorkUnitGenerator.java. The best way to learn what needs to be implemented is to examine the WorkUnitGenerator class, which is thoroughly documented, and contains the string TODO wherever there is something that may need to be implemented or changed. There are at least two methods that must be implemented in that class: recoverState and generateWorkUnit. If the work unit generator were ever restarted, it would need some way to reinitialize its state information so that it could resume generating work units from the appropriate place in the science data. The purpose of the recoverState method is to reinitialize this state information. This method uses the supplied WorkGeneratorClient class to retrieve the last work unit that was generated from the server via XML-RPC. If the server throws an Exception, it indicates that there were no previously generated work units, so the work unit generator should begin generating the first work unit. Otherwise it will return a work unit, which can be inspected to determine where to resume generating the next work unit.
The other WorkUnitGenerator method that needs to be edited is the generateWorkUnit method. This method generates a work unit from the science data, converts that work unit into a byte array, and returns that byte array to the calling method. Another method that may need to be edited is sendWorkUnit. This method uses the WorkGeneratorClient class to send the generated work unit to the project server. However, there are several options for how the work unit can be added. The simplest way is to send only the byte array containing the work unit data to the server. It is also possible to specify other options, such as the desired work unit ID, priority, point value, and expiration time. There are several combinations of these options that can be used, with each combination corresponding to a call to a different overloaded WorkGeneratorClient.sendWorkUnit method. These methods are documented in sendWorkUnit. The last aspect of the template that may need to be changed is the $JTBASE/src/generator/WorkUnitGeneratorController.java. The main method in that class controls when the work unit generator should generate more work units and how many new work units should be generated at once.
The next component template that needs to be modified is the science application template, located in the $JTBASE/src/science directory. To create a working science application from the template it is necessary to edit the ScienceDataProcessor class in the $JTBASE/src/science/ScienceDataProcessor.java file. The methods in that class that will need to be edited are computeResult and scienceAlgorithm, although these two methods could be combined into a single method if desired. The computeResult method will be started in its own low-priority thread by the ComputeThread class. The work unit data, a byte array, is passed into the ScienceDataProcessor class in its constructor. If the science application uses check-pointing, the computeResult method should first attempt to retrieve the last check-point from the project client; the template code for the computeResult method demonstrates how to do this. If any check-point was found, it should be used to initialize the science algorithm, possibly by setting certain private member variables. The computeResult method should then execute the science algorithm on the work unit and produce a result. The result has to be converted into a byte array before being returned by the computeResult method.
It is possible to perform all necessary computations in the computeResult method, but it is usually a cleaner design to use a separate method to actually execute the science algorithm; the scienceAlgorithm method is used for this purpose. The intended design is to use the computeResult method to interpret the work unit and perform any initialization that needs to occur. Then the computeResult method can call the scienceAlgorithm method to compute the result for the work unit. After a result has been computed, the computeResult method can convert the result into the byte array that needs to be returned. During the execution of the science algorithm, check-points can periodically be saved by the project client. The template source for the scienceAlgorithm method demonstrates how to do this.
The third template component, the result validator, is optional. If result validation is required, this component can be implemented. The template for the result validator is located in $JTBASE/src/validator. The class that needs to be edited is ResultValidator, which is located in the file $JTBASE/src/validator/ResultValidator.java. There are three methods that need to be implemented, each corresponding to a different type of validation: validateSingleResult, selectCanonicalResult, and validateSpotCheck. The validateSingleResult method decides whether a single result is valid by examining the result data. The method should return true if the result was valid or false if the result was not valid. If necessary, it is possible to retrieve the work unit from which that result was generated; this operation is demonstrated in the template source. The selectCanonicalResult method examines the set of valid results returned for a work unit and selects one of those results to be the canonical result. The method should return a string, the result ID of the canonical result. If it is necessary to examine the work unit for which the results were computed, it is possible to retrieve that work unit data as demonstrated in the template source. The validateSpotCheck method decides whether a client passed a spot-check. It does so by comparing the spot-check result data computed by the client to the accepted spot-check result data that was computed by the project server. As in the other two methods, it is possible to examine the work unit from which the spot-check result was computed. This method should return true if the client passed the spot-check and false if it failed the spot-check.
Another optional template component is the assimilator. Although it is optional, most projects will find it necessary or convenient to use this component. The assimilator extracts valid results from the project database. The assimilator template is in $JTBASE/src/assimilator. There is only one method that needs to be modified: boolean Assimilator.assimilateNextWorkUnitResultPair(Result r) in the file $JTBASE/src/assimilator/Assimilator.java. This method should assimilate the given result, whatever that means for your specific project. For example, you may wish to insert the result data into another database for later analysis or recombination with other results, or you may wish to send a message to another component based on the contents of the result. The work unit from which the result was computed is also available for assimilation by calling r.getWorkUnit(). If your assimilateNextWorkUnitResultPair method returns true, the work unit that was just assimilated will be deleted from the project database. If your method returns false, the result will not be deleted from the project database. However, if your method returns false, your assimilator will keep receiving the same result every time it asks for the next result to be assimilated until that result is deleted from the database. Therefore, your method should only return false if an error occurred and the result needs to be re-assimilated.