Tuesday, September 27, 2016

How to connect LDAP server using Spring framework ? or How to perform search operation in ldap using spring ?



In the following post we will look in to

  • How to connect LDAP server using Spring framework 
  • Simplify directory access with Spring LDAP
  • Using Spring LdapTemplate.
  • How to perform search operation in ldap using spring ?
  • Introduction to Spring LDAP ?
  • How to use Spring with LDAP ?


First I will show a simple example of how to connect to LDAP using plain java that way you will appreciate Spring LDAP template even better.
There are several threads online on this subject. I adding this article so that i can provide more details on how to use 
spring provide LDAP filters. 

Ok lets start with simple Java approach first.
A simple interface that returns users we are looking for as list of Strings or as list of java objects.
Here is the code to do that lets call this class TraditionalLDAPUserRepoImpl.java and the interface as LDAPUserRepo .java

Interface LDAPUserRepo.java
package com.rama.util.activedirectory;
import java.util.List;

public interface  LDAPUserRepo {
 
 /*  Just return usernames that matches your LDAP query criteria. Just as list of Strings*/
 public List<String> getAllPersonNames();
 
 /* This method will return list of java objects  with user name, email etc */
 public List<LDAPUser> getAllPersonNameObjs();
}
Code that show implementation of TraditionalLDAPUserRepoImpl.java
Needless to say you need to change you ldap address and credentials.
// A simple lookup using plain Java 
package com.rama.util.activedirectory;

import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;

import javax.naming.Context;
import javax.naming.NameNotFoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

public class TraditionalLDAPUserRepoImpl implements LDAPUserRepo {

 public List<String> getAllPersonNames() {
  Hashtable<String, String> authEnv = new Hashtable<String, String>();
  authEnv.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
  //https://docs.oracle.com/javase/8/docs/technotes/guides/jndi/jndi-ldap-gl.html
  authEnv.put(Context.PROVIDER_URL, "ldap://dev.rama.int:389/DC=DevS1,DC=int");
     authEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
  //Your  security principla could be different
     authEnv.put(Context.SECURITY_PRINCIPAL,"CN=rama,OU=Service_Account,DC=DevS1,DC=int");
     authEnv.put(Context.SECURITY_CREDENTIALS,"test123");
     
     //https://docs.oracle.com/javase/8/docs/technotes/guides/jndi/jndi-ldap-gl.html
     //authEnv.put("java.naming.ldap.referral.limit","10");
     //https://docs.oracle.com/javase/jndi/tutorial/ldap/referral/jndi.html
     //authEnv.put(Context.REFERRAL,"follow");
     //For example, the following code specifies that the provider should block until 24 entries have been read from the server or until the enumeration terminates, whichever produces the fewer number of results:
     //authEnv.put(Context.BATCHSIZE,"400");
      
  DirContext ctx;
  try {
   ctx = new InitialDirContext(authEnv);
  } catch (NamingException e) {
   throw new RuntimeException(e);
  }

  List<String> list = new LinkedList<String>();
  NamingEnumeration results = null;
  try {
   SearchControls controls = new SearchControls();
   controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
   
   /*
    If you comment out the below line all properties will  be pulled.
    Here just to show I am explicitly mentioning the properties we want.
    sn- Simple name
    CN- complete name
    OU - organizational unit.
    
    Think of this as a oracle select statement with the columns you wanted listed in select clause 
   */
   controls.setReturningAttributes(new String[] {"sAMAccountName","givenName", "sn","memberOf" ,"CN","OU","name"});
   
   
   /* 
    This is the condition or filter that will be applied to pull results.
    This is more like where clause in your SQL statement.
    BEWARE: If you give more generic  search criteria then you will have too many records and may get errors.
    Its good practice to restrict or narrow down results to smaller subsets.
   */
   
   results = ctx.search("", "(objectclass=person)", controls);
   
   System.out.println(results);
   while (results.hasMore()) {
    SearchResult searchResult = (SearchResult) results.next();
    Attributes attributes = searchResult.getAttributes();
    //Ok lets pick few that we are interested.
    Attribute memeberOfAttr = attributes.get("memberOf");
    Attribute cnAttr = attributes.get("CN");
    Attribute nameAttr = attributes.get("name");
    Attribute samaAccountNameAttr = attributes.get("sAMAccountName");
    list.add(cnAttr.toString());
    
    
    //Debug only ...
    dumpAll(attributes);
    
    //memberOf in my case can be 1 to many .... So just show hot to pull if we have a collection of 
    //same attribute in LDAP.     
    if(memeberOfAttr!=null){
     String memeberOfStr = "";
     try{
      memeberOfStr = getAllValues(memeberOfAttr);
     }catch(Exception exp){
      exp.printStackTrace();
     }
     System.out.println("samaAccountName="+ samaAccountNameAttr+"| cnAttr="+ cnAttr  +" | name="+nameAttr +" | memeberof="+ memeberOfStr);
    }
    
   }
  } catch (NameNotFoundException e ) {
   // The base context was not found.
   // Just clean up and exit.
  } catch (NamingException e) {
   throw new RuntimeException(e);
  } finally {
   if (results != null) {
    try {
     results.close();
    } catch (Exception e) {
     // Never mind this.
    }
   }
   if (ctx != null) {
    try {
     ctx.close();
    } catch (Exception e) {
     // Never mind this.
    }
   }
  }
  return list;
 }


 private void dumpAll(Attributes attributes) throws NamingException {
  NamingEnumeration<? extends Attribute>  allAttr= attributes.getAll();
  while (allAttr.hasMoreElements()) {
   Attribute attribute = (Attribute) allAttr.nextElement();
   if((attribute.getAll()!= null) &&(attribute.getAll().hasMoreElements())){
    //Ok this Attributes can have one or more values.
    NamingEnumeration<?>  childAttr= attribute.getAll();
    while(childAttr.hasMoreElements()){
     System.out.println("Property="+ attribute.getID() +" Value="+ childAttr.next());
    }
   }else{
    System.out.println("Not All="+ attribute.get().toString());
   }
  }
 }
 
 public List<LDAPUser> getAllPersonNameObjs(){
  // I will show the demo later.
  return null;
 }
 
 
 /*
   Here memeberOf can have many rows.
   memberOf: CN=SCHOOL_MAINT_FULL,OU=Security_Groups_Distribution_Lists,DC=DevS1,DC=int
   memberOf: CN=REPORT_FULL,OU=Security_Groups_Distribution_Lists,DC=DevS1,DC=int
   memberOf: CN=LOAN_APP_FULL,OU=Security_Groups_Distribution_Lists,DC=DevS1,DC=int
   memberOf: CN=DISB_MAINT_READ,OU=Security_Groups_Distribution_Lists,DC=DevS1,DC=int
  */
 
 public static String getAllValues(Attribute attribute)throws Exception {
  StringBuffer sbuf = new StringBuffer();
  NamingEnumeration<?>  childAttr= attribute.getAll();
  while(childAttr.hasMoreElements()){
   Object obj = childAttr.next();
   sbuf.append("id="+ attribute.getID()+" Value="+ obj.toString()+"\n");
  }
  
  return sbuf.toString();
 }
 
 public static void main(String[] args) {
  LDAPUserRepo personRepo = new TraditionalLDAPUserRepoImpl();
  personRepo.getAllPersonNames();
 }
}

 


Exceptions:.
===========
Some times you will see exceptions like below which indicates that your search query is returning more results and LDAP server may have size restrictions.
The best thing to do is to change you were clause to limit the result set. I have notice that Spring LDAP template was able to fetch more records than plain java solution.

Exception in thread "main" java.lang.RuntimeException: javax.naming.SizeLimitExceededException: [LDAP: error code 4 - Sizelimit Exceeded]; remaining name ''at com.rama.util.activedirectory.TraditionalLDAPUserRepoImpl.getAllPersonNames(TraditionalLDAPUserRepoImpl.java:87)
at com.rama.util.activedirectory.TraditionalLDAPUserRepoImpl.main(TraditionalLDAPUserRepoImpl.java:151)
Caused by: javax.naming.SizeLimitExceededException: [LDAP: error code 4 - Sizelimit Exceeded]; remaining name ''

NOTE:
=====
For troubleshooting and also to just to view I use LDAP browser from Softterra (Google it). Its FREE. (Don't use "LDAP administrator" from softteraa thats a paid one)
Here is snapshot for my user id when I look it up through LDAP browser.
(Here is the link at the time I was writing this blog http://www.ldapadministrator.com/softerra-ldap-browser.htm)

Now the same thing can be done using Spring LdapTemplate.
---------------------------------------------------------
The beauty of Spring ldap template is you can filter data using AndFilter , OrFilter , LikeFilter.
Please see spring package org.springframework.ldap.filter.* for all filters.
The below code will show you how to use filters.

Ok lets create the maven java project.Here is the maven pom.xml.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>

 <groupId>com.rama.activedirectory</groupId>
 <artifactId>FMActiveDirectory</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>
 <name>FMActiveDirectory</name>
 <url>http://maven.apache.org</url>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.1</version>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupId>org.springframework.ldap</groupId>
   <artifactId>spring-ldap-core</artifactId>
   <version>2.0.4.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>org.springframework.data</groupId>
   <artifactId>spring-data-commons-core</artifactId>
   <version>1.4.1.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>commons-lang</groupId>
   <artifactId>commons-lang</artifactId>
   <version>2.6</version>
  </dependency>
 </dependencies>
</project>

Now we need to return as java object so lets create a POJO to get the values.

I will add few properties feel free to enhance it.


package com.rama.util.activedirectory;
import java.util.List;

public class LDAPUser {
 private String sAMAccountName ;
 private String name;
 private String givenName;
 private String canonicalName;
 private List<String> memberOfValueList  = new ArrayList<String>();
 
 // Removed getter and setters for clarity, Please generate it.
 
}

Spring configuration.
===================
Here is how the spring xml looks. I called it spring-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:ldap="http://www.springframework.org/schema/ldap"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/ldap http://www.springframework.org/schema/ldap/spring-ldap.xsd">

   <ldap:context-source
       id="ldapcontextSource" 
          url="ldap://dev.rama.int:389/DC=DevS1,DC=int"  base="DC=DevS1,DC=int"
          username="CN=rama,OU=Service_Account,DC=DevS1,DC=int"  password="test123" />

 <ldap:ldap-template id="ldapTemplate"  context-source-ref="ldapcontextSource"/>

   <bean id="ldapUserRepoBean" class="com.rama.util.activedirectory.SpringTemplateLDAPUSerRepoImpl">
      <property name="ldapTemplate" ref="ldapTemplate" />
   </bean>
</beans> 
Make sure this spring xml file is in your classpath.
Now we need to implement our LDAPUserRepo interface.In order to convert the result set back to java object we need to also implement AttributesMapper interface. Please see the code below.

The code several filters that you can use like AndFilter , OrFilter, LikeFilter etc,
See package "org.springframework.ldap.filter.*" for more filter Options.

SpringTemplateLDAPUSerRepoImpl.java
--------------------------------

package com.rama.util.activedirectory;
import static org.springframework.ldap.query.LdapQueryBuilder.query;

import java.util.ArrayList;
import java.util.List;

import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.OrFilter;
import org.springframework.ldap.query.LdapQuery;

public class SpringTemplateLDAPUSerRepoImpl implements LDAPUserRepo  {

  private LdapTemplate ldapTemplate;

  public void setLdapTemplate(LdapTemplate ldapTemplate) {
      this.ldapTemplate = ldapTemplate;
   }
    
 /**
  * No Attribute mapper. Simple pull of each property.
  * 
  * @return
  */
 public List<LDAPUser> getAllPersonNameObjs(){
  
  
  //NOTE: Spring doesn't throw javax.naming.SizeLimitExceededException:. Though it cant fetch 
  // all records its remains siletnt.
  // OOPS this is too broad. It may get all memebers from LDAP. But there is a limitation of 1000 in 
  // my case and Spring ldap template pulls thousand and keeps Quite. No exceptions 
  
  LdapQuery query = query().where("objectclass").is("person");
  ldapTemplate.setIgnorePartialResultException(true);
  return ldapTemplate.search(query,new LDAPUSerAttributesMapper());
  
  
  //TO Return reduced result set I tried this to search based on one of the groups the user belongs to. 
  //LdapQuery query = query().where("memberOf").is("CN=DEV_ADMIN_FULL,OU=Security_Groups_Distribution_Lists,DC=DevS1,DC=int");
  //ldapTemplate.setIgnorePartialResultException(true);
  //return ldapTemplate.search(query,new LDAPUSerAttributesMapper());
  
  
  
  //AndFilter andFilter = new AndFilter();
      //andFilter.and(new EqualsFilter("objectclass","person"));
      //andFilter.and(new EqualsFilter("cn",firstName));
      //andFilter.and(new EqualsFilter("sn",lastName));
      //andFilter.and(new EqualsFilter("ou","User_Accounts"));
   //System.out.println("LDAP Query " + filter.encode());
      //ldapTemplate.setIgnoreSizeLimitExceededException(true);
      //ldapTemplate.setIgnorePartialResultException(true);
         //return ldapTemplate.search("",filter.encode(),new LDAPUSerAttributesMapper());
      
   
  //OrFilter filter = new OrFilter();
    //filter.or(new EqualsFilter("objectclass","person"));
    //filter.or(new EqualsFilter("name","Consultants_Contractors_Temps"));
    //distinguishedName: CN=Ramachandra Reddy,OU=Consultants_Contractors_Temps,OU=User_Accounts,DC=DevS1,DC=int
    //filter.or(new EqualsFilter("distinguishedName","CN=Ramachandra Reddy,OU=Consultants_Contractors_Temps,OU=User_Accounts,DC=DevS1,DC=int"));
   //System.out.println("LDAP Query " + filter.encode());
      //ldapTemplate.setIgnoreSizeLimitExceededException(true);
      //ldapTemplate.setIgnorePartialResultException(true);
         //return ldapTemplate.search("",filter.encode(),new LDAPUSerAttributesMapper());
      
   
  //LikeFilter filter = new LikeFilter("memberOf","CN=DEVS1_DEV_Inhouse_SecGroup,OU=Security_Groups_Distribution_Lists,DC=DevS1,DC=int");
   //OrFilter filter = new OrFilter();
   //filter.or(new EqualsFilter("memberOf","CN=DEVS1_DEV_Inhouse_SecGroup,OU=Security_Groups_Distribution_Lists,DC=DevS1,DC=int"));
   //filter.or(new EqualsFilter("memberOf","CN=LOS_ADMIN_FULL,OU=Security_Groups_Distribution_Lists,DC=DevS1,DC=int"));
      //System.out.println("LDAP Query " + filter.encode());
      //ldapTemplate.setIgnoreSizeLimitExceededException(true);
      //ldapTemplate.setIgnorePartialResultException(true);
         //return ldapTemplate.search("",filter.encode(),new LDAPUSerAttributesMapper());
      
   
 }
 
 
 public List<String> getAllPersonNames() {
       return ldapTemplate.search(
          query().where("objectclass").is("user"),
          new AttributesMapper<String>() {
             public String mapFromAttributes(Attributes attrs)
                throws NamingException {
                return (String) attrs.get("cn").get();
             }
          });
   }
 
 /*
  This is how you map your results back to a 
  Java object
 
 */
  private class LDAPUSerAttributesMapper implements AttributesMapper<LDAPUser> {
       public LDAPUser mapFromAttributes(Attributes attrs) throws NamingException {
       LDAPUser person = new LDAPUser();
          person.setsAMAccountName(getValue(attrs.get("sAMAccountName")));
          person.setName(getValue(attrs.get("name")));
          person.setGivenName(getValue(attrs.get("givenName")));
          person.setCanonicalName(getValue(attrs.get("canonicalName")));
          try {
       //Special handling to pull this property as it can  be one to many.
    person.setMemberOfValueList(getAllValues(attrs.get("memberOf")));
   } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
          return person;
       }
    }
  
  /**
   * Checks for null and accordingly gets String value of the attribute.
  * @param attr
  * @return
  * @throws NamingException
  */
 private static String getValue(Attribute attr)throws NamingException{
   if((attr!= null) &&(attr.get() != null)){
     return (String)attr.get();
   }
    return "";
  }
 
 private static void dumpAll(Attributes attributes) throws NamingException {
  NamingEnumeration<? extends Attribute>  allAttr= attributes.getAll();
  while (allAttr.hasMoreElements()) {
   Attribute attribute = (Attribute) allAttr.nextElement();
   System.out.println("All="+ attribute.get().toString());
  }
  
 }
 
 
 public static List<String> getAllValues(Attribute attribute)throws Exception {
  List<String> valueList = new ArrayList<String>();
  if(attribute != null){
   NamingEnumeration<?>  childAttr= attribute.getAll();
   while(childAttr.hasMoreElements()){
    Object obj = childAttr.next();
    //System.out.println("id="+ attribute.getID()+" Value="+ obj.toString()+"\n");
    valueList.add(obj.toString());
   }
  }
  return valueList;
 }
 
 public static void main(String[] args) {
          Resource resource = new ClassPathResource("/spring-config.xml");
          BeanFactory factory = new XmlBeanFactory(resource);
          LDAPUserRepo ref = (LDAPUserRepo) factory.getBean("ldapUserRepoBean");
          System.out.println(ref.getAllPersonNameObjs());
          System.out.println("Done.");
 }
}

As shown the ldaptemplate is much easier and has more flexibility so that we can use many filters, nest the filters to restrict data from  LDAP active directory. So needless to say Spring approach is much easier.


Sunday, January 04, 2015

Building RESTful Web Services or RESTful Web Services with Java


The below article will show examples of building Simple RESTful Web Services, Restful web service for file upload, Restful web service for file download

  • Building RESTful Web Services with JAX-RS using Jboss rest easy API.
  • RESTful Web Services with Java
  • RESTful Java client with Jboss RESTEasy client framework
  • RESTEasy client for consuming REST APIs
  • Pure java client to invoke Restful web service
  • Using Firefox rest client for testing restful web services.
  • RestEasy client for file upload
  • RestEasy client for file download


I used Jboss rest easy API, You can also use Jersey api to build restful web services.
Lets say we need a restful web service which does the following

  • Employee service - To Create,Get,Update and Delete an employee object.
  • File Service - To upload and download a file.
  • Resteasy client  to download a file (ZIP, PDF...etc)
  • Resteasy client  to upload files (ZIP, PDF...etc)

Java code for building Employee Service

Lets build a java object for Employee object which is JAXB enabled. Let use JAXB annotations.

package com.rama.restful;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

/*****
 *   XmlAccessType.NONE --> Tell JAXB not use field name as it's in the class. 
 *                         Instead we will give the names that as to be used  when generating XML. 
 *    
 *     Ideally keep this in common package so that you can share between java client and server                    
 ***/
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name = "employee")
public class Employee {


    @XmlAttribute(name = "id")
    private int Id;
 
    @XmlAttribute(name="uri")
    private String uri;
 
    @XmlElement(name = "firstName")
    private String firstName;
 
    @XmlElement(name = "lastName")
    private String lastName;
    
 public int getId() {
  return Id;
 }
 public void setId(int id) {
  Id = id;
 }
 public String getFirstName() {
  return firstName;
 }
 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }
 public String getLastName() {
  return lastName;
 }
 public void setLastName(String lastName) {
  this.lastName = lastName;
 }
 public String getUri() {
  return uri;
 }
 public void setUri(String uri) {
  this.uri = uri;
 }
 
 
 
}
A list of employee's is wrapped in a Employees Object as shown below.

package com.rama.restful;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name = "employees")
public class Employees {

 //Will embed every object in the list with <employee> tag. 
 @XmlElement(name="employee") 
 private List<Employee> employees = new ArrayList<Employee>();

 public List<Employee> getEmployees() {
  return employees;
 }

 public void setEmployees(List<Employee> employees) {
  this.employees = employees;
 }
}

Now lets create EmployeeService which is the restful web service which will use the objects we created above.We will be adding the following methods which can be invoked on this web service.

  • public Response createEmployee(..)
  • public Response deleteEmployee(..)
  • public Employees getAllemployees()
  • public Employee getEmployeeById(..) - Returns XML respsonse.
  • public Employee getEmployeeByJsonId(..) - Returns JSON response
  • public EmployeeService getServiceInfo() - Returns basic info about this webservice
  • public Employee updateEmployee(..)
Frankly we don't need JAXB annotations (@XmlAccessorType and @XmlRootElement), Since getServiceInfo returns some info on this object as XML we added this tags to this class as well.
As you see the comments on each section you will see that each method is self explanatory.
Each method is marked by annotations which indicate the 
  • @Path - The url you need to access this method 
  • @GET,@PUT,@POST - Indicating the HTTP method type you need to use to access the give method
  • @Consumes -  Indicates if the method accepts XML or JSON
  • @Produces - Indicates if the method returns XML or JSON response.
These are key annotations that you need to know to build restful web services.

package com.rama.restful;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

/**
* 
*  To test use this URL 
*  http://localhost:8081/RESTfulDemoApplication/employeeService/employees  ( Your port could be different)
*
**/
//For  fun we can make even this class JAXB enabled to list out the services...
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name = "employeeService")

@Path("/employeeService")
public class EmployeeService {
 
 @XmlElement(name = "employees")
 private String uri1 = "/employeeService/employees";
 
 
 
 public String getUri1() {
  return uri1;
 }

 public void setUri1(String uri1) {
  this.uri1 = uri1;
 }

 
 
 /**
  * Use the below url to access this
  * http://localhost:8081/RESTfulDemoApplication/employeeService ( Your port could be different)
  * 
  * 
  * OUTPUT: Just prints 
  * 
  * <employeeService>
  *    <employees>/employeeService/employees</employees>
  *    
  * </employeeService>
  * 
  **/
 @GET
 @Path("/")
 @Produces("text/xml;charset=UTF-8")
 public EmployeeService getServiceInfo() {
  return new EmployeeService();
 }

 
 
 
 /**
  * Use the below url to access this
  * http://localhost:8081/RESTfulDemoApplication/employeeService/employees ( Your port could be different)
  * 
  * OUTPUT:
  * 
   *  <employees>
    <employee id="1" uri="/employeeService/employees/1">
     <firstName>Rama</firstName>
     <lastName>chandra</lastName>
    </employee>
    <employee id="2" uri="/employeeService/employees/2">
     <firstName>John</firstName>
     <lastName>Smith</lastName>
    </employee>
   </employees>
  * 
  * 
  * 
  **/
 @GET
 @Path("/employees")
 @Produces("text/xml;charset=UTF-8")
 public Employees getAllemployees() {
  
  //Ideally you will go to database to pull this info..
  
  Employee employee1 = new Employee();
  employee1.setId(1);
  employee1.setFirstName("rama");
  employee1.setLastName("chandra");
  employee1.setUri("/employeeService/employees/1");

  Employee employee2 = new Employee();
  employee2.setId(2);
  employee2.setFirstName("John");
  employee2.setLastName("smith");
  employee2.setUri("/employeeService/employees/2");

  Employees employees = new Employees();
  employees.setEmployees(new ArrayList<Employee>());
  employees.getEmployees().add(employee1);
  employees.getEmployees().add(employee2);

  return employees;
 }

 /**
  * Use the below url to access this
  * http://localhost:8081/RESTfulDemoApplication/employeeService/employees/123 ( Your port could be different)
  * 
  * 
  * OUTPUT:
  *   <employee id="123" uri="/employeeService/employees/123">
   <firstName>demo</firstName>
   <lastName>employee</lastName>
   </employee>
  * 
  **/
 
 @GET
 @Path("/employees/{id}")
 @Produces("text/xml;charset=UTF-8")
 public Employee getEmployeeById(@PathParam("id") int id) {
  
  //Ideally you will go to database to pull this info..
  
  Employee employee = new Employee();
  employee.setId(id);
  employee.setFirstName("demo");
  employee.setLastName("employee");
  employee.setUri("/employeeService/employees/" + id);
  return employee;
 }

 
 
 /**
  * Use the below url to access this
  * http://localhost:8081/RESTfulDemoApplication/employeeService/employeesjson/123 ( Your port could be different)
  * 
  * OUTPUT:
  * 
   {
      "uri": "/employeeService/employees/123",
      "firstName": "demo",
      "lastName": "employee",
      "id": 123
    }

  **/
 @GET
 @Path("/employeesjson/{id}")
 @Produces("application/json")
 public Employee getEmployeeByJsonId(@PathParam("id") int id) {
  
  /* Pretend you are querying data base using this id and returning the results */
  
  Employee employee = new Employee();
  employee.setId(id);
  employee.setFirstName("demo");
  employee.setLastName("employee");
  employee.setUri("/employeeService/employees/" + id);
  return employee;
 }
 
 
 /**
  * Use the below url to access this
  * http://localhost:8081/RESTfulDemoApplication/employeeService/employeesjson2/123 ( Your port could be different)
  * 
  * OUTPUT:
   {
   
       "uri": "/employeeService/employees/123",
       "firstName": "Ram",
       "lastName": "Chandra",
       "id": 123
   }
  * 
  **/
 @GET
 @Path("/employeesjson2/{id}")
 @Produces("application/json")
    public Response getEmployeeById(@PathParam("id") Integer id)
    {
  //Pretend you are querying from database.
        Employee employee = new Employee();
        employee.setId(id);
        employee.setFirstName("Ram");
        employee.setLastName("Chandra");
        employee.setUri("/employeeService/employees/" + id);
        //Another way to send the response
        return Response.status(200).entity(employee).build();
    }
  
 
 /**
  * Use the below url to access this
  * http://localhost:8081/RESTfulDemoApplication/employeeService/employees ( Your port could be different)
  * Make sure you send the following custom http headers.
  * HTTP Headers:
  * =============
  *   Content-Type: text/xml
  *   allow-admin:true
  * 
  * 
  * And in the body the pay load:
  * ===================
  * 
  *    <employee id="1" uri="/employeeService/employees/1">
    <firstName>rama</firstName>
    <lastName>chandra</lastName>
   </employee>

  *  Http-Method:
  *   POST
  *   
  *   I used fire fox rest client add on  for testing.
  **/
 
 @POST
 @Path("/employees")
 @Consumes("text/xml;charset=UTF-8")
 @Produces("text/xml;charset=UTF-8")
 public Response createEmployee(Employee employee,@DefaultValue("false") @QueryParam("allow-admin") boolean allowAdmin)
   throws URISyntaxException {
  System.out.println(employee.getFirstName());
  System.out.println(employee.getLastName());
  return Response.status(201).contentLocation(new URI("/employeeService/employees/123")).build();
 }

 
 /**
  * Use the below url to update (Put method)
  * http://localhost:8081/RESTfulDemoApplication/employeeService/employees ( Your port could be different)
  * 
  *    Input:
  *    <employee id="1" uri="/employeeService/employees/1">
    <firstName>rama</firstName>
    <lastName>chandra</lastName>
   </employee>
  Set HTTP Headers:
  * ===================
  *   Content-Type: text/xml
  * 
  *   HTTP-Method : PUT 
  *   I used fire fox rest client add on  for testing.
  * 
  **/
 @PUT
 // @Path("/employees/{id: [0-9]*}")
 @Path("/employees/{id}")
 @Produces("text/xml;charset=UTF-8")
 @Consumes("text/xml;charset=UTF-8")
 public Employee updateEmployee(@PathParam("id") int id, Employee employee)throws URISyntaxException {
  employee.setId(id);
  employee.setFirstName(employee.getFirstName() + "updated");
  return employee;
 }

 
 
 /*****
  * Use the below url to delete (Delete method)
  * http://localhost:8081/RESTfulDemoApplication/employeeService/employees/1 ( Your port could be different)
  *   where 1 is the id.
  ****/
 @DELETE
 @Path("/employees/{id}")
 public Response deleteEmployee(@PathParam("id") int id)
   throws URISyntaxException {
  System.out.println(" Deleteing employee with id"+ id);
  //Add your magic code to delete 
  return Response.status(200).build();
 }
 
 
}


So how does rest webservice knows that EmployeeService is a Webservice. Well you nee to register that class as shown below.


package com.rama.restful;


import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
 

@ApplicationPath("/")
public class ApplicationConfig extends Application {
    @SuppressWarnings("unchecked")
    public Set<Class<?>> getClasses() {
     List<Class<?>> registeredServiceClassList = Arrays.asList(
       RESTEasyFileService.class,
          EmployeeService.class);
        return new HashSet<Class<?>>(registeredServiceClassList);
    }
}

And in you web.xml add the following



<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
 <display-name>Archetype Created Web Application</display-name>

 <context-param>
  <param-name>resteasy.scan</param-name>
  <param-value>true</param-value>
 </context-param>
 

 <listener>
  <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
 </listener>
 
 <servlet>
  <servlet-name>resteasy-servlet</servlet-name>
  <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
 </servlet>


 <servlet-mapping>
  <servlet-name>resteasy-servlet</servlet-name>
  <url-pattern>/*</url-pattern>
 </servlet-mapping>
</web-app>
This is all you need to set up the basic restful web service.

Now I will show you how to

Upload/Download File using RESTful Web service


In the same package where we added Employeeservice.java , add your RESTEasyFileService.java.
Needless to say you need to register this class with ApplicationConfig .java class as described above.

RESTEasyFileService.java

package com.rama.restful;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;

import org.jboss.resteasy.plugins.providers.multipart.InputPart;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;

/**
 * 
 *   A simple class which you can use to upload files 
 *   or down load files..
 *   Source : 
 *     http://examples.javacodegeeks.com/enterprise-java/rest/resteasy/resteasy-file-upload-example/
 *   (Thanks to Nikos Maravitsas for File upload example)
 *     
 */
/**
 * @author twreddy
 *
 */
@Path("/files")
public class RESTEasyFileService {

 private static final String SERVER_UPLOAD_LOCATION_FOLDER = "C://RestFileUploadTest//";
 //Using same folder for testing ...
 private static final String SERVER_DOWNLOAD_LOCATION_FOLDER = "C://RestFileUploadTest//";  
 
 
 @GET
 @Path("/")
 @Produces("text/xml;charset=UTF-8")
 public String getServiceInfo() {
  return "<services>/upload" +
    "  For Upload use : http://localhost:8081/RESTfulDemoApplication/files/upload     Your port may differ \n" +
    "  For downloads use : http://localhost:8081/RESTfulDemoApplication/files/download/SpringAnnontationsCheatSheet.pdf  \n" +
    "  where SpringAnnontationsCheatSheet.pdf is the file you have on your server at SERVER_DOWNLOAD_LOCATION_FOLDER . You can use a different file \n" +
    "</services>";
 }
 
 
 
 /**
  *  Method that handles file Upload.
  *  
  *  Use sample html page to upload . The main content of the html page should look like this 
  *  
  *  
   <form action="http://localhost:8081/RESTfulDemoApplication/files/upload" method="post" enctype="multipart/form-data">
    <p>
     Select a file : <input type="file" name="file" size="50" />
    </p>
    <input type="submit" value="Upload It" />
   </form>
 
  *  
  **/
 @POST
 @Path("/upload")
 @Consumes("multipart/form-data")
 public Response uploadFile(MultipartFormDataInput input) {

  String fileName = "";

  Map<String, List<InputPart>> formParts = input.getFormDataMap();

  List<InputPart> inPart = formParts.get("file");

  for (InputPart inputPart : inPart) {

   try {

    // Retrieve headers, read the Content-Disposition header to
    // obtain the original name of the file
    MultivaluedMap<String, String> headers = inputPart.getHeaders();
    fileName = parseFileName(headers);
    // Handle the body of that part with an InputStream
    InputStream istream = inputPart.getBody(InputStream.class, null);
    fileName = SERVER_UPLOAD_LOCATION_FOLDER + fileName;
    saveFile(istream, fileName);

   } catch (IOException e) {
    e.printStackTrace();
   }

  }

  String output = "File saved to server location : " + fileName;

  return Response.status(200).entity(output).build();
 }

 
  
 /**
  *
  * http://localhost:8081/RESTfulDemoApplication/files/download/Test.pdf 
  * Where Test.pdf is the document I have stored under SERVER_DOWNLOAD_LOCATION_FOLDER path.
  * 
  */
 @GET
 @Path("/download/{fileName}")
 @Produces(MediaType.APPLICATION_OCTET_STREAM)
 public Response getFile(@PathParam("fileName") String fileName) {
     File file = new File(SERVER_DOWNLOAD_LOCATION_FOLDER+fileName);
     ResponseBuilder response = Response.ok((Object) file);
     response.header("Content-Disposition","attachment; filename="+fileName);
      return response.build();

 }
 
 
 /*
  *  Content-Disposition: form-data; name="file"; filename="AVD1.png"
  Content-Type: image/png

  */
 // Parse Content-Disposition header to get the original file name
 private String parseFileName(MultivaluedMap<String, String> headers) {
  String[] contentDispositionHeader = headers.getFirst("Content-Disposition").split(";");
  for (String name : contentDispositionHeader) {
   if ((name.trim().startsWith("filename"))) {
    String[] tmp = name.split("=");
    String fileName = tmp[1].trim().replaceAll("\"", "");
    return fileName;
   }
  }
  return "defaultFileName";
 }

 // save uploaded file to a defined location on the server
 private void saveFile(InputStream uploadedInputStream, String serverLocation) {

  try {
   OutputStream outpuStream = new FileOutputStream(new File(
     serverLocation));
   int read = 0;
   byte[] bytes = new byte[1024];

   outpuStream = new FileOutputStream(new File(serverLocation));
   while ((read = uploadedInputStream.read(bytes)) != -1) {
    outpuStream.write(bytes, 0, read);
   }
   outpuStream.flush();
   outpuStream.close();
  } catch (IOException e) {

   e.printStackTrace();
  }
 }
}

So this code now can handle both upload and download.

You can download the above server side Restful web service code at 


Rest easy web service clients

In your client package better to copy Employee.java before you add this client code.

Pure Java Restful Web service  Client

This code shows a simple java client that invokes getEmployee method  and prints the XML.

package com.rama.rest.ws.client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import com.rama.restful.Employee;


/**
 * 
 * Pure java client example to test EmployeeService
 * @author twreddy
 *
 */
public class PureJavaClient  {
 public static void main(String[] args)throws Exception {
  try {
   getEmployeeByIDAsXML();

  } catch (MalformedURLException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  } 
 }
 
  
 private static void getEmployeeByIDAsXML()throws ProtocolException, IOException, JAXBException {
  
  // Not really a good idea to openconnection for each Request...
  URL url = new URL("http://localhost:8081/RESTfulDemoApplication/employeeService/employees/1");
  HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  
  conn.setRequestProperty("Content-Type", "text/plain; charset=utf-8");
  conn.setRequestMethod("GET");
  
  if (conn.getResponseCode() != 200) {
   throw new RuntimeException("Failed : HTTP error code : "+ conn.getResponseCode());
  }

  BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
  String responseStr = br.readLine();
  System.out.println("Response :"+responseStr);
  conn.disconnect();

  JAXBContext jaxbContext = JAXBContext.newInstance(Employee.class);
  Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
  Employee user = (Employee) jaxbUnmarshaller.unmarshal(new StringReader(responseStr));

  System.out.println(user.getId());
  System.out.println(user.getFirstName());
  System.out.println(user.getLastName());
 }
}

Jboss rest easy client

Here is the Jboss rest easy client API. Here all you need is to define an interface which more or less matches you webservice method signatures and then create Proxy using the Interface.
Don't worry once you see the below code it will be more clear.
More info @ 


Lets call the Rest easy client for EmployeeService as EmployeeServiceRestfulClient.java 

package com.rama.rest.ws.client;

import java.net.URISyntaxException;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

/**
 * 
 * Restful Client  which will be used by 
 * org.jboss.resteasy.client.ProxyFactory.
 * 
 * See  RestfulClientTest.java to see how to use this class.
 * 
 * BASEURL : http://localhost:8081/RESTfulDemoApplication/employeeService
 *   (your port may be different)
 * @author twreddy
 *
 */
public interface EmployeeServiceRestfulClient {

  @GET
     @Path("/")
     @Produces("text/xml;charset=UTF-8")
     String getServiceInfo();
  
  @GET
  @Path("/employees")
  @Produces("text/xml;charset=UTF-8")
  public String getAllemployees();
  
  
 @GET
 @Path("/employees/{id}")
 @Produces("text/xml;charset=UTF-8")
 public String getEmployeeById(@PathParam("id") int id);
 
 
 @GET
 @Path("/employeesjson/{id}")
 @Produces("application/json")
 public String getEmployeeByJsonId(@PathParam("id") int id);
 
 
 @GET
 @Path("/employeesjson2/{id}")
 @Produces("application/json")
    public Response getEmployeeById(@PathParam("id") Integer id);
 
 
 @POST
 @Path("/employees")
 @Consumes("text/xml;charset=UTF-8")
 @Produces("text/xml;charset=UTF-8")
 //Notice that we are sending Employee object as XML pay load.
 public Response createEmployee(String employee,@DefaultValue("false") @QueryParam("allow-admin") boolean allowAdmin)
   throws URISyntaxException;
 
 
 @PUT
 // @Path("/employees/{id: [0-9]*}")
 @Path("/employees/{id}")
 @Produces("text/xml;charset=UTF-8")
 @Consumes("text/xml;charset=UTF-8")
 public String updateEmployee(@PathParam("id") int id, String employee);
 
 @DELETE
 @Path("/employees/{id}")
 public Response deleteEmployee(@PathParam("id") int id);
 
}

Lets call the Rest easy client for RESTEasyFileService as RestEasyFileServiceRestfulClient.java 
package com.rama.rest.ws.client;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;

/**
 * @author twreddy
 *  
 *  
 * Restful Client  which will be used by 
 * org.jboss.resteasy.client.ProxyFactory.
 * 
 * See  RestfulClientTest.java to see how to use this class.
 * 
 *  BASE URL: 
 *  http://localhost:8081/RESTfulDemoApplication/files
 */
public interface RestEasyFileServiceRestfulClient {

 
 @GET
 @Path("/")
 @Produces("text/xml;charset=UTF-8")
 public String getServiceInfo();
 
 
 @POST
 @Path("/upload")
 @Consumes("multipart/form-data")
 public Response uploadFile(MultipartFormDataOutput  outPut);
 
 @GET
 @Path("/download/{fileName}")
 @Produces(MediaType.APPLICATION_OCTET_STREAM)
 public Response getFile(@PathParam("fileName") String fileName);
 
}
As you see we hardly have written any code to create the restful rest easy clients. 
Now lets make use of the above Restful clients as shown below.
I added both EmployeeServiceRestfulClient.java and RestEasyFileServiceRestfulClient.java   into same test class.Feel free to have separate testing code for each of them.

RestfulClientTest.java

The key in this class is the line which creates PROXY 
EmployeeServiceRestfulClient client = ProxyFactory.create(EmployeeServiceRestfulClient.class,baseUrl);
I have commented some code intentionally while testing. You can comment or uncomment whichever section you need.

package com.rama.rest.ws.client;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.jboss.resteasy.client.ProxyFactory;
import org.jboss.resteasy.client.core.BaseClientResponse;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;

/**
 * @author twreddy
 *
 * Comment or un comment which ever section you need for testing 
 */
public class RestfulClientTest {

 public static void main(String[] args) throws Exception {
  
  //Employee Service Test 
  String empServiceBaseUrl = "http://localhost:8081/RESTfulDemoApplication/employeeService";
  employeeServiceTest(empServiceBaseUrl);
  
  
  
  //RESTEasyFileService test 
  String fileServiceUrl = "http://localhost:8081/RESTfulDemoApplication/files";
  fileServiceTest(fileServiceUrl);
  
  
  
 }

 

 /**
  *  Employee Service Test . Comment or un comment which ever section you want to test.
  */
 private static void employeeServiceTest(String baseUrl ) {
  //NOTE: Dont re use the same client for different calls. 
  EmployeeServiceRestfulClient client = ProxyFactory.create(EmployeeServiceRestfulClient.class,baseUrl);
  
  /*  Get Employee test 
   
  String response = client.getEmployeeByJsonId(1);
  System.out.println("Response:" + response);
  
  Response responseObj = client.getEmployeeById(new Integer(10));
  System.out.println("Get by id="+ responseObj.getStatus());
  
  */
  
  
  /*  Create Employee  test 
   
  String empStr = "<employee id=\"1\" uri=\"/employeeService/employees/1\"><firstName>rama</firstName><lastName>chandra</lastName></employee>";
  Response responseObjForCreateEmp = client.createEmployee(empStr,true);
  System.out.println("Create Emp ="+responseObjForCreateEmp.getStatus());
  
  */
  
  
  /*  Update Employee test
  
  String empStr = "<employee id=\"1\" uri=\"/employeeService/employees/1\"><firstName>rama</firstName><lastName>chandra</lastName></employee>";
  String updatedEmpStr = client.updateEmployee(1,empStr);
  System.out.println("updatedEmpStr Emp ="+updatedEmpStr);
  
  */
  
  /* Delete Employee test */
  
  Response  responseObj = client.deleteEmployee(1);
  System.out.println("Deleted  Emp  status="+responseObj.getStatus());
 }

 
 
 
 /**
  * 
  * @param fileServiceUrl
  * @throws FileNotFoundException
  * @throws IOException
  */
 private static void fileServiceTest(String fileServiceUrl)
   throws FileNotFoundException, IOException {
  
  
  
  /*  File upload  Test  */
  /* 
   RestEasyFileServiceRestfulClient fileServiceClient = ProxyFactory.create(RestEasyFileServiceRestfulClient.class,fileServiceUrl);  
   MultipartFormDataOutput mdo = new MultipartFormDataOutput();
      mdo.addFormData("file", new FileInputStream(new File("c:\\Test.pdf")),MediaType.APPLICATION_OCTET_STREAM_TYPE);
      Response r = fileServiceClient.uploadFile(mdo);
      System.out.println("File upload Response="+ r.getStatus() +":"+ r.getMetadata());
    */
  
             
             
  /*  To Download a File...
   */
  RestEasyFileServiceRestfulClient fileServiceClient = ProxyFactory.create(RestEasyFileServiceRestfulClient.class,fileServiceUrl);
  BaseClientResponse response = (BaseClientResponse)fileServiceClient.getFile("ASD.zip");
  //You can get whatever  name the server sent
  System.out.println(response.getHeaders().getFirst("Content-Disposition"));  
  File s = (File)response.getEntity(File.class);
  File ff = new File("C:\\ASD.zip");
     s.renameTo(ff);
     FileWriter fr = new FileWriter(s);
     fr.flush();
  System.out.println("FileDownload Response = "+ response.getStatus());
 }
 
 
}

A simple HMTL client for testing File upload


<html>
<head>
<title>Form Page</title>
</head>
<body>
 <h1>Upload a File</h1>

 <form action="http://localhost:8081/RESTfulDemoApplication/files/upload " method="post" enctype="multipart/form-data">
  <p>
   Select a file : <input type="file" name="file" size="50" />
  </p>
  <input type="submit" value="Upload It" />
 </form>

</body>
</html>

FIREFOX Restful Webservice Client:

Now I will show you some screen shots as how you can test restful web services with just firefox rest client .

1. CreateEmployee - This is how you can test createEmployee.You need to add two http headers
allow-admin:true
Content-Type:text/xml
and choose the method as POST as shown.



2. UpdateEmployee - Choose method as "PUT" and http header as "Content-Type:text/xml"



3. GetEmployee 



4.  FileDownload - Just type the full url in browser ( http://localhost:8081/RESTfulDemoApplication/files/download/SpringAnnontationsCheatSheet.pdf )
where "SpringAnnontationsCheatSheet.pdf" was the document that was already present on the server


Hope this article gives you enough info for writing restful webcservices and testing them with different clients.

You can download the client code at  RestFullWebserviceClients.zip
Leave your comments if you have any below.