-->

mardi 20 janvier 2015

CXF3 and Spring 4 : using MTOM to upload file

Introduction :

For many applications, files used with any type and generally must upload them to a remote server. But transport files within an HTTP request is really painful for the connection and for the size of the HTTP request. So use the attachment of a file to the message in order to optimize the process. This is the MTOM.
And it is in this context we will see how to make web services with MTOM.
To do that, we must create a maven project and add cxf outbuildings and spring and configure all. You can see my previous article.

Let's code:

Also, we will use the Google API to manipulate files guava, so we have to add the maven dependency:


 com.google.guava
 guava
 14.0

So first we will create a class UploadParameter that implements Parameter (see previous article).
package fr.mjhazbri.webservices.schema;

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

import fr.mjhazbri.webservices.validation.parameter.Parameter;

@XmlRootElement(name = "uploadParameter")
@XmlAccessorType(XmlAccessType.FIELD)
public class UploadParameter implements Parameter {
 /**
  * The file name parameter.
  */
 @XmlElement(name = "fileName", required = false)
 private String fileName;
 /**
  * the file size.
  */
 @XmlElement(name = "fileSize", required = true, nillable = false)
 private Long fileSize;

 /**
  * the file hash code.
  */
 @XmlElement(name = "hashCode", required = false, nillable = false)
 private String hashCode;

 /**
  * the file hash type.
  */
 @XmlElement(name = "hashType", required = false, nillable = false)
 private String hashType;

 /**
  * @return the fileName
  */
 public String getFileName() {
  return fileName;
 }

 /**
  * @param fileName
  *            the fileName to set
  */
 public void setFileName(String fileName) {
  this.fileName = fileName;
 }

 /**
  * @return the fileSize
  */
 public Long getFileSize() {
  return fileSize;
 }

 /**
  * @param fileSize
  *            the fileSize to set
  */
 public void setFileSize(Long fileSize) {
  this.fileSize = fileSize;
 }

 /**
  * @return the hashCode
  */
 public String getHashCode() {
  return hashCode;
 }

 /**
  * @param hashCode
  *            the hashCode to set
  */
 public void setHashCode(String hashCode) {
  this.hashCode = hashCode;
 }

 /**
  * @return the hashType
  */
 public String getHashType() {
  return hashType;
 }

 /**
  * @param hashType
  *            the hashType to set
  */
 public void setHashType(String hashType) {
  this.hashType = hashType;
 }

 /* (non-Javadoc)
  * @see java.lang.Object#toString()
  */
 @Override
 public String toString() {
  return "UploadParameter [fileName=" + fileName + ", fileSize="
    + fileSize + ", hashCode=" + hashCode + ", hashType="
    + hashType + "]";
 }

}
And also the UploadResponse class to simplify the return of the web service :
/**
 * 
 */
package fr.mjhazbri.webservices.upload.response;

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;
import javax.xml.bind.annotation.XmlType;

/**
 * @author jhazbri
 * 
 */
@XmlRootElement(name = "UploadResponse")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name="UploadResponse")
public class UploadResponse {
 /**
  * The response status : OK or KO
  */
 @XmlElement(name = "status")
 private ResponseStatus responseStatus;

 /**
  * the error messages stack
  */
 private List<String> errorMessage = new ArrayList<String>();

 @XmlElement(name = "fileStoragePath")
 private String fileStoragePath;

 /**
  * @return the responseStatus
  */
 public ResponseStatus getResponseStatus() {
  return responseStatus;
 }

 /**
  * @param responseStatus
  *            the responseStatus to set
  */
 public void setResponseStatus(ResponseStatus responseStatus) {
  this.responseStatus = responseStatus;
 }

 /**
  * @return the errorMessage
  */
 public List<String> getErrorMessage() {
  return errorMessage;
 }

 /**
  * @param errorMessage
  *            the errorMessage to set
  */
 public void setErrorMessage(List<String> errorMessage) {
  this.errorMessage = errorMessage;
 }

 /**
  * @return the fileStoragePath
  */
 public String getFileStoragePath() {
  return fileStoragePath;
 }

 /**
  * @param fileStoragePath
  *            the fileStoragePath to set
  */
 public void setFileStoragePath(String fileStoragePath) {
  this.fileStoragePath = fileStoragePath;
 }

 public void addErrorMessage(String message) {
  if (errorMessage == null)
   errorMessage = new ArrayList<String>();
  errorMessage.add(message);
 }
}
Do not forget ResponseStatus for the status of the response:
package fr.mjhazbri.webservices.upload.response;

import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlType;

@XmlType(name="status")
@XmlEnum(String.class)
public enum ResponseStatus {

 OK("OK"), KO("KO");

 private String value;

 /**
  * @return the value
  */
 public String getValue() {
  return value;
 }

 /**
  * @param value
  */
 private ResponseStatus(String value) {
  this.value = value;
 }
}
And now UploadWebService interface is written to model the methods to expose:
/**
 * 
 */
package fr.mjhazbri.webservices.upload.api;

import javax.activation.DataHandler;
import javax.jws.WebService;
import javax.xml.ws.WebServiceException;

import fr.mjhazbri.webservices.schema.UploadParameter;
import fr.mjhazbri.webservices.upload.response.UploadResponse;

/**
 * @author jhazbri
 *
 */
@WebService
public interface UploadWebService {
 /**
  * This method is used to send file
  * 
  * @param UploadParameter
  * @param dataHandler
  * @return UploadResponse
  */
 UploadResponse  upload(UploadParameter uploadParameter, DataHandler dataHandler) throws WebServiceException;
}

Finally, what interests us is the class for writing the business logic of the upload starting with validation web service, save the received file and return a result to the client

/**
 * 
 */
package fr.mjhazbri.webservices.upload;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.UUID;

import javax.activation.DataHandler;
import javax.jws.WebService;
import javax.xml.ws.BindingType;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.soap.MTOM;

import org.apache.log4j.Logger;

import com.google.common.io.Files;

import fr.mjhazbri.webservices.schema.UploadParameter;
import fr.mjhazbri.webservices.upload.api.UploadWebService;
import fr.mjhazbri.webservices.upload.response.ResponseStatus;
import fr.mjhazbri.webservices.upload.response.UploadResponse;
import fr.mjhazbri.webservices.validation.result.Result;
import fr.mjhazbri.webservices.validation.service.ParameterValidationServiceImpl;
import fr.mjhazbri.webservices.validation.service.api.ParameterValidationService;

/**
 * @author jhazbri
 *
 */
@WebService(endpointInterface = "fr.mjhazbri.webservices.upload.api.UploadWebService",serviceName = "UploadWebService", portName = "UploadWebServicePort", name = "UploadWebService", targetNamespace = "http://www.mjhazbri.fr/upload")
@MTOM(enabled=true)
@BindingType(value = javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_MTOM_BINDING)
public class UploadWebServiceImpl implements UploadWebService{

 private static final Logger logger = Logger.getLogger(UploadWebServiceImpl.class);
 private ParameterValidationService<UploadParameter>validationService = new ParameterValidationServiceImpl<UploadParameter>(); 
 /**
  * The XSD PATH
  */
 private static final String DEFAULT_XSD_PATH = "parameter.xsd";
 
 @Override
 public UploadResponse upload(UploadParameter uploadParameter,DataHandler dataHandler) throws WebServiceException {

  UploadResponse response = new UploadResponse() ; 
  response.setResponseStatus(ResponseStatus.OK);
  
  logger.debug("calling sayHello with parameter : "+ uploadParameter);
  // validate the web services 
  File fileTmp = new File(this.getClass().getClassLoader().getResource(DEFAULT_XSD_PATH).getPath()) ; 
  
  Result result = validationService.validateParam(uploadParameter, fileTmp);
  if (!result.isValid()) 
  {
   throw new WebServiceException(result.getMessage());
  }
  
  File storage = fileTmp.getParentFile() ; 
  if (storage == null )
  {
   throw new WebServiceException("Cannot store file");
  }
  
  // get and store file
  byte[] dataByte = null ;
  try 
  {
   ByteArrayOutputStream bos = new ByteArrayOutputStream();
   dataHandler.writeTo(bos);
   bos.flush();
   bos.close();
   dataByte = bos.toByteArray();
   StringBuilder builder = new StringBuilder() ; 
   builder.append(storage.getPath());
   builder.append("/");
   
   builder.append(Files.getNameWithoutExtension(uploadParameter.getFileName()));
   builder.append("_");
   builder.append(UUID.randomUUID().toString().replaceAll("-", ""));
   if (Files.getFileExtension(uploadParameter.getFileName()) != null &&  !"".equals(Files.getFileExtension(uploadParameter.getFileName())))
   {
    builder.append(".");
    builder.append(Files.getFileExtension(uploadParameter.getFileName()));
   }
   Files.write(dataByte, new File(builder.toString())) ;
   response.setFileStoragePath(builder.toString());
   logger.debug("End upload with success !");
  }
  catch (Exception e) 
  {
   logger.error("error on attachment : "+e.getMessage());
   response.setResponseStatus(ResponseStatus.KO);
   response.addErrorMessage(e.getMessage());
  }
  
  return response;
 }
}

Aucun commentaire :

Enregistrer un commentaire