DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

The Latest Testing, Deployment, and Maintenance Topics

article thumbnail
Service Development Lifecycle Controls for Creating a Service Factory
The concept of a software factory describes a practical work-product approach to governing an efficient service factory - a software engineering-based approach to defining, developing, testing, deploying, and operating functional services and automated business processes. All services follow a similar lifecycle of analysis, followed by design, development, deployment, and ongoing management. Because the service creation process is repetitive, a production engineering approach to automating software development can be used. The Production Engineering method required a significant effort up front, creating a specialized production or assembly line that can then mass-produce the product efficiently and in quantity In effect, we are building a Services Factory: much of the purpose of SOA governance is to define how that factory can operate most effectively. In the following excerpt from the book "SOA Governance: Achieving and Sustaining Business and IT Agility" [REF-1] we will take a look specifically at service development lifecycle control points. This article authored by Clive Gee and Robert Laird and published in SOA Magazine on Feb 23, 2009 Introduction While most organizations have some form of a system development lifecycle (SDLC), the nature of creating shared services is best guided by an SDLC with sufficient governance control points to ensure quality of service. This article discusses and explains the key concepts of a governance control point, as applied specifically to the service development lifecycle. Service Development Lifecycle Control Points Most organizations already have some type of system development lifecycle (SDLC) and a methodology that is used to perform development, although we often see in practice a lack of enforcement of that approach across different business units, and even if a set of best practices, standards, policies, and patterns has been defined, they are not always enforced. Effectively enforcing best practices and a consistent SDLC provides a reasonable entry point for real governance, while not being a huge stretch from what is already being performed via the SDLC. At the same time, if the governance maturity level of the organization can be increased to the degree that it is able to govern the SDLC, the organization is then in a much better position to proceed to the next phase of the SOA governance cycle and create program and organization governance. The danger here for even initial attempts at SOA governance is that often some key individuals view the imposition of any process or governance as being something that might apply to other people but not to them personally. For them, it's an over-engineered, useless exercise that just gets in the way of meeting their own deadlines. So, many governance processes are simply bypassed, or they're followed in a less than an enthusiastic manner. The main reason for this is that governance is imposed from the outside and the execution is onerous. What would happen if governance were mostly automated, easy, and added value to the development process and actually helped with project deadlines? Would the skeptics be more willing to take the medicine if it genuinely eased their pain? To adequately govern the SDLC, there is a need to establish measurements, policy, standards, and control mechanisms to enable people to carry out their governance roles and responsibilities as efficiently as possible, without introducing overly bureaucratic procedures. Governance of the SDLC may be characterized by the sorts of decisions that need to be made at certain "control points" within the process of services development. A control point is a decision checkpoint that provides an opportunity to measure adherence to the established processes, whether you are on track to meet the targets and goals you have established, and then decide whether the way the processes are executed or managed needs adjusting. Knowing what decisions involved in the process are critical, when to make them, and understanding what measurements are needed to monitor those processes are all essential aspects of governance. Certain activities within a process may be associated with a control point. At the end of each identified activity, there is a control point at which the governance function decides whether the program is ready to move to the next activity. Each of these milestones is a control point. At its essence, the governance of the SDLC provides a way to identify control points and to define the governance rules. At each control point, it is necessary to identify the following: • The roles for who does what at the control point • The policies to be applied at the control point • Measurements at each control point that should be applied and collected for later governance vitality actions • The proof of compliance records to be created and archived A control point will be created where there is a demonstrated advantage weighing the standardization and efficiency provided versus the time, effort, and possible project delay. The control point enables SOA governance the opportunity to ascertain progress, to communicate this progress, to forecast efforts for subsequent phases of the SDLC based on scope and issues found, to review and report compliance, and to facilitate the injection of expertise and qualified review of the artifacts, process, or decisions made by the development team. Control points don't have to consist of huge formal meetings. Services and most automated business processes are smaller entities than projects, and there are many more of them. Therefore, the existing governance approach has to be streamlined or it might grind to a halt. We've found in practice that effective control point reviews can be made during regular - typically weekly - sessions of a subset of the SOA enablement. A real productivity aid in performing these control point reviews is the use of previously completed checklists, signed off by one or more senior professionals as certification that one or more tasks has been completed successfully, and that the service, process, or other work product is fit for purpose and ready in all respects for the next task in the development process. These checklists should be viewed as contracts between different experts in the service development process. The most important part of the checklist is the signature block to show who exercised approval authority; people tend to be careful about the quality of anything that carries their personal reputation with it. Another productivity aid is the use of automated tooling. As much of the governance control point as possible should be automated. This aids in better near real-time feedback to the developers and provides an easy method to recheck work that has been updated. In addition, human beings are busy and will tend to apply governance in an inconsistent manner. Machines are consistent but not usually as flexible as needed. The combination of the two provides an optimal governance mix. Let's look at the control points needed to govern a generic development lifecycle, at least at a high level. Figure 1 represents a "governance dashboard" monitoring a typical SDLC with an eye toward the key concepts and the points where they must be addressed by SOA governance. Figure 1: Software Development Lifecycle Governance Dashboard As mentioned previously, we need a streamlined process that can handle the large number of services and automated processes that we need to implement to have real impact on business agility and flexibility. However, that streamlined process must not sacrifice the quality of governance just because of the need for extra speed. That would be an unacceptable trade-off. Some organizations deal with highly regulated processes that have mission-critical or life-critical products and need to apply highly formal, auditable governance to manage the risks involved. Other organizations have processes with lower associated risks that can be more lightly regulated. We have found in practice that the same governance process can handle both these extremes perfectly well. If there is a need for stricter governance, it can be met with tighter policies at the control points together with more stringent policy enforcement and compliance measurement. If less-strict governance is more appropriate, the same process can be used with less restrictive policies, fewer audits, and lower levels of checklist signoff required. Even within a single organization, different processes may require different styles of governance. Some processes, such as service certification, require stricter governance than other processes, such as solution architecture. Different organizational cultures require different levels of autonomy in decision making. Good governance requires good judgment. First, let's update our Figure 1 with the location of these control points so that you have a visual representation in mind as you read their descriptions. Figure 2 shows where the control points occur in that development cycle. Figure 2: Software Development Lifecycle with SOA Control Points Here are descriptions of these control points. Business Requirements and Service Identification Control Point For an SOA approach, there is an emphasis on creating services that provide agility and reuse for the business. This first business requirements and service identification control point consists of a high-level review to determine that services are being identified in accordance with services selection and prioritization policies. This first business requirements and service identification control point should address the following types of questions: • Business goals. What are the business goals that the business seeks to attain and how do we measure the benefits or progress toward the business goals via key performance indicators (KPIs)? • Do the requirements as we currently understand them clearly support those goals, and do they align with an existing "business heat map"? • Are those requirements sufficiently understood and agreed to? Are they presented in a form such as use cases, business process models, sequence diagrams, or class diagrams that are consistent with the SOA development approach? • How do we provide traceability of the requirements so that we can ascertain that those requirements have been met during the development process? Have those requirements been entered into an enterprise-wide requirements and business rules catalog? Is there any conflict with existing entries in that catalog? • Which of those requirements could be translated into good candidate services, either because they represent functionality that may be needed by multiple consumers or that might be needed for process automation? Which requirements could be better supported by deploying applications, automated processes, or manual processes? • Where we have identified candidate services, have we identified potential consumers, and determined whether any of them have specific requirements that should be considered? • Given finite IT resources, what development priority should we assign? Is ownership of any new candidate IT asset defined, and is outline funding available for its development? Solution Architecture Control Point Different IT developers and groups, if left to make all design decisions on their own, would invariably use completely different platforms, coding languages, tools, styles, methods, and techniques. This variation adds cost and complexity to the ability of the business to make future changes, and makes future maintenance very hard and costly. Further, it reduces the reliability, stability, and interoperability of the organization's IT assets. We have seen this problem at many organizations that we have visited. Simply put, the purpose of the solution architecture control point is to prevent that expensive multiplicity of approaches from occurring ever again. Essentially, any proposed IT artifact that makes it past this control point is part of the IT build plan. For the area of solution architecture, the governance should control for a series of criteria the following: • Do the proposed standards, policies, and reference architectures - the solution architecture - identify the standards, policies, and design patterns to be followed in the service implementation? This will include reference architectures, platform standards for hardware, and software-usage standards. • Have any reusable assets been identified and assessed for suitability? Has the service sourcing policy been followed? • Have the nonfunctional requirements been identified and assessed? This includes the number of transactions per time unit, a busy hour analysis, the service performance required, presentation access to the service functionality, data managed by the service, space required for the installation of the service, and any dependency and configuration requirements. Governance must validate that all these are considered and addressed. • Governance must validate that all security policies are being considered and addressed. • Governance must validate that all legal and regulatory policies are considered and addressed. • By this stage in the development of IT assets such as services or automated processes, the technical IT staff involved should have a pretty good idea about the complexity of the tasks involved, and the probable level of resources required to complete development. Should development of the asset be confirmed, the scope reduced, or the asset abandoned? Service Specification Control Point A service specification should be created for each service whose development has been approved. Best practices for service design must integrate both an IT and business perspective for the design of the interface and the responsibilities of each service. Because the service specification is, in effect, the organization's face to business partners, customers, and other stakeholders, the service externals - those details of a service that are to be made public - become an important part of the overall business design. The design should take into account the requirements of all potential service consumers (within reason), and be created at a granularity that maximizes business value. For the area of service identification and specification, the governance should control for a series of criteria the following: • Does the service identified make sense, is at the right granularity, and is not duplicating an existing service? • Does the service specification follow all SOA standards and policies? • Does the service specification follow the messaging model? If not, should an exception be granted? Service Design Control Point After the service solution architecture has been turned over to the design team, a number of design elaboration decisions must be made. Collectively, these form the service internals - a set of design models, notes, and advice that will guide the service developers as they create and test the service code. For the area of service design, the governance should control for a series of criteria the following: • Has a service architect confirmed that the design should be able to meet the nonfunctional and functional requirements for this service? • Have the service designer and data architect agreed that the service can be made to conform to the signature (that is, inputs and outputs) described in the service externals? • If a service is wrapping an existing or planned application, are the necessary interfaces to that application well defined and stable (that is, won't change if a new version of that application is installed)? • Have the monitoring metrics (for example, usage, quality of service [QoS] levels) been established? • In the case of automated processes, have the monitoring requirements been defined and planned? • In the case of long-running automated processes, have all the necessary actions to handle recovery from process errors or technical failures been addressed? • Is the overall quality and level of completeness of the service specification package good enough that the service developers or process developers can complete development without further input? Service Build Control Point After the service design has been turned over to the service build team, a number of implementation decisions need to be made before development of the code or executable model. In the interests of consistency and quality, we strongly recommend the use of code walkthrough reviews, where peers (that is, other service developers or process developers) review the work in progress and offer constructive criticism. The service build control point is effectively the last of these code walkthroughs, and should be performed with slightly more formality than the others. Questions that should be addressed include the following: • Was the asset coded in accordance with the design? • Does the code follow the accepted coding standards? • Have all the associated artifacts (for example, load libraries, metadata files, resources) been defined to create a transportable build? Have the versions of each of those artifacts been checked to see that there are no version conflicts with services already in production? Service Test Control Point Service testing is different from testing complete IT solutions or applications. Because services and automated processes do not have their own user interface, it is not possible to perform user acceptance testing directly on services or automated processes. Code frameworks or specialized tools are needed to exhaustively test services and automated processes thoroughly to avoid uncovering problems during later formal user acceptance testing when the rest of the IT solution that uses those services or processes has been completed. SOA governance must ascertain that the services test is being performed in a manner conducive to a services approach, and that exhaustive functional and nonfunctional tests have been passed before releasing any SOA asset to production. The service test team must create and use the right service test environment with tools and data to affect a comprehensive test. This should include the following: • Using the optimum set of service test tools and frameworks. • The use of an automated build and test environment that can enable fast changes of the tested software and regression testing. This environment must closely resemble the production environment. • A load/stress test tool to test nonfunctional requirements, specification, creation, and loading of realistic but artificial test data. • A test management reporting tool to keep management apprised of the testing status. • Trace the test case to the original user requirements. Service Certification and Deployment Control Point The objectives of the deployment are to migrate the services to the production environment while minimizing client downtime and impact on the business. This process is subject to many errors if performed manually. It is vital that the correct version of the services be deployed and that any deployment binding with other services and applications be performed quickly and correctly. Areas for governance to validate include the following: • The use of a tool that automates the deployment and back-out process. • Final certification checks have been made against the services to verify compliance with all policies and standards and being able to demonstrate that what was tested matches not only the requirements but what was delivered, and that no corrective changes made during testing have invalidated other test results. • IT operations have completed acceptance testing and have formally accepted the asset, signifying their confidence in being able to operate it within the terms of the QoS specified for it. • The service registrar and business service champion have reviewed the service description in the service registry and approved it. Certification of a service or automated process is a formal "passing out" ceremony, and granting of certification should signify that the SOA enablement team is happy for their reputation to be associated with the performance of the new asset. Service Vitality Control Point Service vitality takes place periodically as part of SOA governance to check up on and update the governance processes, procedures, policies, and standards in reaction to the results of the real world. This involves examining any and all lessons learned in any of the SOA planning, program control, development, or operations activities. It also includes such things as comments and feedback from all stakeholders and an examination of any common patterns (for example, common exemption requests or common reasons for failure to pass one or more control points) that need remedial action. Metrics in the efforts required for each stage of the development process can show trends that indicate improvements or declines in their vitality. A formal service vitality control point review should be conducted every three to six months to determine whether the SOA transition remains on track, and whether the level and style of governance is optimal. Individual service or automated processes should be reviewed every 6 to 12 months. Usage data of all versions of each service can determine any "stale" versions that can be deprecated or deleted, and whether the deployment options taken and decisions on who should own and who should access each service are optimal. Conclusion We have focused in this extract on SOA Governance service development control points as a method to create a software engineering capability of a service factory. The factory is a production line for services. All services pass through a common, repeatable series of development, deployment and management steps. Quality and governance is built-in throughout the entire process. References [REF-1] "SOA Governance: Achieving and Sustaining Business and IT Agility" by William A. Brown, Robert G. Laird, Clive Gee, Tilak Mitra (IBM Press, ISBN 0137147465, Copyright 2009 by International Business Machines Corporation. All rights reserved.) This article was originally published in The SOA Magazine (www.soamag.com), a publication officially associated with "The Prentice Hall Service-Oriented Computing Series from Thomas Erl" (www.soabooks.com). Copyright ©SOA Systems Inc. (www.soasystems.com)
March 19, 2009
by Masoud Kalali
· 8,359 Views
article thumbnail
Unit Testing File I/O Operations
This is an issue I’ve seen come up in my own team a lot lately and I thought it may be of general interest as well. This issue is how would I unit test this class… public class PointParser { private readonly StreamReader _streamReader; public PointParser(string filePath) { _streamReader = new StreamReader(filePath); } public Point ReadPoint() { var coords = _streamReader.ReadLine().Split(new[] { ',' }); return new Point(Int32.Parse(coords[0]), Int32.Parse(coords[1])); } } This class takes a path to a CSV file, opens the file, and then parses the coordinate values out of each line of the file into a series of points. Let’s tackle the obvious first. Anytime you can describe what a class does using the word “And” we’ve violated the Single Responsibility Principle so the class is doing too much. Let’s simplify it a bit and let the class simply consume a file stream which has already been opened. This way the class is not responsible for managing the stream resource and it can focus on what it does best…parsing the CSV file. public class PointParser { private readonly StreamReader _streamReader; public PointParser(StreamReader streamReader) { _streamReader = streamReader; } public Point ReadPoint() { var coords = _streamReader.ReadLine().Split(new[] { ',' }); return new Point(Int32.Parse(coords[0]), Int32.Parse(coords[1])); } } Now we have a little bit more manageable problem. Let’s think about a simile to this problem. Imagine that instead of coming from a file, our points were coming from a database connection. public PointParser(IDbConnection dbConnection) { _dbConnection = dbConnection; } Now this is something we can more easily recognize. How would we test this? Would we open a connection to live database that we’ve pre-populated with valid points? Of course not, we would abstract the database connection out to a data source and then mock that data source for all of the database connections. So, why wouldn’t we do the same here? Moving from that example, we can see that we need to abstract out our StreamReader class. BCL classes our notorious for being difficult to mock using anything other than TypeMock, but Microsoft threw us a bone here: the StreamReader class actually derives from the TextReader class which is an abstract class. And when it comes to mocking, at least, an abstract class is just as good as an interface. So, our next step is to replace the reference to the concrete StreamReader class with it’s more flexible TextReader base class. Now we have something we can work with. public class PointParser { private readonly TextReader _textReader; public PointParser(TextReader textReader) { _textReader = textReader; } public Point ReadPoint() { var coords = _textReader.ReadLine().Split(new[] { ',' }); return new Point(Int32.Parse(coords[0]), Int32.Parse(coords[1])); } } So, using Rhino.Mocks, we can unit test this class all we like by simply simulating a stream of points… [Test] public void Can_get_the_first_line() { var textReader = MockRepository.GenerateMock(); textReader.Expect(tr => tr.ReadLine()).Return("50,100"); var pointParser = new PointParser(textReader); var point = pointParser.ReadPoint(); Assert.AreEqual(new Point(50,100), point); } We can even generate error conditions [Test] [ExpectedException(typeof(InvalidPointException))] public void Will_throw_an_error_if_point_is_invalid() { var textReader = MockRepository.GenerateMock(); textReader.Expect(tr => tr.ReadLine()).Return("50,Not_A_Number"); var pointParser = new PointParser(textReader); var point = pointParser.ReadPoint(); Assert.AreEqual(new Point(50, 100), point); } So, to recap, here are the important points… Any class that performs operations against the content of a file shouldn’t be responsible for also managing the connection to that file. Your unit tests should only be concerned with how that class works with the content of the file, not the various conditions surrounding the connection. Sure, you’ll want to also have tests in place to determine what happens when the file can’t be open because it’s already in use or isn’t at the location specified, but those are integration tests…not unit tests. If you’re working with a StreamReader class, then you can abstract that up to a TextReader class and mock it. If you’re of the FileStream persuasion, then you can abstract it up to a Stream.
March 13, 2009
by Jeremy Jarrell
· 39,159 Views
article thumbnail
Wicket Tutorial Series: Setting Up the Project
Each day this week will feature a new article with an in-depth look at the creation process behind setting up a Java project and implementing the frontend with Apache Wicket. Wicket is a Java web application framework which allows “Designers” (people good with Dreamweaver) and “Developers” (people good with Java and Databases) to collaborate on a project with minimal chances of stepping on each other’s toes or wearing each other’s hats. The beauty of Wicket is that it uses plain xhtml pages as it’s templating markup. This means that html pages can be loaded into Dreamweaver (or whatever tool the Designer is comfortable with) and they will look very close to the same as they would when rendered on the deployment web server. Workflow The basic workflow involved in creating and maintaining html rendered by Wicket is as follows: The Designer creates the html for the website and fleshes it out with “mock” sections. For instance in the application we intend to create during our Five Days of Wicket will be a pastebin application called “Mystic Paste”. In our application we’ll have an “Add Code to Mystic Paste” page, mock data might include some user created content in the textarea of the page. All css/images, etc… are setup such that if they were to be put on a webserver, everything would work. The Developer needs to flesh out the dynamic areas of the webpage, that is, he needs to instruct Wicket where it will need to show information from the server. The developer does this by decorating the designer’s html page with special Wicket tags and attributes. Because these tags and attributes are just considered part of another namespace separate from xhtml’s, editors like Dreamweaver and browsers will simply ignore them - It is important to note: The developer will still keep the “mocked” sections of the page intact, this is so the page renders and looks fleshed out on its own. The mocked sections will be replaced by real data when rendered by Wicket. The Developer hands the file back to the Designer. The Designer is free to make further edits, so long as he/she does not remove or manipulate the Wicket tags and attributes present in the file. If the Designer does need to remove any Wicket tags or attributes, they need to consult the Developer as such an action will “break” the webpage when Wicket renders it. Example Wicket Page Here is an example of a Wicket page. This example was taken from Manning Publishing’s book “Wicket in Action”: ... Gouda Gouda is a Dutch... $1.99 add to cart Emmental Emmental is a Swiss che... $2.99 add to cart ... This looks almost 100% like a normal webpage would look, the only difference is the addition of the “wicket:XXX” attributes and tags sprinkled through the document. The parts of the document using the special Wicket namespace modifiers will be replaced/removed in the final markup when Wicket renders the page to the user’s browser. Notice the “” element? This is where your designer can put a “mocked” version of what that area of the page should look like. You as a developer can take that mocked html and divide it out into a template that is dynamically driven from the backend. Here is how the final page looks if you were to simply load the page into a web browser (or Dreamweaver) from your hard drive: Preparing for Setup Deviating a bit from the Standard Wicket Convention One of the first things a developer notices when starting out with Wicket is the convention where Wicket likes having its html template files live at the same level and in the same packages as it’s Java source files. Sure you can jump through hoops to get Wicket to load the html template files from elsewhere but a nice compromise is to simply keep your html template files within the same package directory structure but in a source folder separate from the Java classes. Why? Well quite simply to keep your designers (Dreamweaver folks!) from having to grab Java source files along with the html files they are working on. It will just confuse them and clutter their directories. You can of course stick with the typical “Java source files along side html” convention if you wish, but I find it much cleaner to separate them during design time, and have Maven combine them only at build time into the target war (which it will gladly do automagically). Project Folder Structure . |-- pom.xml |-- src | `-- main | |-- filters | |-- java | | `-- com | | `-- mysticcoders | | `-- mysticpaste | | |-- model | | |-- persistence | | | |-- exception | | | |-- hibernate | | |-- services | | `-- web | | |-- ajax | | |-- pages | | |-- panels | | `-- servlet | |-- resources | | |-- com | | | `-- mysticcoders | | | `-- mysticpaste | | | |-- spring | | | `-- web | | | |-- ajax | | | |-- pages | | | `-- panels | | `-- log4j.properties | |-- sql | `-- webapp | |-- WEB-INF | |-- images | |-- js | `-- css src/main: maven builds source and resources from this directory to the main deployable target (i.e. our war file) filters: we keep a set of “filters” files that maven can use to interpolate variables at build time. What does this mean? It means that inside your configuration files, the files you use to setup database connections or file paths, you can insert variable place holders like ${db.host}. When maven does a build, it looks up the correct filter file to use and looks for the key=value part corresponding to “db.host” and inserts it into the configuration file for you. This ensures that you are able to configure your application per environment you deploy to (i.e. DEV, QA, PROD, etc…) by having different filter files with the same keys but different values. For more information see Maven’s documentation on filtering resource. java/*: this folder will contain all of the application’s source code. Everything from the database access code, wicket code and services code for the mysticpaste application (see below). model: all “domain” classes, that is, classes that represent the objects in the application. For mysticpaste you’ll see classes like “PasteItem” which represents an item pasted to the mysticpaste. persistence: at this level of the persistence package a list of interfaces will be kept. The interfaces comprise the basic access layer the services layer will use to save, retrieve and update items to/from the paste bin. exception: the peristence layer needs to tell the services layer when things have gone wrong. It does this via delcaring and throwing exceptions. hibernate: such is our case, our persistence interfaces will be implemented via the ORM known as Hibernate. This package will store all of the custom hibernate implementations and hibernate specific classes services: The services layer will be stored here. Both the generic interfaces and their implementation classes. The persistence layer will be injected via spring. web: this folder is where our Wicket classes will reside and it’s split into several category packages which are as follows: ajax: mysticpaste uses Ajax to render portions of its UI. The wicket classes which render the xml/html to be injected dynamically into the page are stored here. pages: standard Wicket page classes which are used throughout the application are stored here panels: reusable panel classes are stored here. Panels may be included within Wicket pages for sake of templating servlet: any run of the mill servlet code we need is stored here. A good example might be an ImageUploadServlet resources/*: the resources folder will hold our non-java based files. Noteably html files and spring confguration files spring: Holds any spring configuration files needed to wire the services and persistence layer web: this folder and all subfolders mirror the packages under src/main/java/…/web and hold the .html files that the Wicket page/panel classes use as their templates. As described above, a “standard” wicket application simply stores the .html files along side their Wicket classes under src/main/java/…/web, however we want to keep these files separate from the Java source so as to keep the directory our designers checkout from version control contianing only the files they need to work on. sql: any sql scripts we need to keep handy for building the mysticpaste database. webapp: this folder will keep the files which live at the base directory of our war file WEB-INF: where you keep your web.xml file images: any image resource, .gif/.png/.jpg files your webapp will reference js: javascript files your webapp will reference css: style sheets your webapp uses src/test/*: All files which reside under this folder are test classes and resources needed to support the tests. Maven will build everything under src/main/java and add it to the class path of the JUnit or TestNG classes you create. java: JUnit or TestNG test classes which will be run during a build resources: resource files which are needed to support the tests Getting Started Since we are using Maven as our build tool we can take advantage of the fact that the fine folks at the Wicket project have created a specialized “archetype“ which creates a skeleton web application complete with a folder structure which mimics roughly what we have outlined above and Maven pom.xml file used to build a war. The Wicket contributors have even gone one step further and have created a little web page which will, based off a few drop down options, generate the maven command you need to execute in order to create the boiler plate Wicket project. You can find this web page over on the Apache Wicket site under the “Quick Start” link. Copying the above Maven command creates a Skeleton Wicket Project To be precise, the command I used was: mvn archetype:create -DarchetypeGroupId=org.apache.wicket -DarchetypeArtifactId=wicket-archetype-quickstart -DarchetypeVersion=1.3.5 -DgroupId=com.mysticcoders -DartifactId=mysticpaste And I ended up with the following folder structure: . `-- mysticpaste |-- pom.xml `-- src |-- main | |-- java | | `-- com | | `-- mysticcoders | | |-- HomePage.html | | |-- HomePage.java | | `-- WicketApplication.java | |-- resources | | `-- log4j.properties | `-- webapp | `-- WEB-INF | `-- web.xml `-- test `-- java `-- com `-- mysticcoders |-- Start.java `-- TestHomePage.java Now obviously we’ll have to rearrange a few things, for instance I want my base package to be com.mysticcoders.mysticpaste, but that’s easy enough to do once we are in an IDE. For now, let’s test this example webapp out and see if it works. To do that switch into the mysticpaste directory (the directory that has pom.xml in it) and type the following: mvn jetty:run This will start up a Jetty webapp container running on port 8080 (if you have something running there already, use the -Djetty.port= option). Startup a webbrowser and navigate to http://localhost:8080/mysticpaste/ You should see: Your IDE Sooner or later you’re going to want to crack open your IDE and start hacking away. Maven makes this extremely easy by allowing you to create IDE specific project files based off of the Maven pom.xml file. Eclipse mvn eclipse:eclipse For eclipse you’ll also have to set the M2_REPO classpath variable for the workspace your project resides under. Do this by entering the following command: mvn -Declipse.workspace= eclipse:add-maven-repo IntelliJ IDEA mvn idea:idea -OR- in IDEA 7+ simply open the pom.xml file Netbeans Netbeans supports maven out of the box, just “Open Project” and choose the mysticpaste directory that contains the pom.xml file When generating the project files through Maven, the project is setup such that classpath entries point to your local Maven repository (i.e. ~/.m2/repository, or C:Documents and Settingsyourusername.M2repository on Windows). It also sets up src/main/java, src/main/resources as “source folders”. You may add other folders to the source folder list as per your IDE if needed, the only thing you have to remember is if you ever use mvn eclipse:clean followed by mvn eclipse:eclipse again, those other source folders will have to be readded through your IDE. Instead, you should add the source/resource folders directly to your pom.xml, this way they will be maintained. Spring The Mystic Paste application will use Spring, and really you should too. Unless you have been hiding under a rock or work in a corporate environment so lame as to which technologies newer than 2002 are forbidden you should learn to accept Spring as a defacto standard. Dependency injection for the win! We add the following to our pom.xml: org.apache.wicket wicket-spring-annot org.springframework spring org.springframework spring-test org.springframework spring-tx wicket-spring-annot: allows us to wire our Wicket application via handy dependency injection annotations (i.e. @SpringBean, see Wicket documentation for more detail) spring: is just the core spring libraries spring-test: is a set of Spring integration classes for Unit testing spring-tx: is the Spring Transaction Management api for declarative transactions web.xml additions for Spring In order for Spring to manage our Wicket application we need to setup the Wicket filter with a Spring-aware application factory. This allows us to wire our Wicket Application class in our applicationContext.xml file, which is really handy if you have a services and configuration settings you want to inject into the Wicket Application object so the rest of your application can access them. To do this, we change the original Wicket filter like so: wicket.mysticpaste org.apache.wicket.protocol.http.WicketFilter applicationFactoryClassName org.apache.wicket.spring.SpringWebApplicationFactory As well, we want our Spring context to be available to our webapp if ever there is a need for one of our pages to access the Spring managed beans directly: contextConfigLocation classpath:com/mysticcoders/mysticpaste/spring/applicationContext.xml org.springframework.web.context.ContextLoaderListener Hibernate Hibernate is our ORM of choice, it will allow us to persist and retrieve our model objects to and from the underlying database, whatever that database may be. We add the following to our pom.xml: org.hibernate hibernate-annotations c3p0 c3p0 commons-dbcp commons-dbcp javax.transaction jta 1.0.1B hibernate-annotations: used so we can annotate our model classes with mapping information, instead of having to create a separate mysticpaste.hbm.xml file. c3p0: provides a connection pooling library Hibernate can use commons-dbcp: another connection pooling library, we’ll add it as well and decide whether to use it or c3p0 later jta: this is the Java Transaction API which is needed by Hibernate (Hibernate provides an implementation of the API) web.xml additions for Hibernate To have a Hibernate Session open and ready for our webapplication during a Request Cycle we need to setup a Hibernate filter like so (otherwise, good luck getting lazy loading working!): open.hibernate.session.in.view org.springframework.orm.hibernate3.support.OpenSessionInViewFilter open.hibernate.session.in.view /* As the comment states above, make sure this filter-mapping exists *before* your wicket.mysticpaste filter or else it just plain won’t work. Database For the Mystic Paste we decided to use the freely available PostgreSQL. Adding support for PostgreSQL is very easy, unlike with some of the commercial DBMSes where you have to download and install their JDBC driver into your repository. To add support for Postgres, we simply add the following to our pom.xml: postgresql postgresql Servlets Regardless of which webapplication framework you choose there are just some times when a plain jane Servlet comes in really handy. If you have a need for Servlets and the Servlet must have access to the Wicket session add the following to your web.xml: wicket.session org.apache.wicket.protocol.http.servlet.WicketSessionFilter filterName wicket.mysticpaste And then, after your other filter-mappings add the following (assuming you mount your servlet-mappings under /servlet/): wicket.session /servlet/* Maven Filters and Profiles In order to build our Mystic Paste project for various environments (DEV/QA/PROD) we need to implement both Maven profiles and filters. Filters Filters allow you to place variables inside your configuration files and have those variables filled in durring build time. This is very handy for setting environment specific things such as database connection information. Enabling filters is quite easy, we open up the pom.xml file and find the section for and set the value for the element to true as follows: true src/main/resources . . . But for filtering to work, we need to specify a filters file. It’s not enough to specify only one filter file because we need to specify different filters per environment and we’ll do that by using Maven Profiles. Profiles To setup a profile, create a new set of elements following the section in your pom.xml file. Like so: DEV DEV DEV QA QA PROD PROD and just above your tag underneith your tag you would add the following elements: mysticpaste src/main/filters/filters-${env}.properties true src/main/resources src/main/filters will contain the following files. |-- pom.xml |-- src | `-- main | |-- filters | | `-- filters-DEV.properties | | `-- filters-QA.properties | | `-- filters-PROD.properties filters-DEV.properties jdbc.url=jdbc:postgresql://localhost:5432/mysticpaste jdbc.user=mysticpaste jdbc.password=password image.upload.path=/tmp/pasetbin/userimages image.upload.size.limit=4096K filters-PROD.properties jdbc.url=jdbc:postgresql://192.168.2.10:5432/mysticpaste jdbc.user=mysticpaste jdbc.password=CrYp71c image.upload.path=/mysticpaste/userimages image.upload.size.limit=4096K Now within any file under src/main/resources that has variables of the form ${variable.name} will have those variables replaced with the values specified in the proper filters file located under src/main/filters. For instance here is an example of a Spring applicationContext.xml file which will be interpolated with proper variables values at build time: applicationContext.xml To determine which filters file will be used depends on the profile chosen when building. For example, to build to production using the filters-PROD.properties we would execute the following: mvn clean deploy -P PROD The profile you use with the -P switch must match one of the values of the element for a profile. Conclusion Although it’s quite easy to get started with the Maven QuickStart project it is sometimes a bit frustrating putting some of the additonal pieces together. Building to several environments, setting up depenencies not included in the QuickStart project and strucuturing your project in an effort to make life easy for yourself as a developer and for your designer. I hope our Day 1 tutorial leaves you with a good sense of how a Wicket project is setup, now we can move onto coding the app! In the next four days we will be covering: Writing the Tests Designing the backend Designing the Wicket components Putting it all together Mystic Coders, LLC has been coding web magic since 2000. Mystic is a full-service Development Agency specializing in Enterprise development with Java. They are usually involved in developing enterprise-grade software for companies large and small, and have experience working in diverse industries, including b2b, b2c, and government-based projects. Mystic has done work with large companies such as LeapFrog, Nestlé, Harrah's Entertainment and the Los Angeles Conventions & Visitor's Bureau, among others. Andrew Lombardi, CTO of Mystic, is available for speaking engagements. For more about Mystic, check us out at http://www.mysticcoders.com
March 10, 2009
by Craig Tataryn
· 30,204 Views
article thumbnail
Performance Monitoring Using Glassbox
The industry is recognizing the fact that performance testing & engineering should be part of the project execution road map starting from the requirements gathering phase. At many times during project executions, performance engineering related activities are executed based on customer need or slow response time of application after development phase gets completed. Glassbox can be leveraged (by developers/testers/business users) during and after the development cycle to monitor the response times of requests with-out being aware of underlying application structure and code details. Analysis generated by Glassbox gives direct pointers on where is the bottleneck which causes slow response time for that particular request/page/URL. About Glassbox Glassbox is an open source web application which aid in performance monitoring and troubleshooting of multiple web applications deployed in container. Troubleshooting It contains the built-in knowledge repository of common problems which are used to pinpoint the issues and suggestions on causes as Java code executes. Performance Monitoring It monitors the requests as Java code executes and provides details about response times. Glassbox web client (AJAX GUI) provides nice summary dashboard view which contains various attributes like (server-name, application name, operation/request-URL, average time, no. of executions, status (slow / OK) and analysis details). By default, an operation that takes more than 1 sec execution time is marked as SLOW status. Such SLA can be modified using Glassbox properties file. Analysis part describes the problem precisely and very clearly in plain English words, rather than displaying large code/exception trace. This definitely increases developer productivity by reducing developer’s time spent in log files and using IDE debuggers. Internals The two main components of Glassbox are Monitor and Agent. Monitor uses Aspect-Oriented Programming (AOP) to monitor the JVM activity. Agent diagnoses and presents the monitoring results and uses knowledge repository to cross reference the problem with suggestions/solutions. Glassbox agent supports viewing of the analysis results using JMX (eg. Java 5 JConsole) Consoles. Glassbox extensively uses the AOP approach internally to monitor the Java code. This gives the benefit of not making any changes to source code or build-process and hence can work with any legacy web application/jar file as well. Technologies Glassbox should work on any application server that supports Servlet 2.3 or later. The servers where Glassbox is tested and installation process is automated are Apache Tomcat, weblogic, websphere, Resin, Oracle OC4J, websphere, Resin, Jetty & GlassFish. Overhead Having Glassbox application running on same container would generate a performance overhead. Typically this would affect the response time and memory overhead. Hence it is recommended to start the Glassbox application only when it’s required for performance monitoring. Licensing Glassbox is an open source project, it is free to download and run. Glassbox uses the GNU Lesser General Public License to distribute software and documentation. Demo Application Development & Deployment to Tomcat To test the capabilities of Glassbox, a sample application is developed which has a TestServlet class. This servlet calls DelayGenerator class’s generateDelay() method. This method calls Thread class’s sleep() method which suspends the execution of servlet. A counter is being initialized in DelayGenerator class which determines the time interval till which servlet is needed to be suspended. TestServlet.java /** * File: TestServlet.java * @author Viral Thakkar */ package com.infosys.star.glassbox; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TestServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { DelayGenerator delayObj = new DelayGenerator(); int delay = delayObj.generateDelay(); response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println(""); out.println(" Hello World from Test Servlet : "+delay+" milliseconds "); out.println(""); out.flush(); } } DelayGenerator.java /** * File: DelayGenerator.java * @author Viral Thakkar */ package com.infosys.star.glassbox; public class DelayGenerator { private static int counter = 1; public int generateDelay() { try { Thread.sleep(counter * 100); counter++; } catch (InterruptedException e) { e.printStackTrace(); } return counter*100; } } Glassbox Installation & Integration to Apache Tomcat 6.0 Glassbox installation is very straightforward for non-clustered environment for the server where it’s automated. Simply drop the glassbox.war file at the appropriate folder inside server folder or perform the server specific steps/configuration to deploy the war file. Browse to server url with context root as glassbox – http://<>:/glassbox. Follow the instructions available on this page. According to specific server, this page would suggest the configuration changes for a server. Please refer to Glassbox User Guide document for details on how to install Glassbox for clustered application server environment. For Apache Tomcat 6.0- Add following command line arguments to Tomcat’s Java options: -Dglassbox.install.dir=C:\Tomcat6.0\lib\glassbox -Djava.rmi.server.useCodebaseOnly=true -javaagent:C:\Tomcat6.0\lib\aspectjweaver.jar Monitoring & Technical Analysis Glassbox web client (URL- http://<>:<>/glassbox ) shows the summary and detailed view of all the requests/operations that container/JVM has executed. Summary Section View Different attributes (columns) which gets displayed in this table are as below - Attribute / Column Name Comments Status This indicates whether operation/request is performing OK, SLOW or FAILING Analysis For SLOW/FAILING status, this value provides the small summary of the cause of the problem. Operation This is name of the operation/request of an application Server Name of the server where monitoring is being done. In a clustered environment, this allows to distinguish operations on different servers. Executions This value indicates how many times this operation has run since the application server was started or Glassbox’s statistics were last reset. Click the request in above summary table to view its detailed analysis in below detailed section. Detailed Section View The details area provides information relating to operations selected in the summary table. Different sub-sections which gets displayed in this view are as below - Sub-section Name Comments Executive Summary High level summary view of the selected operation gets displayed in a table format. This is neat view to senior stake holders who are not interested in technical details. Technical Summary This section contains more technical details in paragraph and table representation formats to provide insight into root cause of the problem if any, like which operation, query is slow and statistics of same. Details like stack trace, thread lock name are provided to find and fix the problem. “Common solutions” sub section shows pointers to resolve the identified problem/s. “Glassbox has ruled out other potential problems” sub section saves time to know what problems have already been ruled out. Executive Summary View Technical Summary -> Technical Details Views Above two snapshots are parts of the Technical Details section and provide minute details at code level with line number so as to pinpoint where the problem is. Here cause is identified at Class com.infosys.star.glassbox.DelayGenerator inside Method generateDelay at line number 12 where Thread.sleep is invoked. Perform Load Testing Using JMeter and Monitor Using Glassbox Apache JMeter is used to test performance both on static and dynamic resources (files, Servlets, Perl scripts, Java Objects, Data Bases and Queries, FTP Servers and more). It can be used to simulate a heavy load on a server, network or object to test its strength or to analyze overall performance under different load types. It can be used to make a graphical analysis of performance or to test server/script/object behavior under heavy concurrent load. Using JMeter, create a test plan that simulates 10 users requesting for 1 page 5 times. i.e. 10 x 1 x 5 = 50 HTTP requests. First step is to add a Thread Group element. The Thread Group tells JMeter the number of users to simulate, how often the users should send requests, and the how many requests they should send. Next step is to add HTTP Request element to added Thread Group. In parallel, have the Glassbox up and running to monitor response time statistics of the load generated by JMeter application. Below is the Executive summary view of above test in Glassbox web UI interface. Section “Monitoring & Technical Analysis” contains the details to understand the Glassbox generated analysis. Conclusion Glassbox is not the replacement for performance testing tool like load runner. Glassbox aids in the project to various stakeholders in finding, conveying and fixing the performance problems at all phases starting build (development) to post deployment. Glassbox application to be started/installed only during monitoring time so as to avoid the performance overhead for other applications due to CPU & memory footprint occupied by Glassbox application on the container. During load testing of the application, Glassbox turns out to be good option to figure out the root causes inside an application code. References Glassbox web site - http://www.glassbox.com/glassbox/Home.html Glassbox User Guide - http://nchc.dl.sourceforge.net/sourceforge/glassbox/Glassboxv2.0UserGuide.pdf Apache JMeter - http://jakarta.apache.org/jmeter/ Download & Support Glassbox Download Link - http://www.glassbox.com/glassbox/Downloads.html Glassbox forum Link - http://sourceforge.net/forum/forum.php?forum_id=575670 About Author Viral Thakkar is a Technical Architect with the Banking and Capital Markets vertical at Infosys. He has 9.5 years of technology consulting experience mainly on Java/JEE technologies and frameworks with large banks and financial institutions across the globe. He has been part of many small and large-scale initiatives related to application development, architecture creation and strategy definition. From http://viralpatel.net/blogs
March 5, 2009
by Viral Thakkar
· 20,661 Views
article thumbnail
Integrate OpenOffice with Java without Installing OpenOffice
Until a few days ago, I've always needed to work with the rather cumbersome Office Bean and UNO Runtime when integrating OpenOffice into a Java application. I also had to configure a whole bunch of things to force OpenOffice to play nicely with the Java integration. Two days ago, however, I found out about ODF Toolkit. It seems to be a relatively new project, independent since last year some time, though I could be wrong. What's especially interesting is the ODFDOM: ''ODFDOM is an OpenDocument (ODF) framework. It's purpose is to provide an easy common way to create, access and manipulate ODF files, without requiring detailed knowledge of the ODF specification. It is designed to provide the ODF developer community an easy lightwork programming API, portable to any object-oriented language.'' Here's a snippet of it in action: public static void main(String[] args) { try { OdfDocument odfDoc = OdfDocument.loadDocument(new File("/home/geertjan/test.ods")); OdfFileDom odfContent = odfDoc.getContentDom(); XPath xpath = odfDoc.getXPath(); DTMNodeList nodeList = (DTMNodeList) xpath.evaluate("//table:table-row/table:table-cell[1]", odfContent, XPathConstants.NODESET); for (int i = 0; i < nodeList.getLength(); i++) { Node cell = nodeList.item(i); if (!cell.getTextContent().isEmpty()) { System.out.println(cell.getTextContent()); } } } catch (Exception ex) { //Handle... } } Let's assume that the 'test.ods' file above has this content: From the above, the code listing would print the following: Cuthbert Algernon Wilbert And, as a second example, here's me reading the first paragraph of an OpenOffice Text document: public static void main(String[] args) { try { OdfDocument odfDoc = OdfDocument.loadDocument(new File("/home/geertjan/chapter2.odt")); OdfFileDom odfContent = odfDoc.getContentDom(); XPath xpath = odfDoc.getXPath(); OdfParagraphElement para = (OdfParagraphElement) xpath.evaluate("//text:p[1]", odfContent, XPathConstants.NODE); System.out.println(para.getFirstChild().getNodeValue()); } catch (Exception ex) { //Handle... } } On my classpath I have "odfdom.jar" and "xerces-2.8.0.jar". I don't necessarily have OpenOffice installed, which means I can very easily process a whole bunch of spreadsheets (or other OpenOffice output) without (a) installing OpenOffice and (b) faster than I would otherwise do, since OpenOffice doesn't need to be started up, via the Office Bean or otherwise. In fact, Aljoscha Rittner from Sepix, who told me about this project and who is using it in his commercial applications, reports that his processing has sped up to a fraction of the original, also because he doesn't need to handle the situation where OpenOffice would crash randomly in the middle of long running processes, such as during the night when there's no human interaction for restarting it.
February 7, 2009
by Geertjan Wielenga
· 50,475 Views
article thumbnail
Generic Repository and DDD - Revisited
Greg Young talks about the generic repository pattern and how to reduce the architectural seam of the contract between the domain layer and the persistence layer. The Repository is the contract of the domain layer with the persistence layer - hence it makes sense to have the contract of the repository as close to the domain as possible. Instead of a contract as opaque as Repository.FindAllMatching(QueryObject o), it is always recommended that the domain layer looks at something self revealing as CustomerRepository.getCustomerByName(String name) that explicitly states out the participating entities of the domain. +1 on all his suggestions. However, he suggests using composition, instead of inheritance to encourage reuse along with encapsulation of the implementation details within the repository itself .. something like the following (Java ized) public class CustomerRepository implements ICustomerRepository { private Repository internalGenericRepository; public IEnumerable getCustomersWithFirstNameOf(string _Name) { internalGenericRepository.fetchByQueryObject( new CustomerFirstNameOfQuery(_Name)); //could be hql or whatever } } Quite some time ago, I had a series of blogs on DDD, JPA and how to use generic repositories as an implementation artifact. I had suggested the use of the Bridge pattern to allow independent evolution of the interface and the implementation hierarchies. The interface side of the bridge will model the domain aspect of the repository and will ultimately terminate at the contracts that the domain layer will use. The implementation side of the bridge will allow for multiple implementations of the generic repository, e.g. JPA, native Hibernate or even, with some tweaking, some other storage technologies like CouchDB or the file system. After all, the premise of the Repository is to offer a transparent storage and retrieval engine, so that the domain layer always has the feel that it is operating on an in-memory collection. // root of the repository interface public interface IRepository { List read(String query, Object[] params); } public class Repository implements IRepository { private RepositoryImpl repositoryImpl; public List read(String query, Object[] params) { return repositoryImpl.read(query, params); } //.. } Base class of the implementation side of the Bridge .. public abstract class RepositoryImpl { public abstract List read(String query, Object[] params); } One concrete implementation using JPA .. public class JpaRepository extends RepositoryImpl { // to be injected through DI in Spring private EntityManagerFactory factory; @Override public List read(String query, Object[] params) { //.. } Another implementation using Hibernate. We can have similar implementations for a file system based repository as well .. public class HibernateRepository extends RepositoryImpl { @Override public List read(String query, Object[] params) { // .. hibernate based implementation } } Domain contract for the repository of the entity Restaurant. It is not opaque or narrow, uses the Ubiquitous language and is self-revealing to the domain user .. public interface IRestaurantRepository { List restaurantsByName(final String name); //.. } A concrete implementation of the above interface. Implemented in terms of the implementation artifacts of the Bridge pattern. At the same time the implementation is not hardwired with any specific concrete repository engine (e.g. JPA or filesystem). This wiring will be done during runtime using dependency injection. public class RestaurantRepository extends Repository implements IRestaurantRepository { public List restaurantsByEntreeName(String entreeName) { Object[] params = new Object[1]; params[0] = entreeName; return read( "select r from Restaurant r where r.entrees.name like ?1", params); } // .. other methods implemented } One argument could be that the query string passed to the read() method is dependent on the specific engine used. But it can very easily be abstracted using a factory that returns the appropriate metadata required for the query (e.g. named queries for JPA). How does this compare with Greg Young's solution ? Some of the niceties of the above Bridge based solution are .. The architecture seam exposed to the domain layer is NOT opaque or narrow. The domain layer works with IRestaurantRepository, which is intention revealing enough. The actual implementation is injected using Dependency Injection. The specific implementation engine is abstracted away and once agian injected using DI. So, in the event of using alternative repository engines, the domain layer is NOT impacted. Greg Young suggests using composition instead of inheritance. The above design also uses composition to encapsulate the implementation within the abstract base class Repository. However in case you do not want to have the complexity or flexibility of allowing switching of implementations, one leg of the Bridge can be removed and the design simplified From http://debasishg.blogspot.com/
January 20, 2009
by Debasish Ghosh
· 40,638 Views · 1 Like
article thumbnail
The Three Pillars of Continuous Integration
Continuous Integration commonly known as CI is a process that consists of continuously compiling, testing, inspecting, and deploying source code. In any typical CI environment, this means running a new build every time code changes within a version control repository. Martin Fowler describes CI as: A software development practice where members of a team integrate their work frequently, usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly. While CI is actually a process, the term Continuous Integration often is associated with three important tools in particular. As shown in the image the three pillars of CI are: 1. A version control repository like Subversion, or CVS. 2. A CI Server such as Hudson, or Cruise Control 3. An automated build process like Ant or Nant So, let’s look at each of these in detail: Version Control Repository: Version control repositories also known as SCM (source code management) play a crucial role in any software development environment. They also play a very important role for a successful CI process. The SCM is a central place for the team to store every needed artifact for the project. It is mandatory for the teams to put everything needed for a successful build into this repository. This includes the build scripts, property files, database scripts, all the libraries required to build the software and so on. The CI Server: For CI to function properly, we also need to have an automated process that monitors a version control repository and runs a build when any changes are detected. There are several CI servers available, both open source and commercial. Most of them are similar in their basic configuration and monitor a particular version control repository and run builds when any changes are detected. Some of the most commonly used open source CI servers are; Cruise Control, Continuum, and Hudson. Hudson is particularly interesting because of its ease of configuration and compelling plug-ins, which makes integration with test and static analysis tools much easier. Automated Build: The process of CI is about building software often, which is accomplished through the use of a build. A sturdy build strategy is by far the most important aspect of a successful CI process. In the absence of a solid build that does more than compile your code, CI withers. With automated builds, teams can reliably perform (in an automated fashion) otherwise manual tasks like compilation, testing, and even more interesting things like software inspection and deployment. Now that we have seen the important tools in our CI process, let’s see how a typical CI scenario looks like for a developer: CI server is configured to poll the version control repository continuously for changes. Developer commits code to the repository. CI server detects this change, and retrieves the latest code from the repository. This causes the CI server to invoke the build script with the given targets and options. If configured, CI Server will send out an e-mail to the specified recipients when a certain important event occurs. The CI server continues to poll for changes. Why is CI Important? This is one of the most frequently asked questions, and here are a few points to note about this powerful technique: Building software often greatly increases the likelihood that you will spot defects early, when they still are relatively manageable. Extends defect visibility. CI ensures that you have production ready software at every change. CI also ensures that you have reduced the risk of integration issues by building software at every change. CI server can also be configured to run continuous inspection which can assist the development team in finding potential bugs, bad programming practice, automatically check coding standards, and also provide valuable feedback on the quality of code being written. Over the past several months, I have assisted several companies in implementing CI. There was a little bit of resistance from the developers in the early stages when we implemented continuous feedback. But, never heard a single negative comment about this approach. If you already have a version control repository and automated builds, you are very close to the CI process. Download one of the open source CI servers, configure and setup a simple project. It should take less than an hour if you have automated build scripts. Start adding additional features like code inspections, generating reports, metrics, documentation and so on. Most important, send continuous feedback to your team. Give this process a try, you sure will be surprised to see how effective it is. And, as always share your thoughts, concerns or questions.
December 15, 2008
by Meera Subbarao
· 23,915 Views
article thumbnail
Configuring Logging in JBoss
Learn how to properly configure logs in JBoss.
November 19, 2008
by Meera Subbarao
· 223,134 Views
article thumbnail
Performance of SOAP/HTTP vs. SOAP/JMS
today soa is the most prevalent enterprise architecture style. in most cases services (s in soa) are realized using web services specification(s). web services are, in most cases, implemented using http as transport protocol but other options exists. as new architecture style emerges, such as eda, more message friendly transport protocols pops out. in java environments most used is jms. in spite the fact that soap/jms specification is still in draft, jms is supported in all major (java) ws stacks. ibm supports soap/jms bindings in their implementation of jax-rpc framework and recently in jax-ws for websphere application server (was) 7. reason for choosing jms in most cases is reliability. but there are other things that come in mind whether to choose jms or http. reasons to go with http: firewall friendly (web services exposed over internet) supported on all platforms (easiest connectivity in b2b scenario) clients can be simple and lightweight reasons to go with jms: assured delivery and/or only once delivery asynchronous support publish/subscribe queuing if better for achieving larger scalability and reliability better handles temporary high load large volume of messages (eda) better support in middleware software transaction boundary in soa architecture best practice is to use jms internally (for clients/providers that can easily connect to esb) and http for connecting to outside partners (over internet). performance report it will be interesting to compare performance of soap/http and soap/jms services. a few documents on this subject can be found. one of the documents, titled “efficiency of soap versus jms” can be found on the link http://www.unf.edu/~ree/1024ic.pdf. this paper is research paper and compares performance of soap/http to jms system (not soap/jms). it will be interesting to see how soap/http compares to soap/jms using same framework. test setup i have created a simple “hello world” web service using jax-rpc. wsdl has soap/http and soap/jms binding and is deployed to websphere application server v6.1 express (was). server was installed in most basic installation (without http server and db2). was default messaging provider (also called sibus) was used for jms. as implementation is the same for both bindings we can measure communication overhead and compare protocols. i have set up only one machine so we can’t compare scalability. that can be read in paper mentioned above. what we can do, we can test protocols with various concurrent requests and different message sizes. as test tool jmeter is used (http://jakarta.apache.org/jmeter/). jmeter is well known load and performance tool. test was performed on laptop lenovo r61 with 3 gb of ram. server was installed in virtual machine and connected with 1gb network with host (private network with host). at all scenarios processer wasn’t used up to 100% percent so speed of network was limiting factor. to test protocols with different message sizes there are 4 different soap messages. each “hello world” message is simple message with x times hello like: hellohellohellohellohello…. message sizes are in range from half of kilobyte to 102 kilobytes. the same message was send using http and jms 3 times. response time was measured alternating number of concurrent requests. results of the test can be seen in table below. we can look the same results using graph representation. bars are colored according to message size and on vertical axis is average response. every test was performed with loop count set to 100 (except the 102kb messages, tests were stopped when average time was stable). 1. single request when conducting test with only one request we can see some strange results. differences between http and jms are not big, in all scenarios but first. i believe that first request was taking 196 ms because jmeter needed to create initialcontext and fetch queue connection factory and queues from jndi. however same remark doesn’t fit other message sizes. jmeter probably had resources in its internal cache. 2. 30 concurrent requests testing performance with 30 conurrent users we can’t see big differences except with really small messages where http is faster and messages with size of 3,5 kb where jms was faster. it looks like penalty for creating jms connection is higher than penalty for creating new http request. strange results are with 3,5 kb messages. it looks like jms likes messages with that size more than http. 3. 100 concurrent requests i didn’t put load over 100 concurent requests because it was too much for build in http server in was. if i did, after short amount of time, i was getting errors from jmeter http client. again we can see that jms is little slower then http with all messages except 3,5 kb messages when is actually faster. 4. all together putting all data on one graph we can see that there are no big differences in speed between http and jms. choosing one or other should be decided based on non-functional requirements other then performance. miroslav rešetar [email protected]
November 5, 2008
by Miroslav Rešetar
· 75,068 Views
article thumbnail
A Simple Manual Mock Example
Creating and using a mock object is semantically very much like using a stub, except that a mock will do a little more than a stub - it will save the history of communication so that it can later be verified. Let's add a new requirement to our LogAnalyzer class. It will have to interact with an external web service that will receive an error message whenever the LogAnalyzer encounters a filename whose length is not too long. [img_assist|nid=5444|title=|desc=|link=url|url=http://www.manning.com/osherove/|align=left|width=142|height=178]Unfortunately, the web service we'd like to test against is still not fully functional, and even if it were, it would have taken too long to use it as part of our tests. Because of that, we'll refactor our design and create a new interface that we can use to later create a mock object of. The interface will have the methods we will need to call on our web service, and nothing else. Figure 1 shows how the test will work with our MockWebService. [img_assist|nid=5443|title=|desc=|link=none|align=none|width=485|height=350] First off, let's extract a simple interface that we can use in our code under test, instead of talking directly to the web service. public interface IWebService { void LogError(string message); } This interface will serve us when we want to create stubs as well as mocks, without needing to have an external dependency on a project we have no control of. Next, we'll create the mock object itself. It may look like a stub, but it contains one little bit of extra code that makes it a mock object. public class MockService:IWebService { public string LastError; public void LogError(string message) { LastError = message; } } Our mock implements an interface just like a stub, but saves some state for later, so that our test can then assert and verify that our mock was called correctly. Listing 1 shows what the test might look like: Listing 1: The log analyzer under test actually calls our mock object, which holds on to the string that is passed into the implemented method, and later asserted in the test. [Test] public void Analyze_TooShortFileName_CallsWebService() { MockService mockService = new MockService(); LogAnalyzer log = new LogAnalyzer(mockService); string tooShortFileName="abc.ext"; log.Analyze(tooShortFileName); Assert.AreEqual("Filename too short:abc.ext", |#1 mockService.LastError); |#1 } public class LogAnalyzer { private IWebService service; public LogAnalyzer(IWebService service) { this.service = service; } public void Analyze(string fileName) { if(fileName.Length<8) { service.LogError("Filename too short:" |#2 + fileName); |#2 } } } Annotation #1: The assert is done against the mock service, and not against the class under test Annotation #2: The method part we're going to test Notice how the assert is performed against the mock object, and not against the LogAnalyzer class. That's because we are testing the interaction between LogAnalyzer and the web service. We still use the same dependency injection techniques, but this time the stub also makes or breaks the test. That's why it's a mock object. Also notice that we are not writing the tests directly inside the mock object code. There are several reasons for this. We'd like to be able to re-use the mock object in other test cases, with other asserts on the message. If the assert is found inside the mock object, whoever is reading the test will have no idea what we are asserting. We will be hiding essential information from the test code, which hinders the readability and maintainability aspect of the test. In many scenarios in your tests, you might find that you need to replace more than one object for the test to be able to work, which involves combining mocks and stubs. This article is taken from the book The Art of Unit Testing. As part of a chapter on interactive testing using mock objects, this segment shows how to create and use a mock object and helps differentiate mock objects from stubs.
October 13, 2008
by Schalk Neethling
· 31,557 Views
article thumbnail
A Look Inside the JBoss Microcontainer, Part I -- Component Models
Looking at the current state of Java, we can see that POJOs (Plain Old Java Objects) rule the land yet again. Their dominance stretches from enterprise applications to middleware services. At JBoss we were known for our modular JMX-based kernel. The application server was nothing more than a bunch of flexible MBeans and a powerful MicroKernel in the middle. But, as you could feel the change is coming, we still wanted to be ahead of the pack. We could see different POJO based component models popping up all over the place (EJB3, JPA, Spring, Guice, … to name a few), yet nothing was out there that would bind them all, flattening out the differences on a single component model. Hence the Microcontainer project was born. The JBoss Microcontainer project is about many things. The Microcontainer's features range from reflection abstraction, a virtual file system, a simple state machine to transparent AOP integration, a new classloading layer, a deployment framework and an OSGi framework implementation. I'll try to address them all over a short series of articles that will be published here on DZone. This article will examine the Microcontainer's component models. Read the other parts in DZone's exclusive JBoss Microcontainer Series: Part 1 -- Component Models Part 2 –- Advanced Dependency Injection and IoC Part 3 -- the Virtual File System Part 4 -- ClassLoading Layer Part 5 - the Virtual Deployment Framework Part 6 - The Scanning Library What is a component model? What do we consider a component model? First of all, what do we consider being a component? One abstract way to express this would be that “components are reusable software programs that you can develop and assemble easily to create sophisticated applications.” To consider a bunch of components as an actual model, we also need to declare what kind of interactions we allow. JMX MBeans are one example of a component model. Their interactions include executing MBean operations, referencing attributes, setting attributes and declaring explicit dependencies between named MBeans. As mentioned, we had advanced JMX handling already with the MicroKernel. And as expected, the Microcontainer brought extensive POJO support. The default behavior and interactions in the Microcontainer are what you also normally get from any other IoC container and are similar to the functionality that MBeans provided: plain method invocations for operations, setters/getters for attributes and explicit dependencies. However, having only this functionality would mean we didn't get much further than just relieving the pain of declaring MBeans, hence it was only logical for us to do something more. I'll leave the discussion of these new IoC features for the next article in the series. There are many existing POJO component models out there, Guice and Spring being amongst the most popular. Effective integration with these frameworks was an important goal for us. Demo environment setup Before we begin, I'd like to first describe the various parts that constitute the demo. All the source code can be found at this location of our Subversion repository: • http://anonsvn.jboss.org/repos/jbossas/projects/demos/microcontainer/branches/DZone_1_0/ The project is fully mavenized, so it should be easy to adjust it to your IDE. I will first go over the sub-projects within the demo and describe their usage. At the end of my article series, I will provide a more detailed look at what certain sub-projects do. Below are the JBoss Microcontainer demos and sub-projects that are relevant for this article: • bootstrap (as the name suggests, it bootstraps the Microcontainer with demo code) • jmx (adds the JMX notion to demo's bootstrap) • models (source code of our components / services) The demo has only one variable you need to set - demos home - but even this one can be optional if you checked-out your project into the \projects\demos directory. Otherwise, you need to set the system property demos.home (e.g. -Ddemos.home=). You should now be able to run JMXMain as a main class. Make sure you include the models sub-project in the classpath, since some of the services require additional classes in the classpath, several more then what the jmx sub-project expects. Once the Microcontainer is booted it starts to scan the ${demos.home}/sandbox directory for any changes. Now all we need to do is provide a deployable unit and drop it in there. Models Let’s now turn our attention to the models sub-project. This is where the previously mentioned deployable unit should come from. You can see if everything is in place by building the models sub-project (mvn package) and dropping it into the sandbox. You should get a bunch of debug and info messages on the console log, showing how the Microcontainer got booted. Any error message indicates some problems. Let’s go over exactly what the models sub-project does, its integration code and try to redeploy it. If we look at the models src/main/resources/META-INF directory, we'll see plenty of -beans.xml resource files and one -service.xml. You’ll notice that each has a meaningful name that matches the source code package from models's src/main/java/org/jboss/demos/models directory. Let's dissect them one by one, starting with the ones that have no dependencies. org.jboss.demos.models.plain.PojoFactory This is a simple Micrcocontainer beans descriptor file. Anyone who crossed paths with some other IoC’s configuration file should be familiar with it. And, as I already mentioned, I'll follow up on more advanced usage in the next article. The next file shows what we have done to support Spring integration: Note that this file's namespace is different from the previous Microcontainer bean’s plain-beans.xml file. The urn:jboss:spring-beans:2.0 namespace points to our version of the Spring schema port, meaning you can describe your beans Spring style, but it's the Microcontainer that's going deploy then, not Spring's bean factory notion. public class Pojo extends AbstractPojo implements BeanNameAware { private String beanName; public void setBeanName(String name) { beanName = name; } public String getBeanName() { return beanName; } public void start() { if ("SpringPojo".equals(getBeanName()) == false) throw new IllegalArgumentException("Name doesn't match: " + getBeanName()); } } Although the SpringPojo bean has a dependency on Spring lib via implementing BeanNameAware interface, this dependency is only there to expose and mock some of the Spring's callback behavior (see SpringBeanAnnotationPlugin for more details). Since we introduced Spring integration, let's have a look at Guice integration. As Guice users know, Guice is all about type matching. Configuration of Guice beans is done via Modules which means that in order to generate beans, one must implement a Module. Two important parts to watch from this file are PojoModule and GuiceKernelRegistryEntryPlugin. The first one is where we configure our beans: public class PojoModule extends AbstractModule { private Controller controller; @Constructor public PojoModule(@Inject(bean = KernelConstants.KERNEL_CONTROLLER_NAME) Controller controller) { this.controller = controller; } protected void configure() { bind(Controller.class).toInstance(controller); bind(IPojo.class).to(Pojo.class).in(Scopes.SINGLETON); bind(IPojo.class).annotatedWith(FromMC.class).toProvider(GuiceIntegration.fromMicrocontainer(IPojo.class, "PlainPojo")); } } The second class provides integration with the Microcontainer: public class GuiceKernelRegistryEntryPlugin implements KernelRegistryPlugin { private Injector injector; public GuiceKernelRegistryEntryPlugin(Module... modules) { injector = Guice.createInjector(modules); } public void destroy() { injector = null; } public KernelRegistryEntry getEntry(Object name) { KernelRegistryEntry entry = null; try { if (name instanceof Class) { Class clazz = (Class)name; entry = new AbstractKernelRegistryEntry(name, injector.getInstance(clazz)); } else if (name instanceof Key) { Key key = (Key)name; entry = new AbstractKernelRegistryEntry(name, injector.getInstance(key)); } } catch (Exception ignored) { } return entry; } } Notice how we created an Injector from the Modules and then did a lookup on it for matching beans. In mbeans-service.xml we declare our legacy usage of MBeans: What’s interesting to note here is how we injected a POJO into an MBean. The preceding demonstrated our first interactions between different component models. In order to allow for MBean deployment via the Microcontainer, we had to write entirely new component model handling code. See the system-jmx-beans.xml for more details. The code from this file lives in the JBossAS source code: system-jmx sub-project. One note here, this is currently only possible with JBoss's JMX implementation, since the system-jmx code uses some implementation details. Now what if we wanted to expose our existing POJOs as MBeans, registering them into an Mbean server? @org.jboss.aop.microcontainer.aspects.jmx.JMX(exposedInterface=org.jboss.demos.models.mbeans.PojoMBean.class, registerDirectly=true) As you can see from looking at any of the beans in this file, in order to expose your POJOs as MBeans, it’s simply a matter of annotating them with an @JMX annotation. You can either expose the bean directly or its property: Here we see how you can use any of the injection lookup types by either looking up a plain POJO or getting a handle to an MBean from the MBean server. One of the injection options is to use type injection, which is also sometimes called autowiring: The FromGuice bean injects the Guice bean via type matching, where PlainPojo is injected with a common name injection. We then test if Guice binding works as expected: public class FromGuice { private IPojo plainPojo; private org.jboss.demos.models.guice.Pojo guicePojo; public FromGuice(IPojo plainPojo) { this.plainPojo = plainPojo; } public void setGuicePojo(org.jboss.demos.models.guice.Pojo guicePojo) { this.guicePojo = guicePojo; } public void start() { f (plainPojo != guicePojo.getMcPojo()) throw new IllegalArgumentException("Pojos are not the same: " + plainPojo + "!=" + guicePojo.getMcPojo()); } } This only leaves us with an alias component model. Even though the alias is quite a trivial feature, in order to implement it as a true dependency, it has to be introduced as a new component model inside the Microcontainer. The implementation details for this is part of the AbstractController source code: springPojo Here we’ve mapped the SpringPojo name to the springPojo alias. The beauty of having aliases as true component models is that it doesn't matter when the real bean gets deployed. This means that the alias will wait in a non-installed state until the real bean triggers it. Conclusion We've seen how we can deploy simple Microcontainer beans, legacy MBeans, Guice POJOs, Spring beans and aliases. And since all of this is controlled by the Microcontainer, we saw how easily we can mix and match the different component models. I can easily say, with the level of abstraction we put in our component model design, the sky is the limit on what we can handle. An example of this is the upcoming OSGi services, but that's another story, another article. Stayed tuned for my next article which will provide a detailed look at the Microcontainer's IoC functionality. About the Author Ales Justin was born in Ljubljana, Slovenia and graduated with a degree in mathematics from the University of Ljubljana. He fell in love with Java seven years ago and has spent most of his time developing information systems, ranging from customer service to energy management. He joined JBoss in 2006 to work full time on the Microcontainer project, currently serving as its lead. He also contributes to JBoss AS and is Seam and Spring integration specialist. He represent JBoss on 'JSR-291 Dynamic Component Support for Java SE' and 'OSGi' expert groups.
October 1, 2008
by Ales Justin
· 57,334 Views
article thumbnail
Ant or Gant?
Yes, this is exactly what I am frequently asked by my clients and many developers. It isn't easy to answer this question. There are several projects using Ant. Should you run away from Ant just because there is a new cool tool out there called Gant? Should you switch to Gant just because you dislike XML? Not at all. Let's take a closer look and see what might make you switch to Gant. When to choose Gant? 1. Complicated Build Files. If your ant build files are becoming too complicated, and hard to manage, it's time to see if using Gant can help. Let me explain what I mean by complicated build files. If you have too much of conditional logic within your build files, say something similar on the lines shown below in Listing 1: Code Listing 1: Or even something like this where you might be supporting deployment to different application servers based on some property in your build.properties as shown in listing 2. Code Listing 2: Things get out of hand when you have conditional logic as shown above in your build scripts. The listings I have are just the skeleton, imagine what happens when we start adding the actual deployment logic for all these application servers. It doesn't matter how you refactor this, it is still going to be very complicated. Trust me, I have written build scripts which were several thousand lines, and refactoring them was not a trivial task. 2. Custom Ant Tasks. I myself am guilty of writing many of these. There are many situations which arise in projects where we create custom ant tasks. It is simple once you know how to write one, and than for every complicated task you need to perform, you involuntarily will start writing custom ant tasks. Anyone writing a custom ant task will: a. Create a new class that extends Ant’s org.apache.tools.ant.Task class. b. For each attribute, write a setter method. c. Write an execute()method that does what you want this task to do. There isn't anything wrong in doing the above, but imagine each time you want to make a small change, you will have to make changes within your Java source code, compile, test, and re-package. 3. Scripting. You can extend Ant further by not writing custom ant tasks, but by using small snippets of code written in an interpreted language like JRuby, BeanShell, or Groovy. These code snippets can be placed within your build files or in separate text files. If you are using Groovy's Ant task, your build file might look something like this: Code Listing 3: import some.package import another.package def fullpath = "${.basedir}/${defaulttargetdir}" def somefile = new SomeFile(projectName:"${pname}", buildLabel:"${label}", buildTime:"${new Date()}") def xml = "${fullpath}/dashboard.xml" new File(path).write(somefile.generateReport()) ant.xslt(in:path, out:"${properties.defaulttargetdir}/some.html", style:"${properties.defaulttargetdir}/lib/report-style.xsl") Imagine having several lines of XML in your build files which have many of these small snippets of scripts. I myself don't like mixing and matching build files with code snippets. If you have a team where everyone is in the same page, everything works fine. What if a team member has no clue about any of the Scripting languages? He/She will have no clue how to make minor changes when things go badly. If you have all the above or even one of the above three cases, you seriously need to consider using Gant. To quote Aristotle: For the things we have to learn before we can do them, we learn by doing them." So, lets see how easy it is to learn Gant and see how things can improve. This part covers the very basics of Gant. The next part, will dive deeper into Gant by using it with a sample project to build an application, and we will also see how to use it with our CI Server. What's Gant? Gant is a build tool that uses both Groovy and Ant. With Gant, you describe your build process using Groovy scripts. Stated simply, Gant allows you to specify the build logic using Groovy instead of XML. The next thing you may ask is " Is Gant a competitor to Ant?". Let me quote from the Gant web site to make thing more clear here : Whilst it might be seen as a competitor to Ant, Gant uses Ant tasks for many of the actions, so Gant is really an alternative way of doing builds using Ant, but using a programming language rather than XML to specify the build rules. Download and Install Gant. In order for Gant to work, you should have Groovy installed. You can download and follow the installation instructions for Groovy here. As I said earlier also, in order to use Gant, you should have knowledge of Groovy as well. If you have never written Groovy code before, there are many interesting books on Groovy like: 1. Groovy in Action 2. Groovy Recipes 3. Groocy Refcardz You can also read the getting started guide on the Groovy web site, which should give you a good starting point. Download the latest version of Gant from here. Gant is currently at version 1.4.0. Unzip it to a folder. If you already have your GROOVY_HOME set, that's all you need to use Gant. Getting Started. Open a console, and type gant. You should see a message as shown below: meera-subbaraos-macbook-9:~ meerasubbarao$ gant Cannot open file build.gant meera-subbaraos-macbook-9:~ meerasubbarao$ You are all set at this point to use Gant in your projects. Help Information: Open a console, and type gant -h. This will provide you with all the necessary help information you need as shown below: meera-subbaraos-macbook-9:CodeMetricsProject meerasubbarao$ gant -h usage: gant [option]* [target]* -c,--usecache Whether to cache the generated class and perform modified checks on the file before re-compilation. -n,--dry-run Do not actually action any tasks. -C,--cachedir The directory where to cache generated classes to. -D = Define to have value . Creates a variable named for use in the scripts and a property named for the Ant tasks. -L,--lib Add a directory to search for jars and classes. -P,--classpath Specify a path to search for jars and classes. -T,--targets Print out a list of the possible targets. -V,--version Print the version number and exit. -d,--debug Print debug levels of information. -f,--file Use the named build file instead of the default, build.gant. -h,--help Print out this message. -l,--gantlib A directory that contains classes to be used as extra Gant modules, -p,--projecthelp Print out a list of the possible targets. -q,--quiet Do not print out much when executing. -s,--silent Print out nothing when executing. -v,--verbose Print lots of extra information. Create a new file called build.gant at the root of your project. Did a similarity between Ant and Gant strike you here? Ant build files are usually called build.xml, and they are created as a common practice within the root of your project folder as well. If you have written or even modified Ant build files, you will know that it contains one project element, which in turn contains a name,the default target and the base directory. Code Listing 4: So for example, sayHello target in Ant would look something like this: Lets create the sayHello target, and also see how to set it as the default target in Gant as well. A Gant target has a name and a description: Code Listing 5: target ( target-name : target-description ) { groovy code sequence } The above sayHello target in Gant would translate as shown below: target(sayHello:"Saying hello"){ Ant.echo(message:"Hello Javalobby") } Now, open a command window and type gant at the root of the project where the build.gant file exists. You should be able to see a output like: meera-subbaraos-macbook-9:CodeMetricsProject meerasubbarao$ gant Target default does not exist. Gant is complaining that we haven't set a Default target. Lets see how to do the same: Default target: Within Ant, you define the default target from within the project element as seen in Listing 4. The default target is the target called if no target is specified from the command line. There however is no project tag within Gant. There are two ways of specifying the default target as shown below: 1. You simply create a target whose name is default. target ( 'default' , 'The default target.' ) { aTarget ( ) 2. or even simply: setDefaultTarget ( aTarget ) In order to get our sayHello target working, we need to add one of the above scripts to our build.gant file. Code Listing 6: setDefaultTarget(sayHello) or target ("default": "The default target." ) { sayHello ( ) } Complete listing of build.gant: target(sayHello:"Saying hello"){ Ant.echo(message:"Hello Javalobby") } /* target ("default": "The default target." ) { sayHello ( ) } */ setDefaultTarget(sayHello) And you should be able to see: meera-subbaraos-macbook-9:CodeMetricsProject meerasubbarao$ gant [echo] Hello Javalobby meera-subbaraos-macbook-9:CodeMetricsProject meerasubbarao$ That was easy! If you have build files and it is becoming unmanageable by your team, there is a tool out there which can convert your Ant scripts to Gant scripts as well. I haven't used it, but you can try it here. In this part of the series, we learned when to move over from Ant to Gant, downloaded and installed Gant, and finally wrote a simple gant build file. In the next part of this series, we will see Gant in Action within a simple Java project. And as always, keep us posted here if you are encountering any problems getting started with Gant. Stay tuned.
September 23, 2008
by Meera Subbarao
· 52,241 Views
article thumbnail
Javadoc or Doxygen?
In the last two articles, "Reverse-engineer Source Code into UML Diagrams" and "Visual Documentation of Ant Dependencies in 3 Simple Steps" we saw how easy and valuable it was to automate technical documentation. By using open source tools, we were easily able to provide good technical documentation within a few minutes, and at no cost at all. We were also able to keep this up-to date by adding additional tasks to our Ant build files, and run them from our CI Server(Hudson in our case) on commit and nightly builds, and also publish the results. In this article, I will be showing you how to use yet another tool called Doxygen for generating technical documentation based on your source code. We all have used Javadoc and have been using it for a long time, right? So, you may ask what's the need to have another tool which produces the same HTML documentation? Doxygen has a slight edge over Javadoc and here are a few reasons why you should consider using the same: With Javadoc you have to remember all the HTML tags, you need to embed within your code comments. However, with Doxygen code comments are much more concise and polished, without the need for any HTML. Doxygen can also generate a variety of diagrams, we will take a look at some of them later. Doxygen also provides a structured view on the source code. As I mentioned in 2 above in the form of various diagrams, cross-referenced and syntax highlighted code. You get all the above benefits even if the code does not have any comments at all. Last but not the least, Doxygen is a documentation system not for just Java but also for various other languages like C++, C, Java, Objective-C, Python, IDL (Corba and Microsoft flavors), Fortran, VHDL, PHP, C#. So, without wasting further time, lets see what we need to get started with Doxygen. Step 1. Download, Install Doxygen. Download the binary distribution for Doxygen for the operating system you are using. I downloaded the binary distribution for Mac OS X called Doxygen-1.5.6.dmg. Installation is very simple, just drag the doxygen icon from this folder to the Applications folder, or wherever you want to keep it; as shown. I dropped it within my Applications folder. Just be sure to remember where you dragged it. To uninstall, just delete the file. It is completely self-contained. Step 2: Configure Doxygen. To generate documentation using Doxygen, you will need a configuration file called the Doxyfile. You can generate this file in two ways; either by using the Doxygen wizard or by using the command line option. Lets see how to use both these options to generate the configuration file: a. Command line. Open a command window and type the following as shown below: You should be able to locate the configuration file created within your default user folder. The file looks like this: # Doxyfile 1.5.6 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = b. Wizard Option. Launch the Doxygen application, and you should be able to create the configuration file using the wizard approach as shown below. The user interface is quite intuitive so I am going to skip explaining this in detail. The wizard approach was the one I used to get the initial settings for the configuration file. which you can always modify later. A few options in my Doxygen configuration file are as follows: # Doxyfile 1.5.6 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = PetStore PROJECT_NUMBER = 1.0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html GENERATE_TREEVIEW = YES Step 3. Doxygen and Ant. In order to use Doxygen, we need an Ant task. There is already an Ant task written for Doxygen which you can download from here. As always, since using Mac, when I downloaded the binaries and tried to use them, I got the ever famous error message : java.lang.UnsupportedClassVersionError: Bad version number in .class file So, had to do download the source, compile, and jar it up. Copy this library to your projects folder. Next, lets start making changes to our build file. 3.a: Lets define the Doxygen task. 3.b: To generate HTML documentation: 3.c: Lets combine them in target and run: [doxygen] Exec: /Applications/Doxygen.app reports/Doxyfile BUILD FAILED /CodeMetricsProject/build.xml:91: Doxygen not found on the PATH. Total time: 7 seconds 3.d: So, to launch Doxygen not in the path. we make change to the doxygen task as shown below: Lets run the target again and see if it fixed things.Yes indeed. generate-doxygen-docs: [doxygen] Exec: /Applications/Doxygen.app/Contents/Resources/doxygen reports/Doxyfile BUILD SUCCESSFUL Total time: 8 seconds 4. Integrate with Hudson. 4.a Modify Hudson Job. Once you have an Ant target working, calling this from your CI server is trivial. Within Hudson, select your Job, click on configure and add this new target to be called when running the build. 4.b Publish the reports. 4. c: Sample Reports. Force a build, and take a detailed look at the reports generated by Doxygen as shown below: I have given you a brief overview of Doxygen in this article, how to configure the same, and use it effectively to generate technical documentation on a continuous basis; either on commit builds or nightly builds. The Doxygen web site has lots of information on how to use it with other programming languages and also has tutorials in languages other than English as well. As always, if you are having trouble getting Doxygen to work, leave a comment or check out the Doxygen web site.
September 10, 2008
by Meera Subbarao
· 49,764 Views · 1 Like
article thumbnail
EJB 3.0 and Spring 2.5
Why is it that developers from these two communities don't like to see eye to eye? I have been using both Spring from its inception, and EJB's from 2001. Just like everyone else did, I just dreaded the huge amount of XML we had to write for both of these; configuration files in Spring, and deployment descriptors in EJB 2.x. However, Java 5 came to our rescue and now annotations have mostly replaced XML files in both these. But, after having used these two latest versions Spring 2.5 and EJB 3.0, I think that they complement each other, rather than compete with each other. There are certain features which are powerful in Spring, and equal number of features powerful on the EJB side as well. Many developers fail to understand, that Spring is a popular non-standard framework created by Spring Source, while EJB 3.0 is a specification which is supported by major JEE vendors. There are a few developers with whom I have worked earlier, prefer to use standard specification, and they chose EJB2.x/ and are moving now to EJB 3.0. However, there isn't anything stopping you from using Spring along with EJB, is it? The complaint I have heard many times is: We can't use non-standard framework". The same developers who complain about Spring being non-standard use home grown frameworks, which was and will be forever so hard to even decipher. How can it be a specification when a couple of developers write several thousand lines of code? Also, a recent article published here at Javalobby by Adam Bien showed the trend moving towards EJB 3.0, right? Anyway, in this article we will see how by adding a few lines in your Spring configuration file, you can seamlessly use EJB 3.0 components within your Spring application. Back to our EJB 3.0 and Spring 2.5 article, we are going to see how easy and simple it is to access EJB 3.0 components in Spring by using its powerful dependency injection mechanism to inject an instance of our Customer session bean. This Customer session bean, in turn uses the Entity Manager for the CRUD operations on the Customer Entity. Here are the detailed steps: Step 1: Create a simple JPA Entity. The Java Persistence API (JPA) is defined as part of the Java EE 5 specification. Creating entities using JPA is as simple as creating a POJO with a few annotations as shown below: package com.ejb.domain; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; /** * * @author meerasubbarao */ @Entity @Table(name = "CUSTOMER", catalog = "", schema = "ADMIN") public class Customer implements Serializable { private static final long serialVersionUID = 1L; @Id @Column(name = "CUSTOMER_ID") private Long customerId; @Column(name = "FIRST_NAME") private String firstName; @Column(name = "LAST_NAME") private String lastName; @Column(name = "MIDDLE_NAME") private String middleName; @Column(name = "EMAIL_ID") private String emailId; public Customer() { } public Customer(Long customerId) { this.customerId = customerId; } public Long getCustomerId() { return customerId; } public void setCustomerId(Long customerId) { this.customerId = customerId; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getMiddleName() { return middleName; } public void setMiddleName(String middleName) { this.middleName = middleName; } public String getEmailId() { return emailId; } public void setEmailId(String emailId) { this.emailId = emailId; } } Step 2: Create a EJB 3.0 Session bean. This session beans uses the Entity Manager for the Create Read Update Delete (CRUD) operations for the Customer Entity we created in Step 1. The CRUD opertions are also published as web methods by adding a few basic annotations. The Interface: package com.ejb.service; import com.ejb.domain.Customer; import java.util.Collection; import javax.ejb.Remote; /** * * @author meerasubbarao */ @Remote public interface CustomerService { Customer create(Customer info); Customer update(Customer info); void remove(Long customerId); Collection findAll(); Customer[] findAllAsArray(); Customer findByPrimaryKey(Long customerId); } The Implementation Class: package com.ejb.service; import com.ejb.domain.Customer; import java.util.Collection; import javax.ejb.Stateless; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import javax.jws.WebMethod; /** * * @author meerasubbarao */ @WebService(name = "CustomerService", serviceName = "CustomerService", targetNamespace = "urn:CustomerService") @SOAPBinding(style = SOAPBinding.Style.RPC) @Stateless(name = "CustomerService") public class CustomerServiceImpl implements CustomerService { @PersistenceContext private EntityManager manager; @WebMethod public Customer create(Customer info) { this.manager.persist(info); return info; } @WebMethod public Customer update(Customer info) { return this.manager.merge(info); } @WebMethod public void remove(Long customerId) { this.manager.remove(this.manager.getReference(Customer.class, customerId)); } public Collection findAll() { Query query = this.manager.createQuery("SELECT c FROM Customer c"); return query.getResultList(); } @WebMethod public Customer[] findAllAsArray() { Collection collection = findAll(); return (Customer[]) collection.toArray(new Customer[collection.size()]); } @WebMethod public Customer findByPrimaryKey(Long customerId) { return (Customer) this.manager.find(Customer.class, customerId); } } Step 3. Compile, Package and Deploy to an application server. There are no server specific annotations in either the Entity class or the Session bean. Package the entity class, the session bean interface, implemetation class along with the persistence.xml file in a JAR file. Since I am deploying this application to GlassFish, I am using the default persistence provider which is TopLink. Start your application server, and deploy this JAR to it. The contents of persistence.xml file is as shown below: oracle.toplink.essentials.PersistenceProvider spring-ejb Once your application is deployed, make sure you check the JNDI name of your session bean. In GlassFish, click on the JNDI Browsing toolbar button to view the JNDI names. Step 4: Test the Stateless Session beans. Since my session beans are published as web services, I can just easily test them using either the test page provided by GlassFish application server, or by using SoapUI and make sure that my Customer entity can be persisted using the CustomerService session bean. I am using the default test page provided by Glass Fish for web services: Step 5: Create a Spring Bean. Here, I define a simple CustomerManager interface, and an implementation class; just to show how things are wired using Spring. package com.spring.service; import com.ejb.domain.Customer; /** * * @author meerasubbarao */ public interface CustomerManager { public void addCustomer(Customer customer); public void removeCustomer(Long customerId); public Customer[] listCustomers(); } package com.spring.service; import com.ejb.domain.Customer; import com.ejb.service.CustomerService; /** * * @author meerasubbarao */ public class CustomerManagerImpl implements CustomerManager { CustomerService customerService; public void setCustomerService(CustomerService customerService) { this.customerService = customerService; } public void removeCustomer(Long customerId) { customerService.remove(customerId); } public Customer[] listCustomers() { return customerService.findAllAsArray(); } public void addCustomer(Customer customer) { customerService.create(customer); } } Step 6: Injecting the EJB 3.0 Session bean into our Spring Beans. As seen above, I am using setter injection to inject an instance of Customer Service and in turn invoke a method on the Stateless session bean. How do we inject an EJB into a Spring bean? It is quite simple as shown below in the Spring configuration file: The most important aspect here is the wiring of the EJB within the Spring configuration using the element in the jee schema. Next, we need to wire this with our Spring bean which is done as shown below: Step 7: Test How do we know that it works. Lets create a simple class and test. package com.spring.client; import com.ejb.domain.Customer; import com.spring.service.CustomerManager; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringAndEJBMain { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("SpringXMLConfig.xml"); CustomerManager service = (CustomerManager) context.getBean("manageCustomer"); Customer customer = new Customer(); customer.setFirstName("Meera"); customer.setLastName("Subbarao"); customer.setMiddleName("B"); customer.setEmailId("[email protected]"); customer.setCustomerId(new Long(1)); service.addCustomer(customer); for (Customer cust : service.listCustomers()) { System.out.println(cust.getFirstName()); System.out.println(cust.getLastName()); System.out.println(cust.getMiddleName()); System.out.println(cust.getEmailId()); } service.removeCustomer(new Long(1)); } } And here is the sample output from my IDE: We can go back to our GlassFish web services test page, and test the findAll method. It should have two entities. In this article, we saw how quick and easy it was to create JPA entities, persist them using Entity Manager from within our session bean. We also saw how easy it was to publish web services by adding a few annotations to our session beans. Next, we saw how to create a simple Spring bean, inject our session bean, and finally call methods on this session bean from our Spring application. Spring isn't in my opinion a replacement for EJB 3.0, you can mix and match EJB 3.0 and Spring 2.5 components to get the best of both.
August 27, 2008
by Meera Subbarao
· 76,067 Views
article thumbnail
Reverse-Engineer Source Code into UML Diagrams
This article shows how easy and simple it is to include UML diagrams within your Javadoc and also keep them updated with every change in the source code repository.
August 22, 2008
by Meera Subbarao
· 220,941 Views · 1 Like
article thumbnail
The Concept of Mocking
Explore the importance of mocking, including mock objects.
August 16, 2008
by Michael Minella
· 65,170 Views · 5 Likes
article thumbnail
Ant Build File Changes for Java Web Projects in NetBeans IDE 6.1
While working with a Java Web Application in NetBeans, I noticed some slight changes in the Ant build file for my project between NetBeans 6.0 and 6.1. This article explores some of the problems these changes caused to help out anyone with similar issues. I started with a Java Web Application that was created in NetBeans 6.0.1. After adding some JSP files and several Java source files, I committed everything in the project to my CVS repository. For some of my projects, I utilize the Hudson continuous integration build server. Using a standard deployment of Hudson, I configured the project to poll the SCM every 60 minutes, check out the code from CVS (if changes had been committed), and trigger the NetBeans project’s Ant build file (calling several specific targets like compile, dist, and so on. My builds have been functioning correctly for several weeks using this standard setup. I recently opened one of those projects in NetBeans 6.1 Beta and have been thoroughly enjoying the new features (faster startup, better JSP parsing in the Source Editor). After adding some JAR files as libraries and making several configuration changes, I committed the entire project (particularly the build-related files in the nbproject directory). Suddenly, my build for that project started failing. The console output reported by Hudson was : -init-check: BUILD FAILED D:/projects/hudson-server/data/jobs/MyWebProjectl/workspace/nbproject/build-impl.xml:149: The Java EE server classpath is not correctly set up. Your active server type is Tomcat55. Either open the project in the IDE and assign the server or setup the server classpath manually. For example like this: ant -Duser.properties.file= (where you put the property “j2ee.platform.classpath” in a .properties file) or ant -Dj2ee.platform.classpath= (where no properties file is used) Total time: 2 seconds finished: FAILURE I undid the configuration changes one by one, but the build failed regardless of what I reset. Apparently the property j2ee.platform.classpath is now required. I did a DIFF on the nbproject/build-impl.xml file and discovered several changes. The -init-check target includes property checks including this new one : The Java EE server classpath is not correctly set up. Your active server type is ${j2ee.server.type}.Either open the project in the IDE and assign the server or setup the server classpath manually.For example like this: ant -Duser.properties.file= (where you put the property “j2ee.platform.classpath” in a .properties file) or ant -Dj2ee.platform.classpath= (where no properties file is used) I hadn’t really taken notice of this property in the build file before, but it is referenced in a number of other targets such as: -init-macrodef-javac, -init-macrodef-junit, -init-macrodef-java, -init-macrodef-nbjpda, -init-macrodef-debug, compile-jsps, -do-compile-single-jsp, connect-debugger, javadoc-build, -do-compile-test, -do-compile-test-single Not being able to find a definition of the property anywhere in the build file, I looked through the project’s project.properties file among the list of defined properties. The property j2ee.platform.classpath was not defined. Thus, I’m assuming this is passed into the build file dynamically by NetBeans? In general I wouldn’t care, but when running the build file via Ant inside Hudson, the property j2ee.platform.classpath is never passed in. Hudson DOES allow you to pass properties and values to the build file, so I suppose I can specify the value manually, but I would like to keep the number of per project customizations to a minimum to maintain a low level of maintenance. Unless this causes some problem with the project properties in the build system, I would suggest the following fix for anyone who is experiencing a similar issue. Open your project’s project.properties file. Navigate to the section that contains these properties: j2ee.platform=1.4 j2ee.server.type=Tomcat55 Add a new line that specifies a blank j2ee.platform.classpath property such as this: j2ee.platform=1.4 j2ee.platform.classpath= j2ee.server.type=Tomcat55 Now, if the project.properties file is committed to CVS, a Hudson build can be triggered, and the FAIL check in the build-impl.xml file will pass. I ran some quick tests with the project, and everything with the project inside NetBeans still seems to work fine. I would propose to the NetBeans team to have the j2ee.platform.classpath property automatically added to the project.properties file.
March 26, 2008
by Adam Myatt
· 15,645 Views
article thumbnail
DJ NativeSwing - reloaded: JWebBrowser, JFlashPlayer, JVLCPlayer, JHTMLEditor.
Today's release of DJ Native Swing 0.9.4 greatly improves stability and brings new components: in addition to the JWebBrowser and JFlashPlayer, there is now the JVLCPlayer and the JHTMLEditor. Here is a summary of what to expect when using this library. 1. Various native components DJ Native Swing was designed to handle all the complexity of native integration, mainly in the form of components with a simple Swing-like API. Here are some screenshots of several components in action (click to enlarge): JWebBrowser: JFlashPlayer: JVLCPlayer: JHTMLEditor: 2. Simple API First, we need to initialize the framework. This needs to happen before any feature is used. A common place for this call is the first line of the main(): public static void main(String[] args) { NativeInterfaceHandler.init(); // Here goes the rest of the initialization. } Now, let's see how to create a JWebBrowser, with its URL set to Google's homepage: JWebBrowser webBrowser = new JWebBrowser(); webBrowser.setURL("http://www.google.com"); myContentPane.add(webBrowser); Note that we set a URL, but we could as well set the HTML text. The JWebBrowser also allows to execute Javascript calls, and we can even propagate notifications from custom pages to our Swing application. Moving to a more practical example, we may want to be notified of URL change events or track window opening events, potentially preventing navigation to occur or open the page elsewhere. This is easily achieved by attaching a listener: webBrowser.addWebBrowserListener(new WebBrowserAdapter() { public void urlChanging(WebBrowserNavigationEvent e) { String newURL = e.getNewURL(); if(newURL.startsWith("http://www.microsoft.com/")) { // Prevent the navigation to happen. e.consume(); } else { // We can consume the event and decide to open this page in a tab. } } public void windowWillOpen(WebBrowserWindowWillOpenEvent e) { // We can prevent, add the URL to a tab, etc. } // There are of course more events that can be received. }); Let's have a look at the JFlashPlayer: JFlashPlayer flashPlayer = new JFlashPlayer(); flashPlayer.setURL(myFlashURL); The JFlashPlayer can open local or remote Flash files, and files from the classpath; the latter being a general capability of the library by proxying files using a minimalistic web server. Of course, the JFlashPlayer allows to retrieve and set Flash variables, and play/pause/stop the execution. The JVLCPlayer and the JHTMLEditor are no exceptions to this simplicity: playlist can be manipulated in the VLC player, HTML can be set and retrieved from the HTML editor, etc. There is also the possibility to integrate Ole controls on Windows, still with a simple Swing-like API. An example is provided in the library in the form of an embedded Windows Media Player. 3. Advanced capabilities The library takes care of most common integration issues. This covers modal dialog handling, Z-ordering, heavyweight/lightweight mix (to a certain extent), invisible native components with regards to focus handling and threading. Here are some more screenshots, showing a lightweight/heavyweight mix, and Z-ordering capability: The demo application that is part of the distribution shows all the features along with the source code, so check it out! 4. Project info and technical notes Webstart demo: http://djproject.sourceforge.net/ns/DJNativeSwingDemo.jnlp Screenshots: http://djproject.sourceforge.net/ns/screenshots Native Swing: http://djproject.sourceforge.net/ns The DJ Project: http://djproject.sourceforge.net The 0.9.4 version has a completely new architecture. It still uses SWT under the hood, but it does not use the SWT_AWT bridge anymore. The JWebBrowser and browser-based components require XULRunner to be installed, except on Windows when using Internet Explorer. The JVLCPlayer requires VLC to be installed. The JHTMLEditor uses the FCKeditor. 5. Conclusions This project finally brings all that is needed to make Java on the desktop a reality. A web browser, a flash player, a multimedia player, and even an HTML editor. So, what next? Yes, what next? For that one, I am waiting for your feedback. So, what do you think? What are your comments and suggestions? -Christopher
March 12, 2008
by Christopher Deckers
· 54,546 Views
article thumbnail
Writing Unit Tests Using Groovy
Groovy can greatly decrease the level of work involved in creating unit tests for your Java code.
March 6, 2008
by Tomas Malmsten
· 57,141 Views
article thumbnail
SVNKit: Tame Subversion with Java!
SVNKitis an Open Source pure Java Subversion library. SVNKit literally brings Subversion, popular open source version control system, to the Java world. With SVNKit you can do the following: All standard Subversion operations: For instance, the following snipped checks out project from repository: File dstPath = new File("c:/svnkit"); SVNURL url = SVNURL. parseURIEncoded("http://svn.svnkit.com/repos/svnkit/branches/1.1.x/"); SVNClientManager cm = SVNClientManager.newInstance(); SVNUpdateClient uc = cm.getUpdateClient(); uc.doCheckout(url, dstPath, SVNRevision.UNDEFINED, SVNRevision.HEAD, true); Updates it to the latest revision: uc.doUpdate(dstPath, SVNRevision.HEAD, true); And finally commits local changes in "www" subdirectory if there are any: SVNCommitClient cc = cm.getCommitClient(); cc.doCommit(new File[] {new File(dstPath, "www")}, false, "message", false, true); SVNKit supports all standard Subversion operations and compatible with the latest version of Subversion. Access Subversion repository directly: Some applications will benefit from working with repository directly, without keeping working copy locally. Example below displays list of files in "www" directory. SVNURL url = SVNURL.parseURIEncoded("http://svn.svnkit.com/repos/svnkit/branches/1.1.x/"); SVNRepository repos = SVNRepositoryFactory.create(url); long headRevision = repos.getLatestRevision(); Collection entriesList = repos.getDir("www", headRevision, null, (Collection) null); for (Iterator entries = entriesList.iterator(); entries.hasNext();) { SVNDirEntry entry = (SVNDirEntry) entries.next(); System.out.println("entry: " + entry.getName()); System.out.println("last modified at revision: " + entry.getDate() + " by " + entry.getAuthor()); } Direct repository access API allows to perform operations like update, commit, diff and many other. Additionaly to the performance benefits of the direct access to repository, this API makes it possible to version arbitrary objects or object models within Subevrsion repository, not only files from the file system. Replace JNI Subversion bindings with SVNKit: Native Subversion provides Java interface that works with Subversion binaries through JNI. In case you already using it or would like to use as an option, you may also use SVNKit through exactly the same interface. This way you'll let your application dynamically switch between JNI and SVNKit implementation of the same API or let your application work on the platforms where there are no native Subversion binaries. For example: // pure Java implementation of the standard Subversion Java interface SVNClientInterface jniAPI = SVNClientImpl.newInstance(); byte[] contents = jniAPI.fileContent("http://svn.svnkit.com/repos/svnkit/branches/1.1.x/changelog.txt", Revision.HEAD); SVNKit is widely used in different applications, including IntelliJ IDEA, Eclipse Subversion integrations, SmartSVN, JDeveloper, bug tracking server side applications (e.g. Atlassian JIRA) and repository management and tracking tools (e.g. Atlassian FishEye) and many others. Where to get more information: Recently we've released SVNKit version 1.1.6 which is bugfix release. At http://svnkit.com/ you will find more information on that new version and, of course, downloads, documentation, source code example and articles explaining how to use SVNKit. In case of any questions you're welcome at our mailing list, or just contact us at [email protected] SVNKit is widely used in different applications, including IntelliJ IDEA, Eclipse Subversion integrations, SmartSVN, JDeveloper, bug tracking server side applications (e.g. Atlassian JIRA) and repository management and tracking tools (e.g. Atlassian FishEye) and many others. With best regards, TMate Software, http://svnkit.com/ - Java [Sub]Versioning Library!
February 26, 2008
by Alexander Kitaev
· 11,313 Views · 2 Likes
  • Previous
  • ...
  • 591
  • 592
  • 593
  • 594
  • 595
  • 596
  • Next
  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook
×