Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Saturday, November 30, 2013

How to use PowerMock and Mockito to test static and private methods

Introduction

This article is not another diatribe to tell you the importance of unit testing. I think we can all agree that it is important. This is about solving an issue that comes up frequently in unit testing. How do I test static methods, and how do you test private methods.

Until PowerMock, most developers were told you can't really test a static method per se. I will show how to do it below.

A common mechanism for testing private methods is to change them to protected. This is not a good solution for a number of reasons. So how do we test them? Again, PowerMock has come to the rescue.
I want solutions. I use Arquillian, but I am not such a zealot that I will chant the mantra that mocking is evil and should not be done. It is a means to an end. That being said, we use Mockito which in my professional experience is the best current mocking framework available. It is easy to setup and use.
However, Mockito has its limitations. Two are mentioned above. The fine developers of PowerMock have come up with an additional framework to use in conjunction with Mockito to get around the limitations.

Solution

The Apache Maven sample code for the project was developed using NetBeans and can be found on Bitbucket here: unit-testing-mockito-powermockito.

Since I am a Apache Maven user, I simply add the relevant frameworks to my pom.xml as shown below: Once the test frameworks are in place, I can use the PowerMockRunner to help me with my testing. The following are some simple classes to demonstrate how to test. The first is a class to generate UUID values for IDs.

IdentityUtilities.java


Next, I need a class to represent a person. I am interested in testing the private method generateId.

Person.java


Finally, we need our PersonTest class to test our Person object. The explanation follows the code.

PersonTest.java


The @RunWith(PowerMockRunner.class) annotation tells jUnit that we are using an extension to handle testing of this class. This tells jUnit to use this test runner instead of its own test runner.
The @PrepareForTest({IdentityUtilities.class, Person.class}) serves multiple purposes here. The first is to tell PowerMock that we need to do some preparation of the classes to instrument them for our testing. Classes defined using this annotation are typically those that needs to be byte-code manipulated. This includes final classes, classes with final, private, static or native methods that should be mocked and also classes that should be return a mock object upon instantiation. IdentityUtilities.class is our class with a static method, and Person.class contains our private method.

The first test testInitialize() behaves like any other Mockito test with the exception that we mock it using PowerMockito.mockStatic(IdentityUtilities.class) to initialize it. This makes testing static methods as easy as any other Mockito test.

The second test requires a little more explanation. In this case, we spy on the object we are creating. This allows us to instrument it. Then using the "spied" instance we use PowerMockito.when(instance, "generateId").thenReturn("UNIT-1A") to tell the framework that when the private method "generateId" is called, we want to return a specific value. Then we initialize the instance, and check the value is what we expected. Finally, we can optionally check to make sure that the method was actually called by using verifyPrivate(instance).invoke("generateId").

Conclusion

Don't short change yourself, and don't modify your beautifully architected code just to satisfy a testing framework. Find a framework like PowerMock to help you test your code as written instead. You should only change the code because you want to do so, or because you discover flaws in it.

Tuesday, October 15, 2013

JAX-RS Tip of the Day: JIRA and REST Client

Introduction

We are finishing up a release cycle at work. We have switched from Clearcase to Mercurial, and from a home grown bug tracking system to JIRA. We just released our latest software release on Monday, and its time to clean up the repo and JIRA.

Here is the situation. We chose for this release iteration to use a JIRA issue per branch approach. This worked for our situation where we had a number of new users to Mercurial, and JIRA. We could easily manage any issues with the build, or user mistakes. We will re-think the approach now that our team are up to speed on Mercurial.

We also implemented a server side Mercurial trigger that checked if the JIRA issue was assigned to the committer (person pushing to "master" repo). If not, they would not be able to push to the server. That way we could make sure that there were issues associated with check-ins.

So far, I think we did a good job since we yanked the rug from under the staff. QA finished their process and marked all of the JIRA issues closed. However, they don't have permissions to modify Mercurial to close the branches. That makes sense because they should be testing and not writing code. Now it is time to pay the piper.

We needed a mechanism to read the JIRA issues, look for the closed issues, assign them to a primary committer on JIRA with permissions on Mercurial, close the branch, and push to update the issue with a JIRA comment from the Mercurial check-in trigger. Got that?

Lets try that again...
  1. Read the JIRA issues and find all CLOSED issues.
  2. Read all of the Mercurial branches that are not closed. Remember the branches have the same name as the JIRA issue.
  3. Assign the JIRA issue to a primary committer.
  4. Switch to the branch and update
  5. Close branch and commit
  6. Push to "Master" server. This will not work unless the issue is assigned to primary committer since it has a commit trigger.
  7. The commit will update JIRA with the closed branch commit comments.

Are you still with me?

The code we wrote to do most of the work is proprietary. However, one aspect of it is worth sharing with the community. How do you assign a JIRA ticket to another user using the JIRA REST interface. The code below demonstrates how to do that.

Code

IssueAssignmentClient.java


App.java


Wednesday, September 11, 2013

JAX-RS 1.x Tip of the Day: Using POST with JAX-RS

http://commons.wikimedia.org
I was looking over some more unpublished code, and found a simple gem that demonstrates how to use a HTTP POST with JAX-RS and a @Singleton.

The code was originally developed with JAX-RS 1.0, but I went back and retrofitted it to work on JAX-RS 1.1. The code has a @Singleton that manages the "Widgets" that are created using the HTTP POST. It is a simple and fun example of what you can do with JAX-RS.

It is a simple application that creates "Widget" objects and returns JSON with the widget data.

The code for the project can be found here: jersey-post-example

Note: This example application needs to be run on GlassFish 3.1.2+ because of an issue with Guava GlassFish 4.

JSON Response


WidgetSingleton.java



ExampleResource.java



Widget.java


Thursday, April 25, 2013

JAX-RS Tip of the Day: How Do I Read the Authorization Header?

I was looking for a simple method to read the HttpHeaders to determine the username and password for a request. I didn't find a quick answer so I wrote a simple utility method that will return the Base 64 decoded values from the authorization header.

Saturday, January 05, 2013

Using GlassFish 3.1.1 Embedded with JUnit 4.x and HtmlUnit 2.x

Introduction

I was looking for an example of how to use GlassFish Embedded Maven plugin to integrate with HtmlUnit(JUnit) for doing testing. I was surprised that I really didn't find anything that seemed very complete. There were a number of examples that showed how to use the Embedded EJB Container in tests, but nothing that really showed how to use the Maven plugin. While searching I came across a question on stackoverflow asking how about Unit testing a Java Servlet. I decided to kill two birds with one stone; (1) write up a good example for Glassfish, and (2) help someone else with a complete solution

The testing here is implemented as part of the integration-test lifecycle of Maven. This does not replace standard JUnit testing of your code, but rather provides testing of your web application as you would expect in deployment. Consider this a valuable supplement to your testing strategy.

The complete project is located here: image-servlet.

Requirements

  1. First make sure that you configure the Maven plugin. Complete details can be found in Oracle GlassFish Server Embedded Server Guide
  2. Next, configure the surefire plugin to skip its normal test cycle.
  3. Add a dependencies for JUnit and HtmlUnit to the pom.xml
  4. Write your tests. This is one example.
  5. Execute mvn:install.

Conclusion

You should see the GlassFish server start, deploy your application, execute the unit tests, undeploy the application, and shutdown gracefully.

There is a complete project on Bitbucket which demonstrates the entire process from start to finish doing a complete set of integration tests using HtmlUnit.

The project was developed using NetBeans 7.2.1, and GlassFish 3.1.2.

The complete project is located here: image-servlet.

Java Tip of the Day: Converting an InputStream to a BufferedImage

I was looking for a standard way using the JDK to convert an InputStream into a BufferedImage as part of a JUnit test. The solution was quite simple using ImageIO.

Code

Saturday, November 10, 2012

WatchService Using ScheduledExecutorService Example

I was developing some code for the Java Certification Boot Camp project on Java.net where I wanted to demonstrate how to use the WatchService from JDK7 to monitor filesystem activity. I also wanted to demonstrate using it with an Executor.

As part of the process, I needed a graceful way to exit the program when the program completed. I thought that I would simply Google a solution, but I did not find one that met my needs.

So here is the use case I would like to have a WatchService running in its own thread and monitoring the filesystem. After a time period, I would like the service to shutdown gracefully.

I decided to use A ScheduledExecutorService which would start the WatchService using a Callable<V>, and another Runnable which was scheduled to shutdown the WatchService and the ScheduledExecutorService.

So here is how I did it.

WatchServiceImpl.java


Friday, November 02, 2012

Servlet 3.0 and JSF 2.x Tip of the Day: JSF Forward to External Servlet in Different Context

I posted a previous postServlet 3.0 Tip: How Do I Get to Another Servlet Context? which demonstrates how to get to another context. This extends that discussion by showing how to forward a JSF request to the other context and have the servlet output the results. Here is the basic code to be called from the JSF page.

Here is the method.

Here is the servlet I called.

CrossAppServlet.java



Success

Note: If you were going to pass it to JSF, you would need to remove the view state since the Faces Servlet receiving the values would result in a ViewExpiredException since this view state is not in the target Faces Servlet.

Thursday, November 01, 2012

Servlet 3.0 Tip: How Do I Get to Another Servlet Context?

This was a question I got tonight. It was a little more complicated prior to Servlet 3.0, but now it is very easy. In fact I almost thought it was not worth writing a post about it. Then I asked a friend in IM if he knew how to do it. It was so much more complicated, I decided to capitulate and post my response.

So how do I navigate to another web application on the server from my current application context?

Simple...

Dynamic Servlet Registration Example

Today I wanted to load a servlet dynamically, and decided to figure out how to do it. It turns out to be really simple.
I created a ServletContextListener and annotated it. In the contextInitialized() method, I set the servlet name, its class, and a mapping and we are done.

We can then deploy the project and watch the magic. Here is the Apache Maven project: dynamic-servlet.zip

ServletContextListenerImpl.java



ExampleServlet.java


Wednesday, October 31, 2012

Servlet 3.0 and HTML 5 File Upload Servlet Example

Someone asked how simple is it to create a servlet using 3.0 technology which could upload a file. It took me about 5 minutes to do using NetBeans 7.2, and another 10 minutes to tweak for the file name. I hope that this proves how quick and easy it is to do. The code is also very readable.

Here is the code for my servlet, and form:


Wednesday, August 22, 2012

Computing Time in a Method Call

Background

I was trying to do some comparisons on how fast a particular algorithm was calculating Checksum values. In my case, I have Adler32, CRC32, and PureCrc32 (Apache Hadoop) to check. This is my particular case, but in general this question comes up for a number of cases; performance optimization being one of them. Since we are calculating the Checksum on files, the problem is complicated by I/O considerations. File caching, and operating system constraints (resources) being the big ones. So how do most people do it?


The Ugly Truth

The general methodology that most developers use is to wrap the method call of interest with start and end time variables, and calculate the difference. They may repeat the process a couple of times, and average it. If they are fancy, they may randomly execute the method to provide some variance. This pseudo randomness gives the feel of more objective results.

Does it work?

The truth is about precision. This will give you a rough time frame. Perhaps that is all you need. My college mathematics profession, Dr. Alden Monberg, always talked about scale and precision. A tolerance of ± 25mm may work on a ship section weighing a 50 MT., but the same value on a pacemaker, or heart value would be unacceptable. A precision of ± 10nm would work for the heart value, but would be impossible for the ship.

Getting nanometer precision (or nanosecond in our case)

The results from the calculations above will give "thumb in the air" results, but is too imprecise to be useful when you may be calculating 10,000 file, or 10,000,000 files. The overhead of the method call is lost in the I/O, but it still there. The greater the number of files, the more optimized the algorithm, the less time it consumes. We can't control the I/O per se, so lets control our algorithm.

Take a different approach

We still want to do the calculation, but we want to do it on the void update(byte[] b, int off, int len) method which is the root of our algorithm being called. I decided to try to use AOP, and try to wrap the method invocation. I know there are some folks who use Spring, but I do not. I wanted to use an AOP framework directly instead of using it wrapped in Spring. I tried a number of frameworks to see which one I thought would be the least invasive and easiest to use.
After trying all of them, I found that Guice was the easiest to use. I was not able to use it directly out of the box though. The "preferred" method for Guice is to annotate the classes you want to test. In my case, I can not annotate the JDK, nor Hadoop classes. So I had to use another methodology which I will detail.

How do you do it?

I had not originally considered Guice until I found this blog post: Guice Tutorial – part 2: method interception which details performing method interception. This was the jackpot find that got me on track. The example code on that tutorial has the methodology which I used. However, it falls a little short because Guice does not have method matcher which matches on the method name. A little more searching came up with an issue/enhancement posted in Issue tracker for Guice. Issue #164 method name matcher enhancement. The issue is closed as a WONTFIX, but the submitter (Aaron Whiteside) proposed some code to do it. I modified the code slightly, but it was a near perfect fit. Google Groups has an explanation why Bob Lee thinks it is a bad idea: Guice/AOP - intercepting a method thanks to its name. I disagree, but that is his choice. The code Aaron mostly works, and my code below does work. So be it. OK, so we now have most of the pieces in place. The cool thing about this method is that we can use it anywhere. I am going to use it on a JUnit test like the tutorial in my code, but it is very general. So here is what I needed:
  1. A MethodInterceptor implementation
  2. A Matcher implementation
  3. An AbstractModule implementation
  4. A JUnit test

Code

TimingInterceptor.java


MethodCalledMatcher.java


AbstractModuleImpl.java


ChecksumTest.java


Results

However one test does not tell the whole story. When I actually ran this as a more general performance calculation. The results were on curves. On small files like the 10MB one in my test, the Adler32 was fastest. The PureCrc32 code performed the best as the file sizes got larger. Please don't accept the output here as a performance test without considering other factors. It is cool though that we got more precise results rather than brute force attempting it.

Friday, July 27, 2012

JAX-RS Tip of the Day: Basic Client Authentication

This is the second part of the JAX-RS Tip of the Day: Basic Authentication with JDBC. If you have not already done the pre-requisites, please examine the other article first.

Abstract

Unless you are developing a public service where authentication is not required like weather, or time services. This means that you will require authentication, and authorization. This application demonstrates how to perform basic authentication. This may be all that is required for your application, as long as, it is operating in a secure environment, or using secure transport (HTTPS).

Technical Details

If you have already completed creating a secure service, then you will really like how easy it is to create a basic authentication client for that service.

Requirements

As you can see from the code below. The most important item is to add a HTTPBasicAuthFilter to allow you to authenticate. Its that simple... really.

ExampleResourceClient.java


package com.bluelotussoftware.jersey;

import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.filter.LoggingFilter;

/**
 * REST Basic Authentication Client Application
 *
 * @author John Yeary
 * @version 1.0
 */
public class BasicAuthenticationClient {

    public static void main(String[] args) {
        ExampleResourceClient erc = new ExampleResourceClient();
        erc.setUsernamePassword("jyeary", "test");
        System.out.println(erc.getMessage());
        erc.close();
    }

    static class ExampleResourceClient {

        private com.sun.jersey.api.client.WebResource webResource;
        private com.sun.jersey.api.client.Client client;
        private static final String BASE_URI = "http://localhost:8080/secure-jdbc-rest-service/resources";

        public ExampleResourceClient() {
            com.sun.jersey.api.client.config.ClientConfig config = new com.sun.jersey.api.client.config.DefaultClientConfig();
            client = com.sun.jersey.api.client.Client.create(config);
            client.addFilter(new LoggingFilter());
            webResource = client.resource(BASE_URI).path("example");
        }

        public String getMessage() throws com.sun.jersey.api.client.UniformInterfaceException {
            WebResource resource = webResource;
            return resource.accept(javax.ws.rs.core.MediaType.TEXT_PLAIN).get(String.class);
        }

        public void putMessage(Object requestEntity) throws com.sun.jersey.api.client.UniformInterfaceException {
            webResource.type(javax.ws.rs.core.MediaType.TEXT_PLAIN).put(requestEntity);
        }

        public void close() {
            client.destroy();
        }

        public void setUsernamePassword(String username, String password) {
            client.addFilter(new com.sun.jersey.api.client.filter.HTTPBasicAuthFilter(username, password));
        }
    }
}

Thursday, July 26, 2012

JAX-RS JUG Demo CDI and @Singleton Usage

This is the last demonstration I gave at the Greenville Java Users Group (GreenJUG) on CDI and JAX-RS. I cleaned up the code, but not as much as you would think. I managed to code this in about 15 minutes during the meeting live while everyone watched. It was a fun experience, but the best part is that it worked during a live un-rehearsed demo.

It goes to show you that CDI and JAX-RS are simple enough in combination to use in a live high stress demo environment. Imagine what it could do for you in your code. This code was written using NetBeans 7 IDE which may be responsible for the simplicity as much as the other technologies.

Here is the source code: cdi-example.zip

The code below demonstrates some interesting bits. The source code above contains the less interesting POJOs.

PersonResource.java



PersonDB.java


JAX-RS JUG Demo Examples (@QueryParam and @PathParam)

I gave a demo of JAX-RS using @QueryParam and @PathParam annotations, and created a client to connect with the resources and display the results. I promised to post the code. So here it is along with some cleanup.

Here are the Apache Maven projects and code:
simple-queryparam-example.zip
simple-queryparam-client-example.zip

Example.java



SimpleExampleClientApplication.java


Wednesday, July 25, 2012

JAX-RS Tip of the Day: Basic Authentication with JDBC

Abstract

Unless you have a public API like a weather service, or perhaps barometric pressure measurements. You will likely need some form of authentication, and authorization for your service. A tried and tested mechanism is to use JDBC Realm based authentication. In this example I will create  a set of database tables on Apache Derby, set up the security realm on GlassFish 3.1.2.2, and configure basic authentication on a RESTful web service. The majority of the work will be done using the NetBeans IDE 7.2.

Requirements

Database

The first thing we need to do is to set up our database tables which we will use for authentication. These tables can contain more information, but in my example I will keep them simple.

Creating Tables

First we will need to create a Users table which will contain our username and password. Using the sample database in NetBeans do the following:
  1. Select the Services Window, and open the Databases selection
  2. Right click on the Java DB icon, and start the server if it is not already started
  3. Right click on the sample database connection: jdbc:derby://localhost:1527/sample [app on APP] and connect.
  4. Right click on the sample connection and select Execute Command.
  5. Execute the create table commands and create index commands below.
CREATE TABLE users ( username varchar(255) NOT NULL, password varchar(255) DEFAULT NULL, PRIMARY KEY (username) );
CREATE TABLE groups ( username varchar(255) DEFAULT NULL, groupname varchar(255) DEFAULT NULL);
CREATE INDEX groups_users_idx ON groups(username ASC);
Create Tables

Add Users and Groups

We need to add at least one user and group to our table. Since I am using GlassFish as the container, I will use SHA-256 to hash my password. That way it is not visible in plain text.
  1. Right click on our new USERS table, and select View Data
  2. Click on the Insert Records Icon
  3. Add a user, and add a SHA-256 hash of the password.
    Note:An online generator can be found at SHA-256 hash calculator
  4. Repeat the same process as above to open the GROUPS table
  5. Add the username and a group called users
That completes all we need for our JDBC authentication.

GlassFish JDBC Realm

Using the NetBeans IDE perform the following:
  1. Go to the Services window and expand the Servers selection.
  2. Right click on GlassFish 3.1.2 server and select Start.
  3. Right click and select View Domain Admin Console.
  4. On the Admin console web page on the tree on the left select Configurations » server-config » Security » Realms.
  5. Add a new realm called jdbc with the following properties:
    • Name: jdbc
    • Class Name: com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm
    • JAASContext: jdbcRealm
    • JNDI: jdbc/sample
    • User Table: users
    • User Name Column: username
    • Password Column: password
    • Group Table: groups
    • Group Table User Name Column: username
    • Group Name Column: groupname
    • Database User: app
    • Database Password: app
    • Digest Algorithm: SHA-256
    • Encoding: Hex
    • Charset: UTF-8

    Note: the parameters are case sensitive.
  6. Navigate to Configurations » server-config » Security
  7. Change the Default Realm to jdbc
  8. Check the Default Principal To Role Mapping checkbox to enabled
  9. Click Save and Restart server.
The security mapping configuration for automatic mapping makes it so that our application will not require a glassfish-web.xml file as part of our deployment.

JAX-RS Application

Finally we have completed all of the requirements on the server side for securing our applications. This security mechanism can be used by more than the application we will are preparing to deploy. We need to set up the security constraints in our web.xml file as shown below. If you have downloaded the code you can simply open it in NetBeans and examine it.

web.xml


Using NetBeans, you can simply run the application and it will prompt you for an application server. Select the current GlassFish server we have set-up, and it will deploy in a few seconds. You will come to a index.jsp page.
Click on the link for the application.wadl, or navigate to http://localhost:8080/secure-jdbc-rest-service/resources/example and you will be prompted to login. Once you login, you should get this message from the REST service.
This is an example message

Sunday, July 08, 2012

JAX-RS Simple XML Service and Client Example

I thought that I would publish the information and code from a recent JUG meeting where I coded some simple JAX-RS examples on the fly to show how easy it can be to create RESTful web services.

This particular code for the service and client are nothing fancy, but I told the JUG members that I would publish it when I got a chance.

Code

The Apache Maven based projects were developed using the NetBeans 7 IDE and GlassFish 3.1.2. You will need to run the simple-xml-example project first before you can run the client application.

The code for the projects can be downloaded here: simple-xml-example.zip and simple-xml-example-client.zip

ExampleResource.java



SimpleXMLExampleClient.java


Friday, January 20, 2012

JAX-RS Tip of the Day: Use GZIP compression

JAX-RS (Jersey) offers a GZIP filter to compress data for responses, and to handle GZIP compressed requests. This functionality is very easy to enable, and is configurable for both requests, and responses. That does not get much easier.


 You can prove that this works by querying your resource with Firebug, or Developer Tools (depending on browser). You can also confirm that it is working by performing a query like:
curl -HAccept-Encoding:gzip -HAccept:application/json http://localhost:8080/content-coding-gzip/webresources/widget > json.gz
gzip -v -l json.gz
method  crc     date  time           compressed        uncompressed  ratio uncompressed_name
defla 3a79ae18 Jan 20 15:25                1370                3389  60.3% json

The only issue that I have with the currently implemented version is that it does not use configurable compression level.

Tuesday, January 17, 2012

JAX-RS Tip of the Day: Use OPTIONS Method to Determine Resource Capabilities

Did you know that you can make an OPTIONS method call to a JAX-RS resource to determine its capabilites? JAX-RS supports a complete set of HTTP methods including OPTIONS.

If you make a specific URI request to a resource, it will return the supported methods like GET, PUT, HEAD, and OPTIONS. In addition, Jersey supports returning the WADL file by default. This allows tools like NetBeans to take advantage of the resource.

So I guess some examples are in order. The first example is a request to the server URI which in this case is GlassFish 3.1.1. This is followed by a request to a specific resource on the server instance.
curl -X OPTIONS -v http://localhost:8080
* About to connect() to localhost port 8080 (#0)
*   Trying ::1... Operation not permitted
*   Trying 127.0.0.1... connected
> OPTIONS / HTTP/1.1
> User-Agent: curl/7.22.0 (i686-pc-cygwin) libcurl/7.22.0 OpenSSL/0.9.8r zlib/1.2.5 libidn/1.22 libssh2/1.2.7
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Powered-By: Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 3.1.1 Java/Sun Microsystems Inc./1.6)
< Server: GlassFish Server Open Source Edition 3.1.1
< Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS
< Content-Length: 0
< Date: Tue, 17 Jan 2012 14:31:17 GMT
<
* Connection #0 to host localhost left intact
* Closing connection #0
As you can see the command reports that GlassFish supports all standard HTTP 1.1 methods as denoted by the Allow: header. This example calls a specific resource on the server which only supports a subset of the HTTP methods based on the annotations in the resource. The methods always supported by a resource are HEAD and OPTIONS, but this has two methods annotated as @GET and @POST. Additionally, not that the Content-Type: application/vnd.sun.wadl+xml is returned which includes the WADL for this particular resource.
curl -X OPTIONS -v http://localhost:8080/RESTApproachFormParameter/resources/example
* About to connect() to localhost port 8080 (#0)
*   Trying ::1... Operation not permitted
*   Trying 127.0.0.1... connected
> OPTIONS /RESTApproachFormParameter/resources/example HTTP/1.1
> User-Agent: curl/7.22.0 (i686-pc-cygwin) libcurl/7.22.0 OpenSSL/0.9.8r zlib/1.2.5 libidn/1.22 libssh2/1.2.7
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Powered-By: Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 3.1.1 Java/Sun Microsystems Inc./1.6)
< Server: GlassFish Server Open Source Edition 3.1.1
< Allow: OPTIONS,POST,GET,HEAD
< Content-Type: application/vnd.sun.wadl+xml
< Content-Length: 1085
< Date: Tue, 17 Jan 2012 15:01:49 GMT
<
* Connection #0 to host localhost left intact
* Closing connection #0
In summary, you can take advantage of the OPTIONS method to determine what a particular resource will provide for you without any knowledge of the subject domain.

Popular Posts