|
|
WS-Policy and moreFabian's Blog on WS-Policy and more |
|
Thursday Dec 10, 2009
Runtime Configuration Management in Metro 2.0
Today's release of Metro 2.0 comes with a novel feature that we call Configuration Management (WS-CM). It allows to reconfigure a running JAX-WS web service instance without losing any messages. The web service does not have to be redeployed or restarted. All configuration changes are persisted across application redeployments and server restarts. Metro provides an easy to use management interface based on JMX to reconfigure managed web service instances. Any WS-Policy configuration may be changed through that interface. That means you can make extensive changes to your web service's security, transaction, messaging, and many more settings. You can find the full documentation in the Metro guide in the chapter "Monitoring and Management". WS-CM works in all containers supported by Metro 2.0, i.e. Tomcat, GlassFish V2 and GlassFish V3, released today. Tags: Web Services, Project Metro, JAX-WS, GlassFish V3 Posted at 04:39PM Dec 10, 2009 by Fabian Ritzmann in Sun | Comments[0]
Tuesday Dec 08, 2009
Named parameters in Java
I was recently writing some Java factory code that would have benefited from named parameters. Java unfortunately does not support named parameters. I searched around the web for some solutions that could provide a work-around but did not find anything. I was trying to solve a problem that seems common when you are implementing a factory. Imagine a factory that creates objects but does not or should not know what parameters these objects take for initialization. The factory interface might look like this in Java: public interface Factory {
public Result create(Object... parameters);
}
The above has two issues. Object... (and its equivalent Object[]) does not provide any type safety. And parameters depend on the position in the array, which is very error-prone. Code using the above would look like this: Type1 parameter1 = (Type1)parameters[0]; Type2 parameter2 = (Type2)parameters[1] You might ask yourself why I do not just use something like "String... parameters" for type safety? That is fine as long as you can be sure that all your objects are only initialized with Strings and no parameters of any other type that is not a subtype of String. And you still need to be very careful that all parameters are always passed in the correct order. The obvious improvement over using an array or a list to pass arbitrary parameters is the use of a Map. If you use parameter names as map keys and the actual parameter as the map values, you are somewhat closer to real named parameters already. This is how the factory interface could look like then: public interface Factory {
public Result create(Map<String, Object> parameters);
}
The drawback with the above is that any code using the parameters must cast from Object to the actual type like this: Type1 parameter1 = (Type1)parameters.get("parameter name 1");
Type2 parameter2 = (Type2)parameters.get("parameter name 2");
When we reviewed this code, someone suggested a solution using Generics instead: public interface Factory {
public <T> Result create(Map<String, T> parameters);
}
Unfortunately, that approach does not work because it forces you to use the same type T for all parameters. In other words, it is the Generics equivalent to the "String... parameters" approach discussed earlier. We can take the Map approach one step further if we introduce one additional layer of indirection. Instead of using a Map with the same type T for all values, we can implement a wrapper that allows to use an individual type for each parameter: public class NamedParameters {
private final HashMap<String, Object> nameToInstance = new HashMap<String, Object>();
/**
* Add parameter with the given name.
*
* @param <T> The type of the parameter.
* @param name The name of the parameter.
* @param parameter The parameter.
* @return This instance of NamedParameters (so that you can chain multiple put calls).
*/
public <T> NamedParameters put(String name, T parameter) {
this.nameToInstance.put(name, parameter);
return this;
}
/**
* Get parameter with the given name and type. Returns null if a parameter
* with the name exists but has a different type.
*
* @param <T> The type of the parameter.
* @param name The name of the parameter.
* @return The parameter with the given name or null.
*/
@SuppressWarnings("unchecked")
public <T> T get(String name) {
try {
return (T) this.nameToInstance.get(name);
} catch (ClassCastException e) {
return null;
}
}
}
The factory would now look like this: public interface Factory {
public Result create(NamedParameters parameters);
}
And you would use it like this: Type1 parameter1 = parameters.get("parameter name 1");
Type2 parameter2 = parameters.get("parameter name 2");
You might have noticed the NamedParameters parameters = (new NamedParameters()).put("parameter name 1", "text")
.put("parameter name 2", new Integer(5));
String parameter1 = parameters.get("parameter name 1");
// parameter2 will be null:
Boolean parameter2 = parameters.get("parameter name 2");
Depending on your exception handling strategy, you might want to throw an exception instead of returning Tags: Java Posted at 02:59PM Dec 08, 2009 by Fabian Ritzmann in Sun | Comments[0]
Wednesday May 27, 2009
Fabian on Twitter I am giving this newfangled thing called Twitter a try. I like it so far. (As a side effect, Adobe Air now sneaked onto my system through TweetDeck.) If you are interested in my struggles with tools and code you can follow me at: http://twitter.com/ritzmann. Posted at 04:06PM May 27, 2009 by Fabian Ritzmann in Sun | Comments[1] Talks about Metro at JavaOne 2009 We are having quite a couple of talks this year at JavaOne and CommunityOne about Metro. Here is a list sorted by date:
Tags: Web Services, Project Metro, JAX-WS, JavaOne Posted at 03:51PM May 27, 2009 by Fabian Ritzmann in Sun |
Friday Feb 27, 2009
Metro 2.0 on Java SE 6
We have recently had reports in the Metro user forum where people that ran Metro 2.0 with Java SE 6 had trouble using wsimport. They would typically get errors like this:
parsing WSDL...
generating code...
wspolicy/provider/wsdl/server/Echo.java
wspolicy/provider/wsdl/server/EchoResponse.java
wspolicy/provider/wsdl/server/EchoService.java
wspolicy/provider/wsdl/server/Echo_Type.java
wspolicy/provider/wsdl/server/ObjectFactory.java
wspolicy/provider/wsdl/server/package-info.java
Copying 2 files to
/Users/fr159072/tmp/WebApplication8/build/web/WEB-INF/wsdl/NewWebServiceFromWSDL
wsimport-service-generate:
Created dir:
/Users/fr159072/tmp/WebApplication8/build/web/WEB-INF/classes
Created dir: /Users/fr159072/tmp/WebApplication8/build/web/META-INF
Copying 1 file to
/Users/fr159072/tmp/WebApplication8/build/web/META-INF
Copying 3 files to /Users/fr159072/tmp/WebApplication8/build/web
library-inclusion-in-archive:
library-inclusion-in-manifest:
wsimport-service-compile:
Compiling 6 source files to
/Users/fr159072/tmp/WebApplication8/build/web/WEB-INF/classes
/Users/fr159072/tmp/WebApplication8/build/generated/wsimport/service/wspolicy/provider/wsdl/server/EchoService.java:47:
cannot find symbol
symbol : constructor
Service(java.net.URL,javax.xml.namespace.QName,javax.xml.ws.WebServiceFeature[])
location: class javax.xml.ws.Service
super(ECHOSERVICE_WSDL_LOCATION, ECHOSERVICE_QNAME,
features);
/Users/fr159072/tmp/WebApplication8/build/generated/wsimport/service/wspolicy/provider/wsdl/server/EchoService.java:55:
cannot find symbol
symbol : constructor
Service(java.net.URL,javax.xml.namespace.QName,javax.xml.ws.WebServiceFeature[])
location: class javax.xml.ws.Service
super(wsdlLocation, ECHOSERVICE_QNAME, features);
/Users/fr159072/tmp/WebApplication8/build/generated/wsimport/service/wspolicy/provider/wsdl/server/EchoService.java:63:
cannot find symbol
symbol : constructor
Service(java.net.URL,javax.xml.namespace.QName,javax.xml.ws.WebServiceFeature[])
location: class javax.xml.ws.Service
super(wsdlLocation, serviceName, features);
3 errors
For a detailed analysis when exactly this is happening, see this Wiki page. The reason for these failures is that Metro 2.0 contains JAX-WS 2.2, which clashes with JAX-WS 2.1 1 that is built into Java SE 6. You will only see these failures if you did not install Metro 2.0 with our installation scripts metro-on-glassfish.xml/metro-on-tomcat.xml. That is the case if you e.g. installed Metro 2.0 for GlassFish V3 via the update center or if you use a version of GlassFish V3 built into NetBeans. The simplest solution is to download the Metro 2.0 nightly build and run the installation script. The script copies the file webservices-api.jar, which contains the JAX-WS 2.2 API, into <java-home>/lib/endorsed. Alternatively, you can of course manually copy webservices-api.jar into a suitable endorsed directory. Tags: Web Services, Project Metro, JAX-WS, Java 1Java SE 6 update 3 and older contains JAX-WS 2.0. Posted at 04:35PM Feb 27, 2009 by Fabian Ritzmann in Sun |
Wednesday Jan 14, 2009
Speed up NetBeans projects on Mac OS X I found a lot of tips how to build your NetBeans projects faster with the help of tmpfs. However tmpfs is not available for Mac OS X as far as I can tell. Fortunately Mac OS X already has a RAM disk built in that is just as good for this purpose. (That is what tmpfs really does, it provides a RAM disk that is mounted like any ordinary filesystem.) The following is not really specific to NetBeans or NetBeans projects. You can speed up almost any application that relies on many file operations this way. A nice side effect is that not only NetBeans builds but also NetBeans itself works much faster that way, i.e. file scans and other operations in the IDE that used to take a longer time, are almost instantanious after the change. The easiest way to use the Mac OS RAM disk is through this donationware utility: Espérance DV. If you really like the command line, you can achieve the same with the help of the hdid service that is built into Mac OS. No matter how you do it, create a RAM disk, copy your project into it and point NetBeans to it. That's it. In my case, for a large project with lots of file operations during the build, unzipping archives, copying around lots of files, etc. my build finished five times faster than before. That's a huge deal when you run these builds all the time. There are some drawbacks of course. It is a RAM disk after all, i.e. once the power is gone so are your files. That can be fatal when your system suddenly hangs and needs to be powercycled for example. Espérance DV has an option to save your files to a disk image and restore them from there but you need to manually initiate the saving. That is good enough I guess when you regularly reboot your system unless you forget to press the save button. It won't help however when the system freezes. I haven't tried it out but I hope that Time Machine automatically backs up the RAM disk, which would allow you to restore the content again should it be wiped out accidentally. Tags: NetBeans, tmpfs, Mac OS X, RAM disk Posted at 04:39PM Jan 14, 2009 by Fabian Ritzmann in Sun | Comments[1]
Friday Nov 07, 2008
OSGIfying Metro for GlassFish V3
Metro has been a part of GlassFish for a long time now and provides the GlassFish web services implementation. That goes of course for the newly released GlassFish V3 Prelude as well. One of the most important points of GlassFish V3 from an implementation point of view is that it is based entirely on OSGI. This means that all modules like Metro that go into GlassFish have to be provided as OSGI bundles. That is why we recently released Metro 1.4, which is also included in GlassFish V3 Prelude. The main feature it provides is that it makes OSGI bundles of Metro 1.4 for GlassFish V3 available. If you want to install the latest version on GlassFish V3, you do not download Metro yourself anymore. Instead use the update center. We are still making Metro available as an ordinary download of course for non-GlassFish V3 installations. I wanted to talk a little about the technical challenges we had in creating OSGi bundles from Metro. OSGi is very well suited to develop a large modular system like Metro from scratch. It is not quite as easy however to convert a large base of existing code and libraries into an OSGi bundle. Metro consists of app 30 - 40 libraries, many of which are e.g. basic XML libraries that have developed over many years and are used in a huge variety of applications. Many of the libraries are not actually owned by the Metro project but are third party libraries, e.g. Woodstox. In other words, changing code or even starting to use OSGi services internally was not practical. Ideally, we would have created separate bundles for every technology contained in Metro. Unfortunately, that would have meant lots of work and so we decided to stick with two bundles, one for JAXB and one for the rest of the Metro stack. The reason that we singled out JAXB was its unique approach that allows JAXB 2 to ensure backwards compatibility with JAXB 1.0. JAXB 2 is packaging the JAXB 1.0 classes in its JAR file. It puts these classes into a subdirectory so that an ordinary Java classloader can not find them. JAXB 2 implements its own classloader that will load the JAXB 1.0 classes when someone uses the JAXB 1.0 API. Unfortunately, that approach confused the Bnd tool that we are using to create our OSGi bundles. It created entries for the JAXB 1.0 classes with bogus package names because it interpreted the subdirectory as part of the package name. That would later confuse the OSGi container when loading classes. Since JAXB is supposed to use its own classloader in this case, we did not want these classes to show up in the OSGi manifest at all. We ultimately extracted the JAXB 1.0 classes, running the Bnd tool on the remaining classes and then readding the JAXB 1.0 classes to the OSGi bundle. What caused most work was that we had such a big amount of libraries with an uncontrollable amount of dependencies. As I explained before, many libraries have developed over many years and are used by large amounts of applications. Additionally, we found that the OSGi classloaders are not able to deal with e.g. loading of property classes unless the packages containing these properties are declared. We would have had to go through thousands of packages and analyze which ones we really needed to expose. Moreover, as soon as a version of a library changes, you have to check again if any change has an impact on your OSGi manifest. We finally concluded that our best option was to export all Metro packages, no matter if they were supposed to be used by other clients or not. That option is certainly not worse than what you have with any Java application where all public classes in the classpath are accessible throughout the entire JVM. All in all, putting such a large collection of libraries into OSGi bundles is a worthwile exercise because it helps to point out incorrect dependencies. At the same time, you have to realize that it can be a lot of work depending on how far you are prepared to take the conversion. Tags: Web Services, Project Metro, Project Tango, WSIT, GlassFish V3 Prelude, OSGi Posted at 04:20PM Nov 07, 2008 by Fabian Ritzmann in Sun | Comments[2]
Wednesday Oct 29, 2008
Metro 1.3.1 uploaded to Maven 2 repository
We released Metro 1.3.1 a couple of weeks ago but forgot to upload it to our public Maven repository. I just rectified that. Use com.sun.xml.ws:webservices:1.3.1 as the Maven address. Thanks to Kohsuke for reporting it: Metro 1.3.1 missing in Maven. Tags: Web Services, Project Metro, Project Tango, Maven 2 Posted at 03:14PM Oct 29, 2008 by Fabian Ritzmann in Sun |
Tuesday Oct 07, 2008
Metro installation for Java 6
Recently I changed the Metro installation scripts based on this discussion in the forum. We used to always install webservices-api.jar into the Java 6 runtime endorsed system directory. That was necessary with Java 6 update 3 and earlier Java 6 releases because Java 6 contained the JAX-WS 2.0 API while current releases of Metro ship with JAX-WS 2.1. Since update 4 however JAX-WS 2.1 is part of Java 6 and there is no need to use the endorsed mechanism anymore. So now we are installing webservices-api.jar into the endorsed directory only if the script is run with an older version of Java 6. Note that Java 5 installations are not an issue here because Java 5 does not include any JAX-WS API. I was considering for a while whether we should install into a system endorsed directory in the first place instead of an application specific endorsed directory. However, some tools and applications are not designed with that in mind and we want to remain backwards compatible. Tags: Web Services, Project Metro, Project Tango, Java Posted at 02:31PM Oct 07, 2008 by Fabian Ritzmann in Sun |
Friday Sep 19, 2008
Running Findbugs with Ant Tasks for Maven
We have been using Findbugs for quite a while now to help us find and squash bugs before they can do any harm. It is an excellent tool. Findbugs is directly integrated into our Ant build scripts and is run with every build. Findbugs provides an Ant task that makes it easy to integrate into Ant. For the integration you have to install Findbugs of course or provide the libraries with the rest of the Metro workspace. We did not want to require a manual installation for every developer because that seemed just inconvenient. And we did not want to check the libraries into our workspace because that workspace and the downloadable distributables are already bigger than we would like them to be. Hence we chose an approach that I have not seen documented in its entirety anywhere else. The solution is primarily provided by the eminently useful Ant Tasks for Maven. They allow you to execute a couple of Maven related tasks from an Ant build script. And one of the useful things you can do with them is download Findbugs from a Maven repository within your Ant build script. Integrating the tasks is straight-forward: <target name="maven-init">
<typedef resource="org/apache/maven/artifact/ant/antlib.xml">
<classpath>
<pathelement location="lib/maven-artifact-ant-2.0.4-dep.jar" />
</classpath>
</typedef>
<remoteRepository id="maven.repository" url="http://www.ibiblio.org/maven2/"/>
</target>
The above makes sure Ant knows about the new Maven tasks and declares a repository from which we will be dowloading Findbugs. This target is designed to be reused by other targets, not just the one that is downloading Findbugs. But back to integrating Findbugs into our Ant script. This here does the interesting part of the work: <target name="findbugs-base" depends="maven-init">
<dependencies pathId="findbugs.classpath"
useScope="runtime">
<remoteRepository refid="maven.repository"/>
<dependency groupId="net.sourceforge.findbugs"
artifactId="findbugs"
version="1.3.2"/>
</dependencies>
<typedef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask">
<classpath refid="findbugs.classpath"/>
</typedef>
<pathconvert property="findbugs.classpath">
<path refid="findbugs.classpath"/>
</pathconvert>
</target>
The <target name="findbugs-html" depends="findbugs-base"
<findbugs output="html"
outputFile="${build.dir}/findbugs.html"
stylesheet="fancy.xsl"
classpath="${findbugs.classpath}"
jvmargs="-Xmx256m"
pluginlist="${user.home}/.m2/repository/net/sourceforge/findbugs/coreplugin/1.3.2/coreplugin-1.3.2.jar"
excludefilter="findbugs-exclude.xml">
<class location="${build.classes.dir}"/>
<auxClasspath>
<path path="${run.classpath}"/>
</auxClasspath>
<sourcePath path="${src.dir}"/>
</findbugs>
</target>
The above simply invokes the Posted at 03:31PM Sep 19, 2008 by Fabian Ritzmann in Sun | Comments[2]
Tuesday Aug 19, 2008
Metro 1.3
Approximately two weeks ago we released Metro 1.3. There is not much to say from the WS-Policy perspective. It's been mostly a bugfix release and there haven't been any significant bugs to fix in policy. One of our users noted an invalid reference in the NetBeans project settings for the Metro 1.3 source code: nbproject for rt build depends on missing xmldsig.jar. The NetBeans project setup has been fixed on the trunk of course but if you need to work with the source code for Metro 1.3, do the following:
That's it. The cause for this slip was that we are using a new version of the xmlsec.jar that already contains a copy of the xmldsig.jar. Posted at 05:05PM Aug 19, 2008 by Fabian Ritzmann in Sun |
Friday Jul 04, 2008
Printing SOAP messages II
In Printing SOAP messages I was describing a proprietary feature how to monitor SOAP responses and requests on a Metro web service client. Not quite unexpectedly, we got some requests for similar functionality on the server. Marek therefore went and refactored the existing implementation somewhat to enable you to listen to SOAP messages on the server as well. This means that the packages for the client changed a little as well. I will first describe what you need to do with the client if you are using the current Metro builds. Then I will describe what you can do on the server now. Check Marek's blog for a description of some more features that he implemented and that make monitoring on the server more feasible. Printing SOAP messages on the clientVery little changed actually compared to Printing SOAP messages. The package name is different however and I am repeating the code from the previous article with the new package names: import com.sun.xml.ws.messagedump.MessageDumpingFeature;
...
// Prepare to plug in the code that allows to read SOAP messages
MessageDumpingFeature messageDumper = new MessageDumpingFeature();
// Instantiate the web service client
YourService service = new YourService();
// Plug in the SOAP message dumper
YourPort port = service.getYourServicePort(messageDumper);
// Invoke the web service
YourResult result = port.yourmethod(yourparameter);
// Read the SOAP messages that were exchanged
String request = messageDumper.nextMessage();
String response = messageDumper.nextMessage();
...
Printing SOAP messages on the serviceThis task is a little less straight-forward and the example implementation I am showing is somewhat restricted. Usually, you implement a web service implementation class with some operations. You can access the MessageDumpingFeature inside those operations. That means however that that code will only be able to see the SOAP request that came in. The SOAP response has not been generated at that point in time and you do not have access to it. You will however see the SOAP response to the previous request. There are some ways to work around these restrictions and Marek will discuss them in the coming days. I will only show the simple case here where you are accessing the MessageDumpingFeature inside an operation: import com.sun.xml.ws.api.WSBinding;
import com.sun.xml.ws.api.message.Packet;
import com.sun.xml.ws.api.server.WSEndpoint;
import com.sun.xml.ws.api.server.WSWebServiceContext;
import com.sun.xml.ws.messagedump.MessageDumping;
import com.sun.xml.ws.messagedump.MessageDumpingFeature;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.annotation.Resource;
import javax.xml.ws.WebServiceContext;
/**
* The WebService annotation announces to JAX-WS that this is a web service implementation class.
* The second annotation enables the message dumping feature.
*/
@WebService
@MessageDumping(storeMessages=true)
public class TestService {
@Resource
WebServiceContext context;
/**
* A web service operation
*/
@WebMethod(operationName = "echo")
public String echo(@WebParam(name = "text") final String text) {
if (context != null) {
// We need to get access to the MessageDumpingFeature object. This is a little tricky,
// we need to work our way through some JAX-WS implementation classes.
WSWebServiceContext wsContext = (WSWebServiceContext) context;
Packet packet = wsContext.getRequestPacket();
WSEndpoint endpoint = packet.endpoint;
WSBinding binding = endpoint.getBinding();
// Got it finally
MessageDumpingFeature messageDump = binding.getFeature(MessageDumpingFeature.class);
if (messageDump != null) {
// The first time this method is invoked, it will return the SOAP request. All other invocations will
// return the SOAP response of the previous invocation.
String previousResponse = messageDump.nextMessage();
// The first time this method is invoked, it will return null. All other invocations will return the
// current SOAP request.
String request = messageDump.nextMessage();
}
}
// This is the actual business logic. In this case it is a very simple operation.
return text;
}
}
Tags: Web Services, Project Metro, Project Tango, WSIT, JAX-WS Posted at 05:48PM Jul 04, 2008 by Fabian Ritzmann in Sun | Comments[2]
Friday Jun 27, 2008
Printing SOAP messages
Metro has a (proprietary, may change at any time) feature that provides read access to the SOAP messages that a client exchanges with a web service. That allows to display the SOAP messages to users or log them for diagnostic purposes. Metro can be configured extensively to log SOAP messages and other properties, see http://blogs.sun.com/arungupta/entry/message_logging_in_wsit_updated, but with this feature it is possible to get the content of SOAP messages at run-time and process them with your own code any way you like. This feature hinges on the use of the internal class
import com.sun.xml.ws.assembler.MessageDumpingFeature;
...
// Prepare to plug in the code that allows to read SOAP messages
MessageDumpingFeature messageDumper = new MessageDumpingFeature();
// Instantiate the web service client
YourService service = new YourService();
// Plug in the SOAP message dumper
YourPort port = service.getYourServicePort(messageDumper);
// Invoke the web service
YourResult result = port.yourmethod(yourparameter);
// Read the SOAP messages that were exchanged
String request = messageDumper.nextMessage();
String response = messageDumper.nextMessage();
...
The Strings request and response will hold the SOAP messages that were exchanged in clear text. The same approach works with a dispatch client as well. Tags: Web Services, Project Metro, Project Tango, WSIT, JAX-WS Posted at 12:00PM Jun 27, 2008 by Fabian Ritzmann in Sun | Comments[7]
Thursday May 22, 2008
Using Metro With Spring The question on how to configure/deploy/use Metro, i.e. JAX-WS and the WS-* interoperability features, with Spring is coming up quite frequently. I wrote up a set of instructions with screenhots etc. how to do it: https://metro.dev.java.net/guide/#springa. The instructions are based on the information provided by the JAX-WS Commons Spring project. Tags: Web Services, Project Metro, Project Tango, WSIT, Spring, JAX-WS Posted at 03:24PM May 22, 2008 by Fabian Ritzmann in Sun |
Tuesday May 20, 2008
WS-Policy in Metro 1.2 Metro 1.2, our Java web services stack, was released right before JavaOne. Our support for WS-Policy has been very stable and we had to do very few bug fixes only. Indeed I am aware of only two:
Both are not even real bugs but features. The first one allows our underlying transport implementation to manipulate WSDL in ways it hasn't been able to do previously. The other bug removes some legacy code that was trying to load a file named wsit.xml to configure a service instead of wsit-name.of.endpoint.implementation.class.xml. This code had been lingering from before we released WSIT 1.0. Tags: WS-Policy, Web Services, Metro, Project Tango, WSIT Posted at 04:14PM May 20, 2008 by Fabian Ritzmann in Sun | |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||