Hiển thị các bài đăng có nhãn Spring Framework. Hiển thị tất cả bài đăng
Hiển thị các bài đăng có nhãn Spring Framework. Hiển thị tất cả bài đăng

Thứ Bảy, 24 tháng 3, 2012

Software Development Posts of Interest - March 2012

This post references some of the recent blog posts and articles that have interested me. Topics include Java-specific topics such as Java EE, JavaFX, Scala, and Gradle as well as more general software development topics such as software patents and open source.

Why Software Patents are Evil

Simon Phipps summarizes in Why software patents are evil why patents in software may not make sense:

Patents may work in other industries, where the cost of innovation is so high that a temporary, state-sanctioned monopoly provides just enough time to gain a return on the investment. But that investment-return ratio has a completely different value for software. It turns out that software patents have little bearing on encouraging innovation. ... Software patents are ... bad news for most innovators in the software industry.

Phipps also looks at the relationship between software patents and open source software. He writes, "The problem is that open source software is defenseless against the anticompetitive abuse of patents."

Java EE 6 Versus Spring Framework

In the post Why is Java EE 6 better than Spring? Arun Gupta discusses why he believes developers should use Java EE 6 rather than the Spring Framework. Gupta begins the post by referencing several similar blog posts including Java EE wins over Spring and Why I will use Java EE (JEE, and not J2EE) instead of Spring in new Enterprise Java Projects in 2012.

Some of the feedback comments on this post are interesting because they demonstrate the differences of opinions between Java EE evangelists and Spring Framework evangelists (with comments from employees of both Oracle and SpringSource/VMWare among them). It is interesting to see the role reversal in this situation. Evangelists of the Spring Framework (even before it was so named) helped convince the Java enterprise development community of the problems with early J2EE, but now it seems the tables have turned and similar evangelism is advertising the "legacy" nature of Spring Framework as compared to modern Java EE.

Java EE 6 vs Spring - let's get ready to rumble provides another look at this post.

Oracle's Long-Term Intentions for Java

Paul Krill's Oracle lays out long-range Java intentions summarizes the "Oracle slide presentation entitled 'To Java SE 8 and Beyond!' posted on the QCon conference website." Based on Krill's summary, this presentation sounds very similar to the Oracle OpenWorld 2011 presentation From Java SE, 2012, to Java 12: Java SE Roadmap.

Reducing Memory Usage and Garbage Collections with -XX:+UseCompressedOops

Stuart Leneghan's post Reducing Java Memory Usage and Garbage Collections with the UseCompressedOops VM Option looks at the author's observation of the -XX:+UseCompressedOops HotSpot-specific JVM option "[reducing] the memory usage of the application by 14% and the number of garbage collections by 24%."

More on Java Tuning

Speaking of Java performance and memory tuning, Rupesh Ramachandran's post Java Tuning in a Nutshell - Part 1 provides a "JVM tuning cheat sheet" and categorizes JVM options into four categories: garbage collection, heap tuning, logging, and other performance.

The IBM DeveloperWorks article From Java code to Java heap is fairly comprehensive, providing background details on JVM memory handling and a focus on the impact of different Java collections on memory. This article also references the HotSpot option -XX:+UseCompressedOops as well as the similar IBM JVM option -Xcompressedrefs.

Understanding Garbage Collection is another recently-posted resource. This post is "the first of a series of 'Become a Java GC Expert' articles" and its focus is on introducing garbage collection in Java. The same site also hosts the blog post How to Analyze Java Thread Dumps. Figure Out Why Java is Eating CPU provides an interesting tip.

Scala

There continues to be a profusion of Scala posts. Recent posts include How Scala Can Improve Your Life, Is Scala making the right steps forward?, Scala creator Martin Odersky fends off critics of Scala's roadmap, Free online books for learning Scala, and Scala: Sink or Swim? Part 1. I have also seen new references to Twitter's Effective Scala.

Unit Testing

Neil Buesing's post How to Mock Final Classes in Unit Tests examines the problem that "both Mockito and EasyMock cannot mock classes (or methods) that are final." The feedback comments are also informative and discuss other available solutions to this issue: PowerMock), Groovy-based gMock, and JMockit.

Improved Java Stack Trace Presentation

Tomasz Nurkiewicz has posted two blog posts on how to improve Java stack trace experience using the Logback Project. Filtering irrelevant stack trace lines in logs demonstrates his "proof-of-concept" for filtering out selected stack trace frames using Logback and references the StackOverflow thread Cleaning noise out of Java stack traces. An older post, Logging exceptions root cause first, discusses a feature he contributed to Logback for displaying exceptions with root cause first rather than last.

A Peek at NetBeans 7.2

Geertjan Wielenga's NetBeans Java Hints: Quick & Dirty Guide provides a peek at a capability coming in NetBeans 7.2 for creating NetBeans hints.

Gradle

Last milestone for Gradle as it prepares for first major version cites the Gradle roadmap and states that the current version of Gradle ("1.0-milestone-9, released on 13th March 2012") "will be the final one" before Gradle goes into release candidate.

GroovyFX and JavaFX

Gradle is not the only product in the Groovy ecosystem with recent version advancement news. Dean Iverson has announced the GroovyFX First Official Release. He also shows how to use Grape to "grab" GroovyFX similar to the approach shown in my post Easy Groovy Logger Injection and Log Guarding.

Other interesting recent posts related to JavaFX include Example CSS Stylying in JavaFX, New in JavaFX 2.1: ComboBox, and Packaging JavaFX Applications as Native Installers.

Groovy and DevOps

In the post Groovy, A Reasonable JVM Language for DevOps, Geoffrey Papilion writes that Groovy provides the "JVM glue" he sought for "a simple JVM language that allows me to use any native object." After demonstrating use of Groovy for a "quick script to get data from JMX into ganglia fromSsolr," he concludes

So, if you're working in a Java with a bunch of Java apps, think about giving Groovy a chance for writing some of your monitoring tests, and metric collectors. It is a simpler language than Java to put together those little applications that can tell you how your system is performing, and well within the reach of your average DevOps engineer.
DNS for Software Developers

Doug Rathbone's post DevOps DNS for Developers – Now There’s No Excuse Not To Know is intended to help software developers become more familiar with the basics of DNS. This does seem like the sort of article one would except to be associated with the DevOps movement.

The Big Three JVM Languages

The Big Three – Scala, Clojure and Groovy is a blog post with observations about Groovy, Scala, and Clojure seeming to be the most popular JVM languages among Java developers based on two polls (Which alternate JVM language do you prefer? and Which JVM Language Is On Top?). Charles Oliver Nutter has added a feedback comment regarding JRuby being a more popular JVM language when you consider Ruby developers.

Java 7 WatchService

The post What’s New in Java 7: WatchService describes java.nio.file.WatchService and calls the related functionality "one of the more interesting ... new features in Java 7." This is a fairly concise post that quickly introduces the functionality and includes sample code.

Opinions on Rails, Hibernate, Google, JSON's License Agreement, and the Spanish Theory of Management

I started this post with reference to an opinion-oriented post on open source and patents. It seems symmetrically pleasing to close this post with references to other opinion-oriented pieces. Tyler Menezes discusses technical and cultural reasons he won't use Ruby on Rails in the simply titled post I will not learn Rails. James Whittaker provides a articulate and insightful post Why I left Google.

Rob Gordon is "not impressed" with Hibernate 4.1 ease of use. The Dodgy Coder blog ("Never trust a programmer in a suit") includes a post on the "Spanish Theory" of project management.

Brian Fox points out that JSON's license agreement states "The Software shall be used for Good, not Evil." Fox further points out that "compliance is impossible" and that "this isn't even open source." He asserts that "this additional clause adds an unnecessary complication" and I tend to agree. The folks in suits are not comfortable with objective statements in the license agreements.

Conclusion

I have summarized and linked to Java-specific and general software development posts of interest in this blog post. The software development industry continues to be ever-changing and full of news.

Thứ Hai, 8 tháng 12, 2008

Flex's Increasing Circle of Friends: SpringSource

Many of us have discovered the benefits of using Flex for rich client side applications in conjunction with enterprise Java on the server side. The Flex/Java EE combination brings the best of both worlds to the developer seeking rich clients with robust enterprise strength back-ends.

While Flex and Enterprise Java go very well together, Flex is also used with a myriad of other languages. Some advertised efforts related to various languages and frameworks making special effort to work even better with Flex include PHP (Zend - "Zend to Collaborate with Adobe", 16 September 2008), Ruboss (22 May 2008), Ruby on Rails (Flexible Rails), Python, C++, and .NET ("Adobe Flex Reaches Out to .NET Developers", 17 November 2008).

In the Flex+Java world alone, there are many alternatives as well. While HTTPService and WebService make Flex useful with virtually any modern language, Flex (either directly or via its community) has a wide range of Java-specific goodies as well. These include BlazeDS (including support for Spring+Flex, JMS, and Java object remoting), and GraniteDS (specific support for Enterprise JavaBeans 3, the Spring Framework, Seam, and Guice).

Now, we have an announcement that SpringSource will be collaborating with Adobe to deliver Spring BlazeDS Integration. SpringSource will also be releasing an adapter for LiveCycle Data Services ES. With the established pervasiveness of the Spring Framework in the Java EE community and the rapidly growing popularity of Flex in the Java EE community, this announcement was really not much of a surprise and makes a lot of sense. Other articles covering this announcement can be found here, here (extra details), here, here, here (details on what Spring BlazeDS Integration offers above today's Flex+Spring options), and here.

Flex continues to be used with an ever increasing variety of back-end technologies. However, for those of us who still primarily develop our enterprise applications with Java EE and Spring, today's announcement is very good news.

Thứ Hai, 27 tháng 10, 2008

Logging Method Entry/Exit with Spring/AspectJ

The purpose of this blog entry is to show an extremely simple of example of "logging" entry into and exit from methods using the Spring Framework and AspectJ. The example is so simple that I won't actually use log4j or java.util.logging for the actual logging, although they could be easily added.

The first code listing shows the XML file for the Spring context. The majority of this file is devoted to setting up the Spring/AspectJ/AOP configuration. The terms included in the comments of this file that identify aspect-oriented programming (AOP) concepts are defined in Introduction to Aspect-Oriented Programming.


spring-aop-logging-context.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

<!-- Normal Spring-exposed bean. -->
<bean id="exampleBean"
class="dustin.spring.aopexamples.ExampleBeanClass">
<constructor-arg value="A Logging Example" />
<constructor-arg value="1.0" />
</bean>

<!-- The Aspect itself. -->
<bean id="exampleLoggingAspect"
class="dustin.spring.aopexamples.LoggingAspect" />

<aop:config>

<!-- The Pointcut(s). -->
<aop:pointcut id="loggingPointcut"
expression="within(dustin.spring.aopexamples.ExampleBeanClass)" />

<!-- The Advice(s). -->
<aop:aspect id="loggingAspect" ref="exampleLoggingAspect">
<aop:before pointcut-ref="loggingPointcut" method="logEntry" />
<aop:after pointcut-ref="loggingPointcut" method="logExit" />
<aop:after-returning pointcut-ref="loggingPointcut"
method="logExitAfterReturn" />
</aop:aspect>

</aop:config>

</beans>



With the Spring configuration (including AOP support for logging) defined, the main class that instantiates the Spring context based on this XML file is shown next. This class doesn't do much other than instantiating the Spring container and using System.out to output the information returned from an example bean class. However, this is enough to demonstrate how the method entry and exit from each method in that example bean class is logged above and beyond what is obvious in the code.


Main.java


package dustin.spring.aopexamples;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* Demonstrate Spring/AspectJ-based logging.
*
* @author Dustin
*/
public class Main
{
/**
* Print out the contents of the provided ExampleBeanClass.
*
* @param example Object whose contents should be printed out.
*/
public static void printContentsOfExample(final ExampleBeanClass example)
{
System.out.println(
"\n\n=============================================================");
System.out.println(" Dustin's Software Cogitations and Speculations");
System.out.println(
"=============================================================");
System.out.println( "Name: " + example.getExampleName() );
System.out.println( "Version: " + example.getExampleVersion() );
System.out.println( "Name (Version): " + example.provideNameAndVersion() );
System.out.println(
"=============================================================\n\n");
}

/**
* Demonstrate logging via Spring AspectJ support.
*
* @param args the command line arguments
*/
public static void main(String[] args)
{
final ConfigurableApplicationContext context =
new ClassPathXmlApplicationContext(
"dustin\\spring\\aopexamples\\spring-aop-logging-context.xml");
final ExampleBeanClass example =
(ExampleBeanClass) context.getBean("exampleBean");
printContentsOfExample(example);
context.close();
}
}



The next class I'll define here is the Aspect class that contains the code that I am going to want to run on top of (above and beyond) the code that is executed normally. Here is that class.


LoggingAspect.java


package dustin.spring.aopexamples;

import org.aspectj.lang.JoinPoint;

/**
* Aspect class for the Spring/AspectJ Logging example shown in the blog
* Dustin's Software Development Cogitations and Speculations.
*
* @author Dustin
*/
public class LoggingAspect
{
/**
* Log method entry.
*
* @param joinPoint
*/
public void logEntry(final JoinPoint joinPoint)
{
log("Entering method " + joinPoint.getSignature().getName() + "...");
}

/**
* Log method exit.
*
* @param joinPoint
*/
public void logExit(final JoinPoint joinPoint)
{
log("Exiting method " + joinPoint.getSignature().getName() + ".");
}

/**
* Log method exit after returning.
*
* @param joinPoint
*/
public void logExitAfterReturn(final JoinPoint joinPoint)
{
log( "Exiting method (after return) "
+ joinPoint.getSignature().getName() + ".");
}

/**
* "Log" the provided String.
*
* @param messageToLog String to be logged.
*/
public static void log(final String messageToLog)
{
System.err.println(messageToLog);
}
}



We now have Spring context (including logging AOP support) configuration created along with a main class that instantiates that context and a class that will serve as our logging aspect. Last, but certainly not least, we need the actual class whose methods' entry and exit will be intercepted and have the additional code specified in the Aspect applied to them. Here is that example class. Note that it is a POJO with no specific reference to Spring or to AOP or to AspectJ.


ExampleBeanClass.java


package dustin.spring.aopexamples;

/**
* An example bean class meant to be used with Spring and AspectJ to demonstrate
* AOP-based logging. This is used for a blog entry in Dustin's Software
* Development Cogitations and Speculations.
*
* @author Dustin
*/
public class ExampleBeanClass
{
/**
* The name of the example.
*/
private String exampleName;

/**
* The version of the example.
*/
private String exampleVersion;

/**
* No-arguments constructor.
*/
public ExampleBeanClass() {}

/**
* Constructor accepting arguments to set my state.
*
* @param newExampleName Name of this example.
* @param newExampleVersion Version of this example.
*/
public ExampleBeanClass(
final String newExampleName, final String newExampleVersion)
{
this.exampleName = newExampleName;
this.exampleVersion = newExampleVersion;
}

/**
* Provide my example name.
*
* @return My example name.
*/
public String getExampleName()
{
return exampleName;
}

/**
* Set/change my example name.
*
* @param exampleName New name for this example.
*/
public void setExampleName(String exampleName)
{
this.exampleName = exampleName;
}

/**
* Provide my example version.
*
* @return My example version.
*/
public String getExampleVersion()
{
return exampleVersion;
}

/**
* Set/change the example's version.
*
* @param exampleVersion New value for my version.
*/
public void setExampleVersion(String exampleVersion)
{
this.exampleVersion = exampleVersion;
}

/**
* Provide my example name with version in parentheses.
*
* @return My name and version if format "Name (Version)."
*/
public String provideNameAndVersion()
{
return this.exampleName + " (" + this.exampleVersion + ")";
}
}



The class above, ExampleBeanClass, has no methods for writing output to the standard output stream. The Main class that calls this via Spring does have some standard output calls to output the contents of this class, but we will see additional logged messages when we run the application because the AOP portion of this will add method entry, method exit, and method exit after return log statements for each method invoked on the ExampleBeanClass. It is the Spring XML at the beginning of this blog entry that ties all of these together.

Here is what the output (focus on middle section) looks like when run with the appropriate libraries (CGLIB, Spring Framework, AspectJ, etc.) on the classpath (all available with Spring with Dependencies download).



The order of output of the "normally expected" output statements as compared to the order of the output of the "logging" statements made via Spring's AOP support is interesting to observe. As one might expect, "before" comes before "after" which comes before "after returning", but all are part of the methods' entry and exit and so all come before a third class can print the output of the returned Strings.

As this blog entry has demonstrated, it is very easy to apply aspect-oriented programming techniques to Java applications with Spring and Spring's AOP support.

Thứ Hai, 22 tháng 9, 2008

Thoughts on SpringSource's Enterprise Maintenance Policy

UPDATE (11 October 2008): SpringSource has tweaked the policy described below to a significant enough extent that I believe it the altered new policy will be palatable to the vast majority of developers using the Spring Framework. More information on this is available in SpringSource Regains Footing with Support Change and A Question of Balance: Tuning the Maintenance Policy.




The recent mini controversy surrounding SpringSource's Enterprise Maintenance Policy announcement provides interesting material for a look at how different people view open source differently. I have talked with professional software developers who still equate "open source" with "free software" rather than recognizing the classic differentiation between "free speech" and "free beer." In fact, I used to be one of these individuals until I attended multiple editions of the Colorado Software Summit in the early 2000s in which Simon Phipps explained each year different ways of looking at what it means to be open source and to be part of an open source community.

The Spring Framework has become wildly successful and widely adopted. There has been some discussion regarding how much "community" participation there is in Spring versus SpringSource direct involvement with Spring. In this blog entry, I intend to examine competing arguments that have been or might be made in this controversy. I can understand the motivations of the principals of both sides of the argument and I want to look at the issue from both points of view. I also intend to look at some possible results of this SpringSource announcement.

This recent announcement by SpringSource and the reactions to the announcement have caused me to reflect on my own participation in the Spring community. I think in may ways I may be representative of the "typical" Spring "community" member. I have never contributed a line of code to Spring and have not even written up a defect or enhancement request (JIRA). However, I feel like I have at least contributed a little to the Spring community by writing an article on Spring for Oracle Technology Network called Add Some Spring to Your Oracle JDBC Access (November 2005) and blogging on Spring occasionally. In addition, as some have stated in their feedback to the recent announcement, I have purchased Spring-related books and told colleagues about Spring. However, these are, in some respects, indirect support rather than direct contributions to the framework itself.

There is no question that we become accustomed to getting what we have regularly received in the past and do not like to hear that this freely given benefit will be removed or have some cost applied to it. For example, when an employer takes away a benefit we have received in the past, few employees will "welcome" that. From this very human perspective, it is natural to not "welcome" the news that SpringSource will not be publishing releases of the Spring Framework to non-Enterprise users after a major release has been out for three months. After all, if I have been enjoying the benefits of polished releases of software for years, why would I welcome extra work on my part or a subscription fee to continue to receive that same benefit?

My understanding is that bug fixes will continue to be available in the repository trunk, but that they will no longer be available in a binary form after the 3-month period following each major release. For many organizations that use Spring, this is a minor new hindrance to using the framework, but probably not enough of a hindrance to stop using the framework altogether unless something else is available for which the benefit-to-cost ratio seems better.

While the Spring Framework's popularity has grown tremendously, there are a growing number of popular alternatives. For example, Java EE 5 (including EJB3) has borrowed heavily from Spring and, in my opinion, is a now a reasonable alternative. Many of the issues that drove developers from EJB 2.x to Spring have now been resolved. There are also other non-standard but popular frameworks like Google's Guice that are available. What developers need to ask themselves is if the added cost of using Spring from here on out (either the cost of the enterprise support or the cost of building Spring releases) is still worth the benefits of using Spring and if the ratio of these benefits to the costs is still better than the ratio of using an alternative to the cost of using that alternative. For example, a developer may choose to use the simplified Java EE 5 on future projects because the extra effort associated with Java EE is so significantly reduced and the ability to write standard code regardless of providers is a desirable advantage. In fact, with a product like GlassFish, that developer can have an open source and standard Java EE 5 implementation.

Developers will likely have some options between becoming SpringSource Enterprise subscribers and ditching Spring altogether for an alternative. Many major vendors already use Spring in their products. As long as these vendors of IDEs (such as NetBeans 6.1 support and Spring Extension for JDeveloper), application servers (such as WebLogic and Oracle Containers for Java EE), other frameworks (such as AppFuse), and other products continue releasing their Spring-based and Spring-supporting products with new versions of Spring, some of the bug fixes and updates may become available to end-user developers via these third-party products. There is always the possibility that these third-party products could drop support for Spring due to this announcement, but the announcement does not seem onerous enough to me to cause that to happen. Finally, there has already been talk of starting a community effort to fill in the relatively small gap being left by this SpringSource announcement. This proposed project would, in theory, be able to take the source code on the publicly exposed repository and build it into a finished distributable like SpringSource does today. There has even been talk of a complete fork off of Spring.

Some developers are feeling trapped. They have tied their products heavily to Spring and so it is not as easy as simply switching to an alternative. Ironically, Spring creator Rod Johnson pointed out in the excellent book J2EE Design and Development that good design includes isolating non-standard and changeable code from standard and stable code. If developers followed this advice with Spring (and in many ways Spring does encourage this isolation), then the migration would be easier than it would have been from proprietary libraries or other third-party frameworks. Even so, the question to ask if if the new cost of using Spring (three year subscription or building Spring on one's own) is enough to justify the certain cost associated with switching to an alternative.

For some larger organizations, this actually might be welcome news because there are still large corporations that prefer professional support. Some clients and some organizations have been reluctant to use any open source products that did not have professional support. They are likely to already be using Spring's Enterprise support and so this won't impact them. Others may have not chosen this option, but do not mind paying the subscription fee and consider it a relatively small cost.

In his blog entry Open Source, Open Strategy: The SpringSource Manifesto, Rod Johnson covers the history of SpringSource (including its days as Interface21) and outlines reasoning behind using a different license for some of the newer products released by SpringSource. He makes valid points such as the fact that many companies sell products using the Spring Framework for significant portions of their functionality. An important and highlighted note in this blog entry is this statement: "We are not changing and will not change the license of any existing project." He goes on to add that this includes the Spring Framework and Spring Security. I think this is significant. The recent Enterprise Maintenance announcement is less of a blow if existing and future Spring Framework code remains open source under the Apache license.

Some have charged that SpringSource is only making this change in support because of their wide adoption and the dependencies people have on the framework. It seems that it is obvious that a move like this is much more likely to be successful after a framework has been evangelized and adopted rather than in its infancy, so I don't think any of us should be too surprised. SpringSource certainly does have some leverage right now and it is certainly greater than it would have been a number of years ago. In fact, in the blog entry Pumping It Dry: $200 a Barrel and $25,000 per CPU, Rod Johnson points out similar tactics in terms of revenue raising implemented by Oracle after their acquiring BEA.

My biggest concern about the recent SpringSource announcement is not the content of the announcement itself. With the assertion in the summer blog about the license for Spring Framework not changing and with Rod Johnson's assertion at TheServerSide's New Spring Maintenance Policy that "SpringSource continues to expose our open source code", I do not see any reason for immediate panic or knee-jerk reactions. Instead, my much bigger concern is worry that this might only be the first in a long series of steps that make Spring less attractive. It will definitely enter my mind when trying to decide how dependent on Spring I want my application to be. In other words, I may choose to use options where I don't need to implement a Spring interface.

It seems obvious that this decision was made to increase SpringSource revenues. I understand that and empathize with the talented individuals who have sacrificed to make Spring what it is today. They definitely deserve some payback for the sacrifice. Making money on open source development is a tricky business model and it is not surprising that it occasionally needs tweaking. That being said, what happens if this move is not enough to garner that payback? Will the license be changed in the future for new versions/releases or will more other much more drastic measures be taken to gain the desired revenue? I like to think that won't happen, but the recent announcement at least reminds one of that possibility.

The long-term implications of this announcement are interesting to ponder. The blog entry SpringSource Will Charge for Updates to Spring, What Comes Next? provides some possible next steps that SpringSource might take in this same direction. While that blog entry focuses on what SpringSource may do, I also wonder how the community will evolve as a result of this announcement.

The following are some questions whose answers we will likely not know for certain until some time has played out.

* Will there be a dramatic decrease in the number of developers and projects using SpringSource products (especially the Spring Framework)?

* Will there be fewer blog entries, articles, and other coverage of Spring Framework due to this policy change?

* Will the developers that stop using Spring be missed by SpringSource if they weren't providing any type of direct monetary benefit to SpringSource?

* Will the developers that stop using Spring be missed by the community if they weren't contributing directly or indirectly to the community?

* What percentage of the developers that stop using Spring or reduce their usage of Spring will be contributors who have performed useful testing and bug and enhancement reporting?

* Will the new policy allow SpringSource to retain and acquire the necessary talent and resources to make the products better for users?

* Will this announcement be the beginning of a bright new era or the beginning of the end of Spring's rapidly growing dominance?

I won't be surprised if this new policy is the subject of some hallway discussion and even some Q&A discussion at the Colorado Software Summit 2008 that occurs four weeks from now. With Matt Raible speaking on What's Coming in Spring 3.0, with Chris Richardson (author of POJOs in Action) speaking, and with a SpringSource employee (Filip Hanik) presenting, it seems likely this will come up.

No product is perfect and the Spring Framework is no different. However, many enterprise Java developers have found it to be extremely useful and helpful and a welcome release from the complications of EJB 2.x. When evaluating a product, I like to look at the entire package including all advantages and disadvantages. The Spring Enterprise Management policy should be considered along with Spring's advantages and disadvantages when deciding whether or not to use Spring. For some, it may be an advantage, for some it may be considered a significant disadvantage, and for many of us it will probably only be a minor disadvantage. The more interesting questions involve the effect it will have on Spring, on the Spring community, and if it is just the first of additional and even more dramatic steps in this direction.

Thứ Bảy, 26 tháng 7, 2008

JMX Model MBeans with Spring Framework

In the creatively named blog entry The JMX Model MBean, I demonstrated with a simple example how the JMX Model MBean enables greater descriptive ability than is available with other JMX MBean types. The simple example also demonstrated that a Model MBean can be applied to an existing class with no knowledge of JMX and without any awareness that it is being exposed via a JMX management and monitoring interface. The one major drawback of Model MBeans that even this simple example demonstrated is the tedious and verbose code needed to build a Model MBean without aid of other tools or frameworks.

In that blog entry, I called out some approaches that can aid in the development of Model MBeans. These include Spring Framework’s JMX support, The Apache Commons Modeler approach, JBoss’s XMBeans, and the use of reflection. In this current blog entry, I will delve into Spring Framework’s support for Model MBeans in greater detail and demonstrate how easy Spring makes it to apply JMX Model MBeans.

By default, Spring’s support for JMX relies upon Model MBeans (though the developer has no need to deal with Model MBeans directly). The reason for this seems clear – the Model MBean allows normal Java classes with no JMX knowledge or awareness to be exposed via a JMX interface. This approach fits Spring’s behavior in other areas. In other words, it seems to be "the Spring way" to use plain Java classes with little or no knowledge of their surroundings and then "wire" them up to their surroundings via external configuration. In this blog entry, I’ll demonstrate how Spring enables Java classes with absolutely no Spring or JMX awareness to be exposed via a JMX interface and how just a little tinkering with the plain Java class via annotations enables the full descriptive power of Model MBeans to be deployed.

Although the JMX Specification (Chapter 4) talks about other potentially useful features of the Model MBean (such as persistence described in section 4.3.4), the two options of the ModelMBean that I most often take advantage of are the Model MBean’s descriptive support and the ability of the Model MBean to expose a non-JMX class in a JMX agent. In Spring, it is almost trivial to obtain this first benefit and expose a class with no awareness of JMX (or even of Spring) as a manageable and monitorable resource. In fact, the "code" needed to do this lies completely in Spring configuration. The following Java code listing contains the class (SimpleCalculator) that has no JMX awareness, but will be exposed via Spring as JMX-accessible. The XML code listing following SimpleCalculator.java shows how Spring is instructed to expose SimpleCalculator as a JMX-accessible resource.

SimpleCalculator.java


package dustin.jmx.modelmbeans;

/**
* Simple calculator class intended to demonstrate how a class with no knowledge
* of JMX or management can be "wrapped" with ModelMBeans.
*
* @author Dustin
*/
public class SimpleCalculator implements SimpleCalculatorIf
{
/**
* Calculate the sum of the augend and the addend.
*
* @param augend First integer to be added.
* @param addend Second integer to be added.
* @return Sum of augend and addend.
*/
public int add(final int augend, final int addend)
{
return augend + addend;
}

/**
* Calculate the difference between the minuend and subtrahend.
*
* @param minuend Minuend in subtraction operation.
* @param subtrahend Subtrahend in subtraction operation.
* @return Difference of minuend and subtrahend.
*/
public int subtract(final int minuend, final int subtrahend)
{
return minuend - subtrahend;
}

/**
* Calculate the product of the two provided factors.
*
* @param factor1 First integer factor.
* @param factor2 Second integer factor.
* @return Product of provided factors.
*/
public int multiply(final int factor1, final int factor2)
{
return factor1 * factor2;
}

/**
* Calculate the quotient of the dividend divided by the divisor.
*
* @param dividend Integer dividend.
* @param divisor Integer divisor.
* @return Quotient of dividend divided by divisor.
*/
public double divide(final int dividend, final int divisor)
{
return dividend / divisor;
}
}


spring-mbean-simple-context.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<bean id="exposedModelMBean"
class="dustin.jmx.modelmbeans.SimpleCalculator" />

<util:map id="exposedMBeans">
<entry key="modelmbean:type=spring-simple" value-ref="exposedModelMBean" />
</util:map>

<bean class="org.springframework.jmx.export.MBeanExporter"
p:beans-ref="exposedMBeans"
p:assembler-ref="assembler" />

<util:list id="manageableInterfaces">
<value>dustin.jmx.modelmbeans.SimpleCalculatorIf</value>
</util:list>

<bean id="assembler"
class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler"
p:managedInterfaces-ref="manageableInterfaces" />

</beans>



The SimpleCalculator class shown above is essentially the same class used in my previous blog entry on Model MBeans done without benefit of Spring. This is far less code than needed in my example of employing Model MBeans without the Spring Framework, but the one disadvantage is that the greater descriptive ability of the Model MBean is not enjoyed in this simple example. This is demonstrated in the following three screen snapshots of JConsole viewing this simple Spring-exposed Model MBean.








The Spring Framework provides a mechanism to provide greater descriptive information to our Spring-exposed Model MBeans. This is done via Spring-specific annotations. The downside of this approach is that the otherwise JMX-unaware and Spring-unaware classes now dependent on Spring-specific JMX-related annotations. However, the benefit of this is great descriptive ability with relative coding ease. The next code listing shows the adapted SimpleCalculatorAnnotated class that is the same class as SimpleCalculator, but with the Spring JMX annotations. The XML needed to configure this class to be exposed via Spring is then shown as well.

SpringCalculatorAnnotated.java


package dustin.jmx.modelmbeans;

import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedOperationParameter;
import org.springframework.jmx.export.annotation.ManagedOperationParameters;
import org.springframework.jmx.export.annotation.ManagedResource;

/**
* Simple calculator class annotated with Spring JMX annotations to demonstrate
* using Spring JMX metadata approach. This class uses J2SE 5 annotations, but
* Spring also supports use of Apache Commons Attributes for metadata specification.
*
* @author Dustin
*/
@ManagedResource(
objectName="modelmbean:type=spring-annotated",
description="A simple integer calculator." )
public class SimpleCalculatorAnnotated implements SimpleCalculatorIf
{
/**
* Calculate the sum of the augend and the addend.
*
* @param augend First integer to be added.
* @param addend Second integer to be added.
* @return Sum of augend and addend.
*/
@ManagedOperation(description="Integer Addition")
@ManagedOperationParameters({
@ManagedOperationParameter(
name="augend",
description="The first parameter in the addition (augend)."),
@ManagedOperationParameter(
name="addend",
description="The second parameter in the addition (addend).")})
public int add(final int augend, final int addend)
{
return augend + addend;
}

/**
* Calculate the difference between the minuend and subtrahend.
*
* @param minuend Minuend in subtraction operation.
* @param subtrahend Subtrahend in subtraction operation.
* @return Difference of minuend and subtrahend.
*/
@ManagedOperation(description="Integer Subtraction")
@ManagedOperationParameters({
@ManagedOperationParameter(
name="minuend",
description="The first parameter in the substraction (minuend)."),
@ManagedOperationParameter(
name="subtrahend",
description="The second parameter in the subtraction (subtrahend).")})
public int subtract(final int minuend, final int subtrahend)
{
return minuend - subtrahend;
}

/**
* Calculate the product of the two provided factors.
*
* @param factor1 First integer factor.
* @param factor2 Second integer factor.
* @return Product of provided factors.
*/
@ManagedOperation(description="Integer Multiplication")
@ManagedOperationParameters({
@ManagedOperationParameter(
name="factor1",
description="The first factor in the multiplication."),
@ManagedOperationParameter(
name="factor2",
description="The second factor in the multiplication.")})
public int multiply(final int factor1, final int factor2)
{
return factor1 * factor2;
}

/**
* Calculate the quotient of the dividend divided by the divisor.
*
* @param dividend Integer dividend.
* @param divisor Integer divisor.
* @return Quotient of dividend divided by divisor.
*/
@ManagedOperation(description="Integer Division")
@ManagedOperationParameters({
@ManagedOperationParameter(
name="dividend",
description="The dividend in the division."),
@ManagedOperationParameter(
name="divisor",
description="The divisor in the division.")})
public double divide(final int dividend, final int divisor)
{
return dividend / divisor;
}
}


spring-mbean-metadata-context.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<bean id="exposedModelMBean"
class="dustin.jmx.modelmbeans.SimpleCalculatorAnnotated" />

<bean id="exporter"
class="org.springframework.jmx.export.MBeanExporter"
p:autodetect="true"
p:assembler-ref="assembler"
p:namingStrategy-ref="namingStrategy" />

<bean id="namingStrategy"
class="org.springframework.jmx.export.naming.MetadataNamingStrategy"
p:attributeSource-ref="attributeSource" />

<bean id="attributeSource"
class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource" />

<bean id="assembler"
class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler"
p:attributeSource-ref="attributeSource" />

</beans>


The next three screen snapshots show via screen captures of JConsole how the Spring annotations have allowed the annotated class to provide greater descriptive details to the JMX client. The annotations are far less verbose and are arguably easier to write and maintain than the code I showed in the Model MBean blog entry in which I did not use Spring.







If it is overly burdensome or undesirable to add these annotations to the source class, one can "wrap" the source class with a class that has these annotations. An example of this is shown next. The SimpleCalculatorWrapper class "wraps" the SimpleCalculator class. In this approach, SimpleCalculatorWrapper must know about Spring and Spring’s JMX annotations, but the original SimpleCalculator does not need to be specific to Spring or to JMX.

SimpleCalculatorWrapper


package dustin.jmx.modelmbeans;

import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedOperationParameter;
import org.springframework.jmx.export.annotation.ManagedOperationParameters;
import org.springframework.jmx.export.annotation.ManagedResource;

/**
* "Wraps" a SimpleCalculator class so that this wrapper class can be annotated
* with Spring JMX annotations rather than needing to modify the business logic
* Simple Calculator class.
*/
@ManagedResource(
objectName="modelmbean:type=spring-wrapper",
description="A simple integer calculator." )
public class SimpleCalculatorWrapper implements SimpleCalculatorIf
{
private SimpleCalculator simpleCalculator;

/**
* Setter method to set the object that I "wrap."
*
* @param calculator SimpleCalculator that I should wrap.
*/
public void setWrappedObject(final SimpleCalculator calculator)
{
this.simpleCalculator = calculator;
}

/**
* Calculate the sum of the augend and the addend.
*
* @param augend First integer to be added.
* @param addend Second integer to be added.
* @return Sum of augend and addend.
*/
@ManagedOperation(description="Integer Addition")
@ManagedOperationParameters({
@ManagedOperationParameter(
name="augend",
description="The first parameter in the addition (augend)."),
@ManagedOperationParameter(
name="addend",
description="The second parameter in the addition (addend).")})
public int add(int augend, int addend)
{
return simpleCalculator.add(augend, addend);
}

/**
* Calculate the difference between the minuend and subtrahend.
*
* @param minuend Minuend in subtraction operation.
* @param subtrahend Subtrahend in subtraction operation.
* @return Difference of minuend and subtrahend.
*/
@ManagedOperation(description="Integer Subtraction")
@ManagedOperationParameters({
@ManagedOperationParameter(
name="minuend",
description="The first parameter in the substraction (minuend)."),
@ManagedOperationParameter(
name="subtrahend",
description="The second parameter in the subtraction (subtrahend).")})
public int subtract(int minuend, int subtrahend)
{
return simpleCalculator.subtract(minuend, subtrahend);
}

/**
* Calculate the product of the two provided factors.
*
* @param factor1 First integer factor.
* @param factor2 Second integer factor.
* @return Product of provided factors.
*/
@ManagedOperation(description="Integer Multiplication")
@ManagedOperationParameters({
@ManagedOperationParameter(
name="factor1",
description="The first factor in the multiplication."),
@ManagedOperationParameter(
name="factor2",
description="The second factor in the multiplication.")})
public int multiply(int factor1, int factor2)
{
return simpleCalculator.multiply(factor1, factor2);
}

/**
* Calculate the quotient of the dividend divided by the divisor.
*
* @param dividend Integer dividend.
* @param divisor Integer divisor.
* @return Quotient of dividend divided by divisor.
*/
@ManagedOperation(description="Integer Division")
@ManagedOperationParameters({
@ManagedOperationParameter(
name="dividend",
description="The dividend in the division."),
@ManagedOperationParameter(
name="divisor",
description="The divisor in the division.")})
public double divide(int dividend, int divisor)
{
return simpleCalculator.divide(dividend, divisor);
}
}


spring-mbean-wrapper-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<bean id="wrappedClass"
class="dustin.jmx.modelmbeans.SimpleCalculator" />

<bean id="exposedModelMBean"
class="dustin.jmx.modelmbeans.SimpleCalculatorWrapper"
p:wrappedObject-ref="wrappedClass" />

<bean id="exporter"
class="org.springframework.jmx.export.MBeanExporter"
p:autodetect="true"
p:assembler-ref="assembler"
p:namingStrategy-ref="namingStrategy" />

<bean id="namingStrategy"
class="org.springframework.jmx.export.naming.MetadataNamingStrategy"
p:attributeSource-ref="attributeSource" />

<bean id="attributeSource"
class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource" />

<bean id="assembler"
class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler"
p:attributeSource-ref="attributeSource" />

</beans>


I won’t show the JConsole view of the wrapper because it appears nearly the same as what was shown for the directly annotated class. The only difference is that the original SimpleCalculator is left untouched by Spring-specific JMX annotations because the wrapper class shields these details from the SimpleCalculator class.

In the annotations examples above, I used the standard Java SE type annotations to provide the JMX Model MBean metadata. Spring also supports using Apache Commons Attributes for this. The Spring approach of specifying JMX ModelMBean metadata via annotations has proven so popular that it now sounds like JMX 2 is very likely to include similar, or at least Spring-inspired, annotation support. The obvious benefit of this would be the ability to enjoy highly descriptive Model MBeans without all the code even when not using Spring.

For completeness, I am including the main Java class that instantiated my three Spring-related examples above: SimpleCalculator without annotations, SimpleCalculator with annotations, and a "wrapped" SimpleCalculator.


package dustin.jmx.modelmbeans;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


/**
* The purpose of this class is to demonstrate use of ModelMBeans with Spring.
*/
public class SpringModelMBeanDemonstrator
{
/**
* Pause for the specified number of milliseconds.
*
* @param millisecondsToPause Milliseconds to pause execution.
*/
public static void pause(final int millisecondsToPause)
{
try
{
Thread.sleep(millisecondsToPause);
}
catch (InterruptedException threadAwakened)
{
System.err.println("Don't wake me up!\n" + threadAwakened.getMessage());
}
}

public static void main(final String[] arguments)
{
String option;
if ( arguments.length < 1 )
{
option = "simple";
}
else
{
option = arguments[0].toLowerCase();
}

ApplicationContext context;
// assume simple example unless metadata or wrapper explicitly requested
if ( option.equalsIgnoreCase("wrapper") )
{
System.out.println("Spring Wrapper Approach");
context = new ClassPathXmlApplicationContext(
"/dustin/jmx/modelmbeans/spring-mbean-wrapper-context.xml");
}
else if ( option.equalsIgnoreCase("metadata")) // metadata example
{
System.out.println("Spring Metadata Approach");
context = new ClassPathXmlApplicationContext(
"/dustin/jmx/modelmbeans/spring-mbean-metadata-context.xml");
}
else // use simple if neither wrapper nor metadata specified
{
System.out.println("Spring Interface Approach");
context = new ClassPathXmlApplicationContext(
"/dustin/jmx/modelmbeans/spring-mbean-simple-context.xml");
}

final SimpleCalculatorIf calculator =
(SimpleCalculatorIf) context.getBean("exposedModelMBean");
pause(1000000);
}
}


I also added an interface, SimpleCalculatorIf, to these examples to make them easily accessible via the same code for any of the three approaches covered in this blog entry. That simple interface listing is shown next.

SimpleCalculatorIf.java

package dustin.jmx.modelmbeans;

/**
* Interface to expose Model MBean via Spring.
*/
public interface SimpleCalculatorIf
{
public int add(final int augend, final int addend);

public int subtract(final int minuend, final int subtrahend);

public int multiply(final int factor1, final int factor2);

public double divide(final int dividend, final int divisor);
}


Spring makes use of JMX easier in general. Because Spring uses Model MBeans anyway for its JMX support, it is easy to apply the descriptive power of the Model MBean to one’s Spring-exposed JMX MBeans using annotations.

See the blog entry Adding Information to a Standard MBean Interface Using Annotations for a method of using annotations processing to provide descriptive detail via Standard MBeans (as opposed to Model MBeans).




UPDATE (7 February 2009): The following section has been added in response to a request in the feedback section. This section demonstrates how to build and run the code examples shown earlier in the blog post.

The Java source files and XML configuration files for Spring shown above can be placed in different locations depending on how the build file is set up. I will provide an Ant build.xml file that generates a JAR file and a script for running the examples. This build file depends on the Java source code files and Spring Framework configuration files being in a directory structure as shown in the next two screen snapshots.

Placement of Java Source Code Files



Placement of Spring Framework XML Configuration Files



As the screen snapshots above demonstrate, I placed the directories and files under a root directory called C:\dustinjmx. The src and config subdirectories hold the Java source code files and Spring XML configuration files respectively. With this structure in place, the following Ant build.xml file can be used to compile the Java source code and assemble a JAR file. This build file also optionally generates a script that can be used to run the Java/Spring examples.

build.xml

<?xml version="1.0" encoding="UTF-8"?>
<project name="SpringModelMBeansExamples" default="all" basedir=".">

<property name="spring.home.dir"
value="C:\\spring-framework-2.5.6" />

<property name="config.dir" value="config" />
<property name="src.dir" value="src" />
<property name="build.dir" value="build" />
<property name="classes.dir" value="${build.dir}/classes" />
<property name="dist.dir" value="dist" />
<property name="jar.name" value="springjmx.jar" />

<property name="command.string"
value="java -cp ${spring.home.dir}/dist/spring.jar${path.separator}${spring.home.dir}/lib/jakarta-commons/commons-logging.jar${path.separator}${dist.dir}/${jar.name} dustin.jmx.modelmbeans.SpringModelMBeanDemonstrator" />
<property name="script.name" value="runIt" />

<target name="-init">
<mkdir dir="${dist.dir}" />
<mkdir dir="${classes.dir}" />
</target>

<condition property="isWindows" value="true">
<os family="windows" />
</condition>

<target name="compile"
depends="-init"
description="Compile Java classes.">
<javac srcdir="${src.dir}"
destdir="${classes.dir}"
classpath="${spring.home.dir}/dist/spring.jar:${spring.home.dir}/lib/jakarta-commons/commons-logging.jar" />
</target>

<target name="jar" depends="compile"
description="Assemble class files and context XML files into JAR.">
<jar destfile="${dist.dir}/${jar.name}"
basedir="${classes.dir}"
includes="**/*.*"
filesonly="true">
<fileset dir="${config.dir}" includes="**/*.*" />
</jar>
</target>

<target name="clean"
description="Clean generated artifacts.">
<delete dir="${dist.dir}" />
<delete dir="${build.dir}" />
</target>

<target name="display-run-command"
description="Shows how to run these examples.">
<echo>
<![CDATA[
Run the assembled executable Spring JMX Demonstration code
with a command like the following:

${command.string} <<<demonstrator_type>>>

where <<<demonstrator_type>>> is one of the following:

simple
wrapper
metadata
]]>
</echo>
</target>

<target name="generate-run-scripts"
description="Generate script to run JMX examples"
depends="generate-windows-run-script, generate-linux-run-script" />

<target name="generate-windows-run-script"
description="Generate run script for Windows"
if="isWindows">
<echo file="runIt.cmd">${command.string} %1</echo>
</target>

<target name="generate-linux-run-script"
description="Generate run script for Linux."
unless="isWindows">
<echo file="runIt.sh">#!/bin/bash${line.separator}${command.string} $1</echo>
</target>

<target name="all" depends="jar, display-run-command"
description="Default target: Compiles Java source and assembles JAR" />

</project>



The location of the Spring Framework should be changed in the build file to point to wherever it is located on the individual machine. The generate-run-scripts target can be called with ant generate-run-scripts to build a script that can then be run to start the examples covered earlier in this blog posting. When the script is run, it should be run with a command-line option of simple, wrapper, or metadata like this: runIt simple.



Once this script has been started, JConsole can be started in a different window by typing "jconsole" on the command line. If JConsole is run on the same machine as the Java application just started, the it should be a local connection that can be selected as shown in the following screen snapshot. Use the MBeans tab to interact with the Java application as shown earlier.

Thứ Tư, 2 tháng 7, 2008

Simple Spring HTTP Remoting Example

I am using this blog entry to demonstrate by simple example the use of the Spring Framework's HTTP Remoting. There are numerous online resources on this subject, so my intention here is to provide an extremely simple but complete demonstration of using Spring's HTTP Remoting with non-browser clients.

The Spring approach to HTTP Remoting allows clients to communicate with the Spring-hosted server code via HTTP without the client code requiring any knowledge of HTTP being used. Instead, the client Java code only "sees" normal business-related Java objects (usually interfaces) rather than HTTP-specific objects.

Spring HTTP Remoting generally requires Spring and Java on both the server side and client side. However, if those two requirements can be met, Spring HTTP Remoting is easily applied.

The following steps allow HTTP communication between Spring-hosted clients and servers. After first briefly outlining the steps, I'll then delve into them in more detail (including code samples).


  1. Create or use an existing Spring bean that typically implements a Java interface.

    This is nothing special to HTTP remoting and is the same step you'd need to take to do most things in Spring (a notable exception is Spring JDBC that does not require any Spring beans to be used).


  2. Create the Spring XML configuration file for associating the bean created in step #1 with a Spring application context.

    As with Step #1, this XML file is nothing particular to Spring HTTP Remoting, but is instead common to nearly all Spring Framework wiring and configuration.


  3. Create or add to web.xml file.

    This third step is the first step that is more particular to Spring HTTP Remoting, but is still generally applicable with Spring MVC framework. This step includes adding the servlet class and URL mappings as one usually uses with Java EE servlets and JavaServer Pages. The most important part of this step is to specify the Spring DispatcherServlet. An optional "link" is also provided in this web.xml file to a context config location where one or more Spring XML application context files are located and used.


  4. Create the Spring-specific servlet context file.

    This XML file looks a lot like a "normal" Spring application context XML configuration file, but its name is prescribed by the convention of servlet name followed by a hypen and the word servlet. In other words, if the servlet was called "somewebthing" in the web.xml file, this Spring servlet configuration file would be called somewebthing-servlet.xml. This file contains the configuration for the HttpInvokerServiceExporter (the piece of this that is particular to the HTTP Remoting covered in this blog entry) and URL mapping information.


  5. Test!

    Although the simple client will be writting without HTTP in mind and will appear to only be using Java objects, it will actually be invoking the service via HTTP. This will be "proven" by running the client without the service deployed and watching for the resulting HTTP error code.




I'll now move onto demonstrating the above steps in greater detail and attempt to illustrate them concretely with code samples.

Step #1: The Bean and Its Interface

This step is no different than defining Java classes and interfaces they implement for use with Spring. The following code listings show the interface (StateCapitalServiceIF) and the implementing class (StateCapitalService) used for this example.

--- StateCapitalServiceIF.java ---

package examples.springhttp;

import java.io.Serializable;

/**
* The State Capital Service interface that the client will use to access
* server-side functionality via HTTP.
*/
public interface StateCapitalServiceIF extends Serializable
{
/**
* Provide capital of state whose name is provided.
*
* @param stateName Name of state whose capital is desired.
* @return Capital of the specified state; null if not found.
*/
public String getCapital(final String stateName);
}


--- StateCapitalService.java ---

package examples.springhttp;

import java.util.Map;

/**
* Implementation of functionality to be run after being called by client via
* HTTP.
*/
public class StateCapitalService implements StateCapitalServiceIF
{
Map statesAndCapitals = null;

public StateCapitalService()
{
}

/**
* Set my states to state capitals mapping.
*
* @param statesAndCapitals States to state capitals mapping.
*/
public void setStatesAndCapitals(final Map statesAndCapitals)
{
this.statesAndCapitals = statesAndCapitals;
}

/**
* Provide capital of state whose name is provided.
*
* @param stateName Name of state whose capital is desired.
* @return Capital of the specified state; null if not found.
*/
public String getCapital(final String stateName)
{
return this.statesAndCapitals.get(stateName);
}
}



Step #2: Spring Application Context Configuration File

I like to keep Spring's HTTP-specific configuration separate from the bean's XML configuration. Therefore, the bean's configuration is exactly like one would see normally with Spring. To configure the StateCapitalService class above, the following configuration is used:

--- spring-http-config.xml ---

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<util:map id="statesCapitalsMap">
<entry key="Alabama" value="Montgomery" />
<entry key="Alaska" value="Juneau" />
<entry key="Arizona" value="Phoenix" />
<entry key="Arkansas" value="Little Rock" />
<entry key="California" value="Sacramento" />
<entry key="Colorado" value="Denver" />
<entry key="Connecticut" value="Hartford" />
</util:map>

<bean id="stateCapitalService"
class="examples.springhttp.StateCapitalService"
p:statesAndCapitals-ref="statesCapitalsMap" />

</beans>


So far, nothing specific to HTTP Remoting has been done. In fact, the bean, its interface, and its XML application context configuration could all be run by a normal Java SE class like the one shown below:

--- MainServiceAppContext.java ---

package examples.springhttp;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* Demonstrates how Spring bean can be used without any HTTP involvement.
*/
public class MainServiceAppContext
{
public static void printStateInfo(
final StateCapitalServiceIF stateCapitalMapper,
final String state)
{
System.out.println(
"The capital of " + state + " is "
+ stateCapitalMapper.getCapital(state));
}

/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
final ApplicationContext context =
new ClassPathXmlApplicationContext(
"examples/springhttp/spring-http-config.xml" );
StateCapitalServiceIF stateCapitalMapper =
(StateCapitalServiceIF) context.getBean("stateCapitalService");
printStateInfo(stateCapitalMapper, "Alabama");
printStateInfo(stateCapitalMapper, "Colorado");
}
}


Step #3: The web.xml File

This web.xml file is familiar to anyone who has developed a Java EE web application. The web.xml used in this example is shown next.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

<display-name>
Simple Spring HTTP Remoting Example
</display-name>

<description>
This is meant as an extremely simple example of using Spring's HTTP
Remoting capability.
</description>

<servlet>
<servlet-name>statesCapitals</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>statesCapitals</servlet-name>
<url-pattern>/statesCapitals</url-pattern>
</servlet-mapping>

<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/examples/springhttp/spring-http-config.xml</param-value>
</context-param>

</web-app>


Step #4: The Servlet Context Configuration File

Because the servlet in this example is named "statesCapitals," a Spring servlet configuration file named statesCapitals-servlet.xml needs to be provided. It is shown next:

--- statesCapitals-servlet.xml ---

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<bean id="httpStateCapitalService"
class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter"
p:service-ref="stateCapitalService">
<property name="serviceInterface">
<value>examples.springhttp.StateCapitalServiceIF</value>
</property>
</bean>

<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/statesCapitals">httpStateCapitalService</prop>
</props>
</property>
</bean>

</beans>


Step #5: Testing It

We need to configure the client to communicate via HTTP with our server-side application. The configuration for this is contained in spring-http-client-config.xml for this example and is shown next:

--- spring-http-client-config.xml ---

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<bean id="stateCapitalProxyService"
class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl">
<value>http://localhost:8080/SpringHTTPExample/statesCapitals</value>
</property>
<property name="serviceInterface">
<value>examples.springhttp.StateCapitalServiceIF</value>
</property>
</bean>

</beans>


The client code that uses the above XML to bootstrap a Spring container and call the server-side code via HTTP is in the class HttpClient and that code is shown next:

--- HttpClient.java ---

package examples.springhttp.client;

import examples.springhttp.StateCapitalServiceIF;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* This class demonstrates a client of a Spring HTTP-exposed service and shows
* how the client interacts with the server as if using normal Java objects
* rather than using anything HTTP specific.
*/
public class HttpClient
{
public static void printStateInfo(
final StateCapitalServiceIF stateCapitalMapper,
final String state)
{
System.out.println(
"The capital of " + state + " is "
+ stateCapitalMapper.getCapital(state));
}

public static void main(final String[] arguments)
{
final ApplicationContext context =
new ClassPathXmlApplicationContext(
"examples/springhttp/client/spring-http-client-config.xml");
final StateCapitalServiceIF stateCapitalService =
(StateCapitalServiceIF) context.getBean("stateCapitalProxyService");
printStateInfo(stateCapitalService, "Colorado");
printStateInfo(stateCapitalService, "Alabama");
}
}


When the server-side code is built into a WAR and deployed to Tomcat or other web server, the above client will connect to it successfully and print out the capitals of Alabama and Colorado as shown in the next screen snapshot:



If the server-side application is undeployed or the web server is turned off, the client prints a 404 ("Not Found") HTTP status code indicating it is not available and proving that HTTP is being used. This is shown in the next screen snapshot.



The Packaging

I have displayed the contents of all the files above, but the packaging of them can be a little tricky. This section shows the contents of various JARs and the WAR I used to run the above examples.

--- SpringHTTPExample.war ---
This is the WAR file I deployed to Tomcat:

102 Thu Jul 03 23:25:54 MDT 2008 META-INF/MANIFEST.MF
1218 Thu Jul 03 23:13:42 MDT 2008 WEB-INF/web.xml
1505 Thu Jul 03 23:25:56 MDT 2008 WEB-INF/lib/SpringHTTPExample-web.jar
52915 Thu Jul 03 23:25:56 MDT 2008 WEB-INF/lib/commons-logging.jar
2832933 Thu Jul 03 23:25:56 MDT 2008 WEB-INF/lib/spring.jar
385822 Wed Jan 09 13:24:06 MST 2008 WEB-INF/lib/spring-webmvc.jar
1099 Thu Jul 03 22:33:04 MDT 2008 WEB-INF/examples/springhttp/spring-http-config.xml
1143 Thu Jul 03 23:25:42 MDT 2008 WEB-INF/statesCapitals-servlet.xml


In the above WAR, three of the JARs in the WEB-INF/lib are Spring-provided. Besides those, the remaining content of the WAR consists simply of the web.xml file shown above, the statesCapitals-servlet.xml file shown above, the spring-http-config.xml file shown above, and a JAR file called SpringHTTPExample-web.jar, whose contents are shown next.

--- SpringHTTPExample-web.jar ---

102 Thu Jul 03 23:25:54 MDT 2008 META-INF/MANIFEST.MF
1011 Thu Jul 03 23:25:54 MDT 2008 examples/springhttp/StateCapitalService.class
205 Thu Jul 03 23:25:54 MDT 2008 examples/springhttp/StateCapitalServiceIF.class


The contents of the JAR above consist simply of the bean class and the interface it implements, both of which are shown above.

--- SpringHTTPClient.jar ---
The contents JAR used to test the HTTP-exposed service are shown now:

102 Thu Jul 03 23:25:54 MDT 2008 META-INF/MANIFEST.MF
205 Thu Jul 03 23:25:54 MDT 2008 examples/springhttp/StateCapitalServiceIF.class
1618 Thu Jul 03 23:25:54 MDT 2008 examples/springhttp/client/HttpClient.class
954 Thu Jul 03 23:25:54 MDT 2008 examples/springhttp/client/spring-http-client-config.xml


The above client JAR includes the compiled version of the client class shown above along with the spring-http-client-config.xml configuration file shown above. Perhaps the most interesting thing to note here is that the interface class included in the server JAR also needs to be in the client JAR. This makes sense, of course, because it is that interface the client code uses as a proxy to the server side.

Conclusion

In this blog entry, I have included all the code (Java and XML) necessary to build and run a simple example that uses and illustrates Spring's HTTP Remoting capabilities. I did not cover every nuance of this feature and did not explicitly discuss some of the associations between various configuration files. There are several good resources on Spring's HTTP Remoting that do this. I instead attempted to illustrate complete code for a simple Spring HTTP Remoting example without referencing work on similar Spring remoting solutions. (Because Spring treats remoting very consistently, many good books and tutorials cover HTTP support with references to the other protocols supported.) I am including some references to these other resources related to Spring HTTP remoting below.

Other Resources

* Section 17.4 ("Exposing Services Using HTTP Invokers") of Spring Framework 2.5 Reference Manual

* Best of Both Worlds Remote Services with Spring HTTP Invoker

* A Case for Lightweight Remoting (Part 2): Spring to the Rescue