Showing posts with label Development. Show all posts
Showing posts with label Development. Show all posts

Monday, May 5, 2014

WaveMaker: Rapid Web App Generator


Now-a-days web applications are demanded like customers buying goods from the retailers' shops. In fact companies like Google, Apple, Microsoft and others have already introduced concepts like application market or store on mobile and other areas as well. Software applications are no more expected to follow a baby-birth process these days which demands for a high speed rapid application development or generation. During the last few years MDA and other paradigms have attracted us toward meta-programming and different code generators. But they were not matured enough to generate a full-fledged web application so far. 
Looking at the future demand and technology trend, I was in search of such a web application generator which can generate simple web applications for database CRUD (Create, Read, Update, Delete) operations. I was excited with Naked Objects (NO) framework 
(
http://www.nakedobjects.org/) and anticipating a vital outcome on this direction. Eventually Apache Isis (http://isis.apache.org/index.html) attracted me since this is a Java based implementation of NO. It uses But the project is in incubator and has no definite road map for release and the product has some areas still grey. There is another implementation of NO on .NET known as NuGET. Hope readers will pardon my Java inclination here. 
Apache Isis is a framework for rapidly developing domain-driven apps in Java. Write your business logic in entities, domain services and repositories, and the framework dynamically (at runtime) generates a representation of that domain model as a webapp or as a RESTful API. Use for prototyping or production. Apache Isis follows the hexagonal architecture pattern (also known as the onion architecture or ports-and-adapters architecture). It places the domain model in the middle, with presentation, persistence and other services dependent upon the domain model. Though Apache Isis uses a very promising architecture with latest Open Source frameworks like Wicket, JPA, Hibernate and RESTFul communication but the amount of change to be made to enable it for professional usage is little de-motivating.
On continuation of my search someone referred WaveMaker ( http://www.wavemaker.com/) to me. While exploring WaveMaker (WM), ultimately I felt like I found something which falls in line with my hunt. WM is easy to deploy and learn. They have nice videos and tutorials to jump start development. The nice and browser based integrated development environment (IDE) for development and deployment. Most of the well known databases can be integrated with the IDE with export and import features. The IDE offers options to develop entity objects that can be engineered forward onto database tables. Also when the existing tables can be imported to WM, it generates entity objects automatically. WM uses DOJO for frontend code generation and hibernate for object relational mapping (ORM). 
It can also link with LDAP or database for user authentication and authorization. It uses a panel with DOJO and HTML elements to be use on the GUI by simple drag-drop feature. Each element has its own property panel that reminds me of IDEs like JBuilder, Visual Age, Power Builder and Visual Studio. It uses Tomcat as an embedded server to run the IDE and test run applications. WM provided limited numbers of GUI templates with pre-generated style-sheets which can be further modified in the IDE.

Wednesday, October 9, 2013

Integrated Software Development Factory: An Idea

Software Development: The Process


Software development and delivery process is the backbone of business for a professional organization in software industry. Software development is a team activity involving more than one professional with defined set of roles and responsibilities. The involvement of multiple people in the process requires a well defined work flow to be maintained. Apart from human resources the software development process (SDP) typically requires development software tools, platforms and hardware infrastructure and most importantly a strong collaboration mechanism within the team involving the artifacts of the delivery.  Ideally a software development and delivery process (as per the water falls model) involves certain technical steps or phases as briefly described below. Phases including financial, business and management activities such as scoping, estimation, planning are not included here.

Requirement Study & Analysis: Where a person (Requirement Analyst) interacts with the user or customer to understand the process and requirement that the software (to be developed) should implement. The information captured in this phase is generally captured in Software Requirement Specification (SRS). Test cases to validate the system (after development) are also defined following this phase.

Architecture & Design: Specifying and documenting the architecture and design for the software system to visualize the basic structure or model which should be followed to construct the software system. This phase can have two primary steps such as - 
·         Defining the business architecture or functional design by covering the business processes and logic
·         Defining the technical architecture or system design explaining the structure of system components required to implement the business processes.
Design and Architecture specifications are documented in this phase.
Development & Coding: In this phase, different software components are built or developed according to the design specified in the previous phase and tested. The outcome of this phase is source code and executable code.
Deployment & System Testing: All components developed are put together and tested to evaluate the ability of the system to provide the functionalities specified during the requirement capturing phase. Test cases defined during the requirement capturing phase are executed in this phase and test results are captured and defects found during testing are fixed.
User Acceptance: Once system testing is completed the software is submitted to the customer for final acceptance. This phase ideally have customer testing involvement. Defect fixing activities (if any) are also involved in this phase.
Operation & Maintenance: Once the software is accepted by the customer, it is finally delivered and installed for final use. In case any change in requirement takes place or any problems are identified by the customer after the delivery is done, necessary changes to implement new requirement or to fix problems are implemented in the system. In this case a new waterfall (starting with Requirement Analysis phase) can be followed for each new requirement or defect. Please refer to the waterfall model at http://en.wikipedia.org/wiki/Waterfall_model.
Monitoring & Tracking: Overall monitoring and tracking activities for the entire project are performed by a project manager (PM) throughout the phases of a software development lifecycle (SDLC).
The steps mentioned above are depicted in figure 1 below.
Figure 1: Software development lifecycle phases


Pain Areas in the Process


Æ      Majority of employees in a software development organization (SDO) are involved in the process of software development for customers. The development activities (projects) are performed by forming project teams consisting of different people. Typically a lead or manager is involved to monitor and track a project. Apart from the project team members (PTM) other stakeholders such as reviewers, users and customer also get involved throughout the lifecycle of a project. Nowadays most of the stakeholders come from different geographic locations even with different time zones. This is the reason why a project requires a strong collaboration mechanism to be in place.
Æ      Usage of standard practices, software tools and frameworks increases the efficiency of the software under development by reducing defects and improving performance, flexibility, extensibility etc. Enforcing standards and best practices over a team of people can be a challenge without a centralized control and strong collaboration.
Æ      The process of requirement study & analysis does not only involve human interactions, it can also involve several documents and pre-existing software systems as well. Sometimes existing source code from the previously existing system can also be taken as the input for requirement. Recovering the design and logic from an existing system or source code might need a reverse engineering mechanism to be in place.
Æ      Proper event tracking technique always helps in getting everyone in a team notified about the latest updates and help them to react promptly.
Æ      The next problem commonly faced is increasing gap in communication which often results in a big difference between the requirement and the development software system. Figure 2 illustrates the same with a popular cartoon. Usually this problem leads to wastage of investment and following rework.

Figure 2: Gap between requirement and implemented system

Æ      Misunderstandings in certain areas of requirement between a person with and without software background create major problems in communication as illustrated by the famous Dilbert Cartoon in figure3. Ideally a predefined flow of communication and precisely designated requirement capturing interface with relevant questions and clarifications can help in reducing such gaps. Educating the stakeholder (without software background) a little also helps here.

Figure 3: Misunderstanding in requirement capturing

Æ      Communication Gaps can exist between the requirement analyst (who understands the requirement from the customer or user) and the architect or designer which can be minimized by recording requirement with all necessary information which can help the architect or designer. Similar gaps can exist between designer and developer which lead to defects introduced during development phase.
Æ      Sometimes manual effort spent in build, deployment and installation procedures leads to human dependency. This process can be made automatic and time-driven with the help of a Continuous Integration (http://www.thoughtworks.com/continuous-integration) technique.
Æ      Rather than putting the test cases in document only and executing manually during the testing phase, Test Driven Development (TDD) Tools can be used to record the use cases and execute them automatically by integrating the same with Continuous Integration tools. Martin Fowler’s article (http://www.martinfowler.com/articles/continuousIntegration.html) on Continuous Integration explains this more clearly.
Æ      Overall a central repository with version control mechanism is a very important component to keep all artifacts which are referred (e.g. customer supplied documents) and produced (e.g. SRS, Design Document, Source Code etc.) during a project secured.

Goals to Achieve


The primary goal of software development process is to produce deliverables according to requirement with expected quality. The artifacts produced by a project which can be treated as deliverables are usually the SRS, architecture document, design document or source code etc. The final goal of a software development project should ideally be a working piece of software meeting customer’s requirement.
During SDLC, injection of defects is inevitable. Defects are introduced in different phases of a software development project such as Requirement Analysis, Design or Development. The impact of defects on delivery process and cost to fix them is directly proportional with time. The bugs discovered at the end of the SDLC would cost more to get fixed. So it is better, to find problems in the initial state of SDLC and fix them at the earliest. Based on a study (https://buildsecurityin.us-cert.gov/articles/best-practices/code-analysis/business-case), it has been found that, the savings potential from early defect detection is huge; nearly 60 percent of all defects usually exist by design phase.  Figure 4 shows how the cost to fix a defect increases with time.
There are certain techniques such as Pair Programming (PP), Continuous Integration (CI), and Test Driven Development (TDD) etc. which are found to be highly effective in catching the bugs early. While we think of an integrated software development environment (ISDE) as a solution, these techniques need to be considered as well. So we are assuming that, our solution will be equipped to facilitate such techniques. For this article, let’s assume a name for the solution as Integrated Software Development Factory (iSDF).

Figure 4: Increasing Cost to Fix a Defect with time

Integrated Software Development Factory (iSDF): In Search of a Pain Killer


A discussion on so many pain areas together is enough to get a strong headache for anyone. So if we quickly look for a pain killer, a solution to address all primary pain areas in developing a software solution or system, we need to map the resolutions of the pain areas as use cases to the pain killer. Let’s name this pain killer as Integrated Software Development Factory (iSDF). Typical use cases for iSDF deduced from the pain areas described above are the following.
·         Submit Requirement:  The software end-user or customer should be able to enter his / her requirement in our iSDF using a graphical user interface. The customer should also be able to submit associated documents supporting the requirement. The requirement will be stored in system and later referred by other involved in the project team. Once a requirement is submitted, all relevant stakeholders such as requirement analyst, PM and architect should be notified to take necessary actions to process the same.

·         Study & Analyze Requirement: The requirement analyst should have an interface to view the requirement statements and supporting documents entered by the customer for analysis. The analyst should also be able to interact with the end-user / customer for clarifications on the requirement. The analyst should be able to produce and submit an SRS document according to pre-defined format or template. Once the SRS is submitted, required stakeholders such as PM and architect should be notified to take necessary actions to process the same. iSDF should capture requirement in predefined format such as use case or user story so that other PTMs can refer to the same following a specific standard and paradigm (e.g. Object-Oriented Paradigm). Specially, the designer should be able to refer to the use cases or user stories by using a design tool integrated with iSDF. This will help in reducing the interpretation gap between requirement and design.
·         Define Architecture: iSDF should provide an interface for the Architects to view SRS and define the architecture for the software application based on the SRS submitted by the analyst. Relevant project members such as PM and architecture reviewer should be notified while architecture is defined and submitted in iSDF.

·         Review Architecture: Once the architecture is produced, a technical reviewer should be able to review the architecture and provide comments on the same. The architect will incorporate changes suggested by the reviewer (if any) and update the architecture document. Proper notification mechanism (to PM and Architect) should be in place on review comments submission.

·         Define Test Cases: iSDF should provide an interface for the Testers to view requirement and define required test cases for software application based on the SRS submitted by the analyst. Relevant project members such as PM, analyst and customer (if required) should be notified while test cases are identified and submitted in iSDF.

·         Review Test Cases: Once test cases are produced, a reviewer (ideally analyst or business users) should be able to review the test cases and provide comments on the same. The test case creator will incorporate changes suggested by the reviewer (if any) and update the test cases. Proper notification mechanism (to PM, analyst and other concerned members) should be in place on review comments submission.

·         Define Design: Once the architecture is finalized after review, the designer should be notified to start producing the software design. iSDF should provide an interface for the designer to view the requirement (in form of use case or user story), architecture and supporting documents such as SRS and architecture document. The designer should be able produce the software application design by using some design tools integration with iSDF and submit. Once submitted iSDF will store the design and relevant documents and notify the PM and design reviewer.

·         Review Design: Once the design is created, a technical reviewer should be able to review the design and provide comments on the same. The designer will incorporate changes suggested by the reviewer (if any) and update the design document. Proper notification mechanism (to PM and designer) should be in place on review comments submission.

·         Develop & Build: The next phase to design is development and build, which primary includes the generation of source code in desired programming languages, customization and configuration. The developers should be provided with proper interface (in iSDF) to be able to build or develop software applications to work in this phase.
Integrated development environments (IDE) like Eclipse and NetBeans are few examples of development tools which can be integrated with iSDF so that, design models (e.g. UML) can be viewed and referred using the IDE. Code generation options can also be integrated to generate code from the design models whenever required. The source code, configuration files and other associated artifacts produced during this phase should be stored in a centralized repository secured by a version control system such as Git, SVN and CVS etc. so that everyone in a development team should be able to share and update the source code as required.
An automatic build tool can be integrated with iSDF so that, the build process can be scheduled in a periodic manner or based on an event (such as on any update in source code repository). Usually this feature is available in typical Continuous Integration (CI) tools like Hudson, Apache Gump and CruiseControl etc. Once triggered by a time-driven or a event-driven approach, the scope of activities for a CI tool should be to check out the source code and configuration files from version controlled repository, compile and build the same, deploy the application on an execution platform e.g. an application server for a test tool to start testing.
Technical reviewers should be notified on any code change or repository update so that, the new code change can be reviewed. 

Figure 5: iSDF use cases


·         Review Code: Once a new code or modified piece of code or other artifacts are submitted in repository, a notification should be send out to assigned reviewer to review the new or modified artifact and provide comments or approve the change. Once the comments or approval is posted the concerned developer or changer should be notified by iSDF notification mechanism. For any clarification, an integrated collaboration mechanism can be used by the reviewer and changer if required. To support required activities during the review, a code review interface, a notification, a collaboration mechanism and workflow should be in place.

·         Test: This is an important phase in a SDLC. iSDF should have an interface for the testers to produce test cases associated with the requirement of a project during the requirement analysis phase. Once the development is completed, testers should be able to configure the test cases in automated testing tools integrated with iSDF. For example, Fitness is a very useful wiki based tool to implement Test Driven Development (TDD). Such tools can be integrated with the CI layer (within iSDF) so that, build, deployment and testing can be automated removing human dependencies. Once test results are produced, a notification mechanism can circulate the results to concerned parties (e.g. developer, project manager and tester etc.) for further actions.

·         Defect Tracking: Defects can be recorded and monitored using a Defect Tracking tool such as Bugzilla, Jira, Trac, Traxis and Mantis etc. In order to do this, iSDF should be integrated with a Defect Tracking Tool. While defects are introduced concerned parties can be notified by the system for further actions.

·         Deploy & Install: Different versions of application execution platforms or environments for development, testing, staging and production can be set up and integration with iSDF so that, once the application is developed and tested is can be easily deployed or installed on a designated execution environment. Developers can use a development environment to deploy and perform unit testing on their code. On completion of development and code review, individual code changes can be integrated and deployed on a testing environment for the testers to start testing. Once the testing is over, the tested application can be deployed on staging environment for customer’s acceptance testing or review.

·         Acceptance by Customer: Our iSDF solution should also provide an interface for the customers or business users to test and review the completed application and provide final acceptance or sign off. Typically, a staging environment and an interface to report defects are provided for customer acceptance testing. The defect reporting interface should have notification capabilities to keep the concerned parties informed.

·         Monitor & Track SDLC: Apart from an event based notification mechanism, iSDF should also provide a facility so that the entire SDLC followed in a project should be monitored and tracked by a project manager and other concerned stakeholders on a regular basis. Usually the progress of a project, issues and defects are the primary items of interest for monitoring.

·         Administration: Capabilities like User management, user authentication, authorization, project creation, project member allocation can be implemented as administrative activities required for iSDF.

Recipe of a Pain Killer: The Solution

In order to implement the abovementioned use cases certain technical capabilities will be necessary for our iSDF. These capabilities (listed below) together can be considered as a good recipe for iSDF.
*      iSDF should have a Web based Graphical User Interface or portal to be able to provide all user interfaces required for requirement submission, requirement analysis, collaboration and document management.
*      A Workflow Management Framework will be required to manage workflows and human interactions in terms of requirement analysis and reviews etc.
*      A Software Design Tool or interface should be integrated with iSDF so that, the requirement documents or SRS can be referred by the designer and design the software accordingly. Ideally a use case model prepared by the requirement analyst should be captured and shared among relevant users within iSDF in a predefined format so that the design tool can interpret the same as the starting point of design. Apart from preparing design models (e.g. class diagram, sequence diagrams and activity diagrams etc.), the designer can also prepare a design document and store the same in centralized repository of iSDF. The centralized repository can be controlled by version control systems to secure the documents.
*      A Code Generation feature can be added to iSDF to generate initial code structure from design. For example, once the designer completes class diagrams for an application and executes the code generator on the same, the code generator should be able to read the class diagrams and generate initial source codes in desired programming languages (e.g. Java, C++, C# etc.). Once the initial source code structure is generated, they can be stored (checked) in a version controlled repository for reference later by the developers.
*      Development Tools or environments can be integrated with iSDF, where developers can check out the existing source codes from version controlled repository, modify the code, compile and check in the modified code back in the repository. Once there is an update in source code repository, an automatic event or notification should be generated in iSDF that should trigger the build process (through a CI tool).
*      A Reverse Engineering facility of iSDF can help in generating design models from code (in case existing source codes are referred as requirement artifacts). For example, class diagrams can be generated from Java source code.
*      A Reusable Component Repository (containing standards, frameworks, reusable code etc.) should be available with iSDF for the designer, architects and developers to refer to and reuse during architecture definition, design and development.
*      An Email Notification mechanism to notify members involved in a project or administrator whenever there is a change in repository. For example, the PM and requirement analyst should be notified whenever the customer or business user submits a requirement. Similarly architects, designers should be notified whenever the SRS is finalized and code reviewers should be notified once there is an update on source code.
*      A Collaboration Framework for the geographically distributed members to collaborate within each other during a review, analysis and general discussions. The mode of communications can be implemented through chat, email, desktop sharing and video chatting etc.
*      A Continuous Integration platform or tool to automate build, testing and deployment processes should be implemented in iSDF. This is make the process of compiling, building source codes and deploying application packages on desired execution platforms e.g. application or web server etc. Once an update is made on source codes by the developers and automatic event will be generated which will trigger the CI tool to start the build and deployment process. Figure 6 depicts  a typical continuous integration process.
*      A Build Tool should be provided as an integrated feature of iSDF. This tool should ideally be integrated with the CI component so that, whenever there is an update in code repository this tool can be automatically invoked based on an event. On invocation, the tool should be able to check out the latest source code changes from the code repository, compile, build and deploy the same on an execution platform (e.g. application server) for execution. Some popular build tools used nowadays are Apache Ant, Apache Buildr, Apache Maven, Cabal, Gradle, Bamboo etc.
*      Integrated Testing Tools for software application testing should be provided as an important feature of iSDF. The testing tools which can implement a test driven development (TDD) process such as Fitnesse. It should provide the feature to configure the test cases and test data in it. The testing tool should be integrated with the continuous integration tool or platform so that, on each update in source code or application configuration, testing can be executed automatically and the results can be shared (using email) with appropriate stakeholders. Ideally when the application is built and deployed on the execution platform (e.g. Application Server), the testing tool should start executing the test cases which were already pre-configured in it.

Figure 6: Continuous Integration Process

*      A Defect or Bug Tracker tool can be integrated with iSDF to manage and track defects. These tools can be integrated with iSDF to register and track bugs or defects found during testing. Monitoring and tracking of defect life cycle and maintaining a defect repository for further analysis are important aspects of this.
*      A User Authentication & Authorization mechanism to authenticate and authorize users (preferably directory service integration will be a modern technique for this) should be integrated with iSDF. This will enable security and restrict user access based on authority.
*      Reporting Tool is a significant component for any application software. For iSDF, the customer, project manager and other designated stakeholders can monitor and track the software development process by using desired web based reporting interfaces or dashboards.
Figure 7 shows the entire iSDF solution as conceptualized in this article.

Figure 7: iSDF Solution

References


1.     Waterfall model for project management and execution at http://en.wikipedia.org/wiki/Waterfall_model
2.     Continuous Integration technique at http://www.thoughtworks.com/continuous-integration
3.     Martin Fowler’s article on Continuous Integration at http://www.martinfowler.com/articles/continuousIntegration.html
4.     FitNesse, the acceptance testing framework at http://fitnesse.org/

Wednesday, March 24, 2010

Killer Servlet: a performance tuning and garbage collection solution

An applet is a Java application executed by a web browser to show dynamic graphics on the front-end. After the advent of Rich Internet Application (RIA) technologies, applets are disappearing from the tech landscape but once upon a time it was the only way to show rich contents on the front-end. A servlet in brief is a piece of Java code executed on the server side (typically a web server with an embedded servlet engine) to process request, collect data from data source or rendering a well formatted HTML page on the browser.
An applet-servlet communication is typically done where one can not avoid having a thick client such as an applet on the front-end posting requesting and / or receiving feed from the server side. For example, suppose an applet is continuously drawing and updating a graph based on the feeds received from the servers on the stock prices.
Whenever a user is opening an applet on his/her browser, the browser is downloading the applet and starts executing it. The applet draws a nice graph on the front-end (browser) and on the background connects to a server to fetch stock prices. When we had such a situation back in 2001/2002 (original situation has been modified a little to keep the privacy of the project intact) the architecture followed to implement this is as follows.
Among the technical components there were

• A Stock Price Applet with
o a nice graph panel
o a thread to render the graph on the front-end
o a thread to communicate with a servlet at the back-end

• A Stock Price Servlet (HTTPServlet) on the server with a “while” loop in the doPost() method and having some sub-components as below.
o a JMS Listener attached to the Stock price JMS topic
o a shared message cache where the subscriber stored the messages and the servlet used to read from.

• A Stock price JMS Topic on the JMS server

• Multiple Stock price publishers connected with different external Stock servers on the outer end and with the Stock price JMS topis on the inner end (in the server). Figure 1 explains the architecture.


Figure 1

The applet used to run on the browser and communicate (by opening a http stream) with the StockPriceServlet at the back-end. The servlet used to instantiate the JMS subscriber on receiving the applet’s request. The JMS subscriber was connected with the Stock price JMS topic to listen to Stock price update messages. On the other hand the JMS publishers kept adding messages as and when received from the external servers. To keep the http session alive between the applet and the servlet an infinite “while” loop is placed in the doPost() method of the servlet. The communication was a server push within an http session continuation.

Everything was nice and smooth but after serving a certain number of clients (i.e. applets) the server was getting slower and slower. It was a real-time application and delays to a certain extent was permissible but not beyond that.
So we started investigating the reason behind it. We discovered that the StockPriceServlets those were serving the applets on the front-end were kept alive even after the applet window was closed. The reason was the infinite loop in the doPost() method. The JMS subscriber was still alive listening to the JMS topic and throwing the messages to the servlet. The StockPriceServlet was writing the messages on the http response stream without any errors/exceptions because it was unable to sense that the receiver on the other side of the stream (i.e. the applet) has been stopped.

There was an option to put a timeout on the servlet so after a certain period pf time it dies out but that was not optimal. With an increased frequency of updates received by the stock servers the system might choke anytime.
Another option was to send a completion request from the applet to the servlet so that it can come out of the loop. But once the servlet receives the first request from the applet it starts the JMS subscriber and goes inside the loop. Http communications are stateless therefore a new request will invoke a new servlet.

Looking for more options we figured out a way to stop the StockPriceServlet and free up the resources with a programmatic technique. It was quite clear that the servlet needed to be killed on the completion of the applet’s activities. So an event or update needs to be thrown back to the servlet notifying that the applet has been stopped. Based on this update the servlet had to be killed. So we felt the need of an agent on the server side who will receive the notification from the applet’s end. The agent needs to accomplish the following activities.

1. Receives the completion notification from the applet.
2. Identifies the StockPriceServlet instance that was serving the applet.
3. Notify the servlet by updating a flag that makes the servlet to break out from the infinite loop and stop the subscriber attached to it.

So the agent took birth as the KillerServlet (please don’t laugh :) it’s the birth of the terminator ;). Activity 1 can be easily achieved by sending a http request from the applet to the KillerServlet. The most critical was the step 2 i.e. to identify the servlet instance. All servlet instances were maintained by the servlet container and hence getting a hold with them is tough. Well, getting the reference of a servlet from the ServletContext method was easy and official during 2001/2002 , but the issue was to identify the exact subject for kill i.e. a correlation. To establish a correlation the participants in the communication channel i.e. the applet and the servlet should be marked / tagged with a unique id (a correlation id) that can be used later to get a reference of the participants.
Figure 2 explains the modified architecture to include the solution. The solution technique was conceptualized as below.

Figure 2

1. The applet connects with the StockPriceServlet.
2. The StockPriceServlet generates a unique id (correlation id) and sends back the same to the applet with the first response before entering the loop. The StockPriceServlet should have a flag to terminate the while loop e.g. “while(!completed){}” instead of “while(true){}”. The StockPriceServlet should also have a unique id generator (preferably a singleton object).
3. The StockPriceServlet sets an attribute to the ServletContext (ServletContext.setAttribute()) with its own reference against the unique id.
4. Once the applet receives the unique id it should store the same.
5. Once the applet is stopped or terminated it should be able to sense the same (may be by using a JavaScript or a close button) and invoke the KillerServlet with the unique id.
6. The KillerServlet receives the unique id and looks up for the same in the ServletContext. (ServletContext.getAttribute()).
7. On receiving the appropriate reference to the StockPriceServlet instance the KillerServlet should update the completion flag to “true” in the StockPriceServlet instance.
8. Once the while loop is terminated, the StockPriceServlet stops the JMS subscriber and cleans up the message cache.

We did not want to invoke the destroy method to avoid touching the lifecycle controls and left the rest of things on the servlet container.

Tuesday, June 17, 2008

Code Generator Part VIII: The generated code

As the concluding part of the Code Generator series here is an example of how the generator works to generate the code. In this post I am going to present a sample object definition as the input (order.xml) to generate couple of Java source files using the home made code generator.

A piece of code generated using your home made Code Generator

Here is an example of an XML object specification for Customer, Order, OrderItem and Item objects to be supplied as the input for the code generation.


Order.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- order.xml -->
<OOSpec name="Order">
<Package name="">
<Class name="Customer" stereotype="class" visibility="public" baseInterfaces="Transformer">
<Import reference="java.util.Vector"/>
<Attribute name="code"/>
<Attribute name="names" multiplicity="3" defaultValue="Partha,Sarathi,Sengupta"/>
<Attribute name="age" type="integer"/>
<Attribute name="contacts" multiplicity="*"/>
<Operation constructor="yes" documentation="This is default constructor"></Operation>
<Operation directive="" documentation="This is transform operation" name="transform" returnType="string" bodyClassName="com. codegenerator.ToXMLStringBody">
</Operation>
</Class>
<Class name="Order" baseInterfaces="Transformer">
<Attribute name="number"/>
<Attribute name="date" type="date"/>
<Operation constructor="yes"></Operation>
<Operation name="transform" returnType="string" bodyClassName="com. codegenerator.ToXMLStringBody" synchronized="yes">
</Operation>
</Class>
<Class name="OrderItem" baseInterfaces="Transformer">
<Attribute name="number" type="integer"/>
<Attribute name="quantity" type="integer"/>
<Operation constructor="yes"></Operation>
<Operation name="transform" returnType="string" bodyClassName="com. codegenerator.ToXMLStringBody">
</Operation>
</Class>
<Class name="Item" documentation="This is a sample documentation">
<Attribute name="number"/>
<Attribute name="description" defaultValue="This is a description of the item"/>
<Attribute name="price" type="double" defaultValue="2.12"/>
<Operation constructor="yes"></Operation>
<Operation name="transform" returnType="string" visibility="public" bodyClassName="com.codegenerator.ToXMLStringBody">
</Operation>
</Class>
<Class name="Transformer" stereotype="interface" baseInterfaces="java.io.Serializable">
<Operation name="transform" returnType="string"></Operation>
</Class>
</Package>
<Association name="">
<Role class="Customer" multiplicity="1" name="" start="yes" navigable="no"/>
<Role class="Order" multiplicity="2" name="myOrders" navigable="yes"/>
</Association>
<Association name="">
<Role class="Order" multiplicity="1" name="order" start="yes" navigable="no"/>
<Role class="OrderItem" multiplicity="4" name="orderItems" navigable="yes"/>
</Association>
<Association name="">
<Role class="OrderItem" multiplicity="1" name="" start="yes" navigable="no"/>
<Role class="Item" multiplicity="1" name="item" navigable="yes"/>
</Association>
</OOSpec>


The Java source codes generated from the above specification are presented below. Notice how the transform method has been generated differently in each class.
Customer.java

/* This file has been generated by the CodeGenerator */
package com.order;
import java.util.Vector;

public class Customer implements Transformer {
private String code;
private String[] names;
private int age;
private java.util.ArrayList contacts;
private Order[] myOrders;

public String getCode() { return this.code; }
public void setCode(String code) { this.code = code; }
public String[] getNames() { return this.names; }
public void setNames(String[] names) { this.names = names; }
public int getAge() { return this.age; }
public void setAge(int age) {this.age = age;}
public java.util.ArrayList getContacts() {return this.contacts;}
public String getContacts(int index) {return (String)this.contacts.get(index);}
public void setContacts(java.util.ArrayList contacts) {this.contacts = contacts;}
public void addContacts(String contacts) {this.contacts.add(contacts);}
public Order[] getMyOrders() {return this.myOrders;}
public void setMyOrders(Order[] myOrders) { this.myOrders = myOrders;}
public Customer() {
code = new String();
names = new String[3];
names[0] = new String("Partha");
names[1] = new String("Sarathi");
names[2] = new String("Sengupta");
age = 0;
contacts = new java.util.ArrayList();
myOrders = new Order[2];
for(int i=0; i<myOrders.length; i++) { myOrders[i] = new Order(); }
}

/*This is transform operation*/
public String transform() {
StringBuffer sb = new StringBuffer();
if(code != null && !code.toString().equals("")) {
sb.append("<code>"+code+"</code>");
}
else {
sb.append("<code/>");
}
for(int i=0; i<names.length; i++) {
if(names[i] != null && !names[i].toString().equals("")) {
sb.append("<names>"+names[i]+"</names>");
}
Else {
sb.append("<names/>");
}
}
sb.append("<age>"+age+"</age>");

for(int i=0; i<contacts.size(); i++) {
if(contacts.get(i) != null && !contacts.get(i).toString().equals("")) {
sb.append("<contacts>"+((String)contacts.get(i)).toString()+"</contacts>");
}
Else {
sb.append("<contacts/>");
}
}
for(int i=0; i<myOrders.length; i++) {
if(myOrders[i] != null){
sb.append("<myOrders>");
sb.append(myOrders[i].transform());
sb.append("</myOrders>");
}
Else {
sb.append("<myOrders/>");
}
}
return sb.toString();
}
}
Order.java

/* This file has been generated by the CodeGenerator */

package com.order;
import java.util.*;

public class Order implements Transformer{
private String number;
private java.util.Date date;
private OrderItem[] orderItems;
public String getNumber() {return this.number;}
public void setNumber(String number) { this.number = number; }
public java.util.Date getDate() { return this.date; }
public void setDate(java.util.Date date) { this.date = date; }
public OrderItem[] getOrderItems() { return this.orderItems; }
public void setOrderItems(OrderItem[] orderItems) { this.orderItems = orderItems; }
public Order(){
number = new String();
date = new java.util.Date();
orderItems = new OrderItem[4];
for(int i=0; i<orderItems.length; i++) {
orderItems[i] = new OrderItem();
}
}
public synchronized String transform() {
StringBuffer sb = new StringBuffer();
if(number != null && !number.toString().equals("")){
sb.append("<number>"+number+"</number>");
}
else {
sb.append("<number/>");
}
if(date != null && !date.toString().equals("")) {
sb.append("<date>"+date+"</date>");
}
else {
sb.append("<date/>");
}
for(int i=0; i<orderItems.length; i++) {
if(orderItems[i] != null){
sb.append("<orderItems>");
sb.append(orderItems[i].transform());
sb.append("</orderItems>");
}
else {
sb.append("<orderItems/>");
}
}
return sb.toString();
}
}
Item.java

/* This file has been generated by the CodeGenerator */

package com.order;
import java.util.*;

/*This is a sample documentation*/
public class Item implements java.io.Serializable{
private String number;
private String description;
private double price;
public String getNumber() { return this.number; }
public void setNumber(String number) { this.number = number; }
public String getDescription() { return this.description; }
public void setDescription(String description) { this.description = description; }
public double getPrice() { return this.price; }
public void setPrice(double price) { this.price = price; }
public Item() {
number = new String();
description = new String("This is a description of the item");
price = 2.12;
}
public String transform(){
StringBuffer sb = new StringBuffer();
if(number != null && !number.toString().equals("")){
sb.append("<number>"+number+"</number>");
}
else{
sb.append("<number/>");
}
if(description != null && !description.toString().equals("")) {
sb.append("<description>"+description+"</description>");
}
else{
sb.append("<description/>");
}
sb.append("<price>"+price+"</price>");
return sb.toString();
}
}
OrderItem.java

/* This file has been generated by the CodeGenerator */

package com.order;
import java.util.*;

public class OrderItem implements Transformer{
private int number;
private int quantity;
private Item item;
public int getNumber(){ return this.number; }
public void setNumber(int number) { this.number = number; }
public int getQuantity(){ return this.quantity; }
public void setQuantity(int quantity){ this.quantity = quantity; }
public Item getItem(){ return this.item; }
public void setItem(Item item){ this.item = item; }
public OrderItem(){
number = 0;
quantity = 0;
item = new Item();
}
public String transform(){
StringBuffer sb = new StringBuffer();
sb.append("<number>"+number+"</number>");
sb.append("<quantity>"+quantity+"</quantity>");
if(item != null && !item.toString().equals("")) {
sb.append("<item>");
sb.append(item.transform());
sb.append("</item>");
}
else{
sb.append("<item/>");
}
return sb.toString();
}
}
Hope this article will help those who are looking for preliminary information on the concepts and technologies used in code generation. Please feel free to leave your comments.