Team. The contracts have been placed in the controller application. If a contract is violated, we raise an exception which the main method catches. The source code is below. I would appreciate any insights or comments. Also, please forgive another skipped day, Wednesday, 12.03.2012. I am wrapping up an assignment with a small business client whose billing cycle is just ending. So, I have been very busy. La-La.
//BEGIN JAVA CAB SOURCE
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package cab;
/**
* The CAB eventually will be the kernel of the CABOOSE general purpose servlet.
* Implicit Contract Requirements and Guidelines:
* The CAB contracts with support classes that have rendering methods which
* return String content. These methods also must have the signature
* public String methodName( java.util.HashMap<String,String> aMapParameter )
* by implicit contract. If they do not, the reflection activities which
* automatically invoke them will fail since they cannot find the requested
* method. Class, method, tile replacement, and stencil filename identifiers are
* all stored in a file called directory.xml which contain a mapping between
* each item.
*
* @author Jody Sharpe
*/
public class CAB {
//Simulated URL String. We will eventually get all of our input from the
//the servlet's Request object.
String request = "?project=caboose&module=skeleton&create_date=10.30.2014";
//A data structure for holding a description of the page, stencil, and tile
//directory. It is keyed by the page name. Each value in the structure is a
//ViewModel. See the description of this inner class for information on its
//content and structure.
java.util.HashMap<String,ViewModel> aDirectoryMap = null;
//private inner class representing a model of a single view which the
//controller can return.
private class ViewModel {
//The stencil filename.
private String theStencilName = null;
//A data structure which holds the tile identifier as a key and the name
//of the class and method for rendering the the tile as a
//comma seperated value
private java.util.HashMap<String,String> theTileRendererMappings = null;
//This method assigns the stencil filename
void settingTheStencilName( String aStencilName ) throws Exception{
//Opening Contract
//The stencil name is not a null or empty string.
if ( aStencilName == null || aStencilName.length() == 0 ){
throw new Exception("Stencil name is null or empty");
}
theStencilName = aStencilName;
//Closing Contract (Implicit)
//The stencil name is a non-empty string.
}
//This method assigns the tile renderer mappings
void settingTheTileRendererMappings( java.util.HashMap<String,String> aSetOfTileRendererMappings ) throws Exception{
//Opening Contract
//The set of mappings between tiles and renderer methods is not null
//It might be of size zero if there soes not exist any replacment tiles
//within the stencil.
if ( aSetOfTileRendererMappings == null ){
throw new Exception("The mapping between tiles and render methods is null");
}
theTileRendererMappings = aSetOfTileRendererMappings;
//Closing Contract (Implicit)
//The tile renderer mappings is not null. They might be empty.
}
//This method returns the stencil file name
String gettingTheStencilName(){
//Invariant Contract (Implicit)
//The stencil name is a non-empty string.
return( theStencilName );
}
//This method retruns the tile renderer mappings data structure
java.util.HashMap<String,String> gettingTheTileRendererMappings(){
//Invariant Contract (Implicit)
//The tile renderer mappings are not null. They might be empty.
return( theTileRendererMappings );
}
}
//This method extracts the content of a stencil from the file system based
//upon a file name. In the future this method will need adapting so it
//retrieves the proper file in a web server's file system using
//the servlet context.
String gettingTheResponseStencil(String aViewFileName) throws Exception {
//Opening Contract
//The file name of the view stencil is not a null or empty string.
if ( aViewFileName == null || aViewFileName.length() == 0 ){
throw new Exception("The filename of the view stencil is null or empty");
}
java.io.BufferedReader aStencilReader = new java.io.BufferedReader(new java.io.FileReader(aViewFileName));
String theStencilContent = "", theNextLine = null;
while ((theNextLine = aStencilReader.readLine()) != null) {
theStencilContent += theNextLine;
}
//Closing Contract
//The stencil content of the view in not its initial value of an empty string.
if ( theStencilContent.length() == 0 ){
throw new Exception("The stencil content of the view stencil is empty");
}
return (theStencilContent);
}
//This method extracts the name and value pairs from the input query string.
//We assume that it is not url encoded. For the generic servlet edition of
//the cab, this method will not be useful. But it might be of use for a
//command-line based edition of the cab for report writing or rendering
//windowing applications.
java.util.HashMap<String, String> mappingTheRequestNameValuePairs(String aRequest) throws Exception{
java.util.HashMap<String, String> aMap = new java.util.HashMap<String, String>();
//Opening Contract
//If the request query string is null or empty, return an empty aMap
if ( aRequest == null || aRequest.length() == 0 ){
return aMap;
}
aRequest = aRequest.replace("?", "");
String[] theNameValuePairs = aRequest.split("&");
for (String aNameValuePair : theNameValuePairs) {
final int theName = 0, theValue = 1;
String[] aTuple = aNameValuePair.split("=");
aMap.put(aTuple[theName], aTuple[theValue]);
}
//Closing Contract
//The Map cannot empty on the input of a non-empty request query string
if ( aMap.size() == 0){
throw new Exception("The input key-value map is empty. Could not interpret the query string.");
}
return aMap;
}
//This model populates a view stencil with the content generated by
//dynamically invoking reendering methods and replacing their associated
//user-defined tile identifiers ( a.k.a stencil replacement variables ).
//See the contract guideline in the header comments of this document.
String preparingTheResponse(String theViewId, java.util.HashMap<String, String> aRequestMap) throws Exception {
//Opening Contract
//The id of the view cannot be null or empty
if ( theViewId == null || theViewId.length() == 0 ){
throw new Exception("The view identifier is null or empty.");
}
//Opening Contract (Implicit)
//The size of the request map is zero or larger
ViewModel aViewModel = (ViewModel) aDirectoryMap.get( theViewId );
//Intermediate Contract
//The view model cannot be null.
if ( aViewModel == null ){
throw new Exception("The view model was not found.");
}
String [] aTileClassAndMethod = null;
String theStencilContent = gettingTheResponseStencil( aViewModel.gettingTheStencilName() );
//Intermediate Contract (Implicit)
//The stencil content of the view in not an empty string.
java.util.HashMap<String,String> someTileRenderMappings = aViewModel.gettingTheTileRendererMappings();
//Intermediate Contract (Implicit)
//The tile renderer mappings are not null. They might be empty.
for( String aTileId : someTileRenderMappings.keySet()){
//Intermediate Contract Within Evaluation (.get) (Implicit)
//The tile class and method is a non-empty string whcih contains a single
//comma as a CSV string.
aTileClassAndMethod = ((String)someTileRenderMappings.get( aTileId )).split(",");
//Intermediate Contract
//The class and method names for the tile renderer cannot be null or empty.
if ( aTileClassAndMethod[0] == null || aTileClassAndMethod[1] == null || aTileClassAndMethod[0].length() == 0 || aTileClassAndMethod[1].length() == 0 ){
throw new Exception("The class or method name for the tile renderer was null or empty.");
}
//Start Reflection Activities
Class aClass = Class.forName( aTileClassAndMethod[0] );
Class [] theFullyQualifiedParameterTypeClasses = new Class[1];
theFullyQualifiedParameterTypeClasses[0] = (new java.util.HashMap<String,String>()).getClass();
Object [] theParameterObjectList= new Object [1];
theParameterObjectList[0] = aRequestMap;
theStencilContent = theStencilContent.replace( aTileId , (String) ( aClass.getMethod(aTileClassAndMethod[1],theFullyQualifiedParameterTypeClasses) ).invoke((aClass.getConstructor()).newInstance(), theParameterObjectList));
//End Reflection Activities
}
//Closing Contract (Implicit)
//The class and method for the given name exist among the controller application bundle.
return (theStencilContent);
}
//This model extracts the information from the directory.xml file using an
//XML reader that creates a DOM from which the method creates a user-defined
//map between view names and ViewModel objects. In the future, we might
//utilize a SAX XML reader skipping the creation of the DOM and directly
//create the ViewModel map data structure. This should result in a slight
//processing speed up although we will only be during it once during a servlet
//session and storing the utlimate view model map in the servlet's session
//object. Directoy.xml represents a model mapping for the entire application.
//Based upon the length of this method ( 50+ lines of code ) it should
//likely be subdivided and invoke a few private utility methods for
//completing its work.
void readingTheDirectoryXMLFile(String theViewId) throws Exception {
//Opening Contract
//The id of the view cannot be null or empty
if ( theViewId == null || theViewId.length() == 0 ){
throw new Exception("The view identifier is null or empty.");
}
String aViewId = null;
String aStencil = null;
String aTileId = null;
String aTileClass = null;
String aTileMethod = null;
aDirectoryMap = new java.util.HashMap<String, ViewModel>();
javax.xml.parsers.DocumentBuilderFactory theDocumentBuilderFactory =
javax.xml.parsers.DocumentBuilderFactory.newInstance();
javax.xml.parsers.DocumentBuilder theDocumentBuilder = theDocumentBuilderFactory.newDocumentBuilder();
//Intermediate Contract (implicit)
//The argument for the java.io.File constructor is the canonical name
//for all CABOOSE bundles and is XML. (It will differ in the final version).
java.io.File aFile = new java.io.File("./src/cab/directory.xml");
org.w3c.dom.Document theDocument = theDocumentBuilder.parse(aFile);
theDocument.getDocumentElement().normalize();
org.w3c.dom.NodeList theModelNodeList = theDocument.getElementsByTagName("model");
for (int aModelNodeIndex = 0; aModelNodeIndex < theModelNodeList.getLength(); aModelNodeIndex++) {
org.w3c.dom.Node aModelNode = theModelNodeList.item(aModelNodeIndex);
if (aModelNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
org.w3c.dom.Element aModelElement = (org.w3c.dom.Element) aModelNode;
org.w3c.dom.NodeList theViewNodeList =
aModelElement.getElementsByTagName("view");
for (int aViewNodeIndex = 0; aViewNodeIndex < theViewNodeList.getLength(); aViewNodeIndex++) {
org.w3c.dom.Node aViewNode = (org.w3c.dom.Node) theViewNodeList.item(aViewNodeIndex);
if (aViewNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
org.w3c.dom.Element aViewElement = (org.w3c.dom.Element) aViewNode;
ViewModel aViewModel = new ViewModel();
aViewId = aViewElement.getAttribute("id");
aStencil = aViewElement.getAttribute("stencil");
aViewModel.settingTheStencilName(aStencil);
java.util.HashMap<String,String> someTileRendererMappings = new java.util.HashMap<String,String>();
org.w3c.dom.NodeList theTileNodeList = aViewElement.getElementsByTagName("tile");
for (int aTileNodeIndex = 0; aTileNodeIndex < theTileNodeList.getLength(); aTileNodeIndex++) {
org.w3c.dom.Node aTileNode = (org.w3c.dom.Node) theTileNodeList.item(aTileNodeIndex);
if (aTileNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
org.w3c.dom.Element aTileElement = (org.w3c.dom.Element) aTileNode;
aTileId = aTileElement.getAttribute("id");
aTileClass = aTileElement.getAttribute("class");
aTileMethod = aTileElement.getAttribute("method");
someTileRendererMappings.put( aTileId, aTileClass + "," + aTileMethod );
}
}
aViewModel.settingTheTileRendererMappings(someTileRendererMappings);
aDirectoryMap.put(aViewId, aViewModel);
}
}
}
}
//Closing Contract
//The directory amp cannot be empty if the CAB returns a view
if ( aDirectoryMap.size() == 0 ){
throw new Exception("The application view directory map is empty.");
}
}
/**
* @param args the command line arguments
* This is the main entry point of the application. It builds the request
* map from the the "temporary" query string. It then build the view model
* mappings from the directory.xml file by side-effect. Finally it prepares
* and presents a response. All in less than 0.5 KLOC including
* the comments. The number of lines of code are not critical in application.
* The features it provides in the lines it has is most important.
*/
public static void main(String[] args) {
// TODO code application logic here
CAB aCAB = new CAB();
try {
java.util.HashMap<String, String> aRequestMap = aCAB.mappingTheRequestNameValuePairs(aCAB.request);
aCAB.readingTheDirectoryXMLFile("test_page");
System.out.println(aCAB.preparingTheResponse("test_page", aRequestMap));
} catch (Exception e) {
e.printStackTrace();
}
}
}
//END JAVA CAB SOURCE
No comments:
Post a Comment