-->

mercredi 28 décembre 2016

Send hipchat notification from Jenkins pipeline

Introduction :

For a few months I have been working on automating the deployment of web executables on docker containers hosted on AMAZON AWS, and I have added a hipchat notification to each deployment.

mardi 27 décembre 2016

Docker : how to create Wildfly and MySQL in the same server

Introduction :

I continue with the exploration of the docker world. After wildfly container creation, i will add a MySQL RDMBS, for this you have the choice between the creation of two Dockerfile document and execute the build and the run of servers, or, write in once only one document and specify the environnement document in the whole.

Let's code now the first choice :

the Dockerfile for Wildfly  


The wildfly dockerfile file mentions several other files such as standalone-mjhazbri.xml and module-mysql.xm. The file start-wildfly.sh will be used to start the server wildfly :
  


The Dockerfile of MySQL : 



The MySQL dockerfile file mentions several other files such as my.cnf and run.sh :


the second choice will be explained in other article.

mercredi 21 décembre 2016

Install Wildfly with Docker

Introduction :

Recently, for a mission to a client, my team and I had developed a backoffice application to expose web services REST. We used the Java EE 7 standard. Among several application servers we chose Wildlfy 9. And so I was able to install this server for continuous integration.

Introduction :

As stated in my old article, the docker's heart is the Dockerfile file, so the first thing to do is to write this file.


FROM jboss/wildfly:9.0.2.Final
MAINTAINER Jalel HAZBRI "jalel.hazbri@gmail.com"

# ENV VARIABLES 
ENV WILDFLY_HOME /opt/jboss/wildfly
ENV WILDFLY_VERSION 9.0.2.Final

# Add console admin user
RUN ${WILDFLY_HOME}/bin/add-user.sh mjhazbri mjhazbri --silent

# Ports
EXPOSE 8080 9990

# Volumes
VOLUME ${WILDFLY_HOME}/standalone/deployments/
VOLUME ${WILDFLY_HOME}/standalone/log/

# RUN script
COPY start-wildfly.sh ${WILDFLY_HOME}/bin/start-wildfly.sh
USER root
RUN chmod +x ${WILDFLY_HOME}/bin/start-wildfly.sh
#USER jboss

ENTRYPOINT ["sh", "-c", "${WILDFLY_HOME}/bin/start-wildfly.sh"]

And the last line is to start wildfly with the script start-wildfly.sh :

#!/bin/sh

${WILDFLY_HOME}/bin/standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0




mardi 20 décembre 2016

Docker : Dockerfile

Introduction :

First, to Dockerfile, we should read this definition extracted from docker web site : 
"Docker can build images automatically by reading the instructions from a Dockerfile. A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Using docker build users can create an automated build that executes several command-line instructions in succession."

Second, the Dockerfile has this format :  


# Comment
INSTRUCTION arguments

From :

The instruction is not case-sensitive. However, convention is for them to be UPPERCASE to distinguish them from arguments more easily. Docker runs instructions in a Dockerfile in order. The first instruction must be `FROM` in order to specify the Base Image from which you are building.

FROM ImageName
# directive=value

The FROM structure is :


FROM image

Or 


FROM image:tag

Or 


FROM image@digest

From :

The Maintainer instruction allows you to set the Author field of the generated images.

Expose :

The EXPOSE instruction informs Docker that the container listens on the specified network ports at runtime. EXPOSE does not make the ports of the container accessible to the host. To do that, you must use either the -pflag to publish a range of ports or the -P flag to publish all of the exposed ports. You can expose one port number and publish it externally under another number.

ENV:

The The ENV instruction sets the environment variable to the value . This value will be in the environment of all “descendant” Dockerfile commands and can be replaced inline in many as well.

The ENV instruction has two forms. The first form, ENV , will set a single variable to a value. The entire string after the first space will be treated as the - including characters such as spaces and quotes.

The second form, ENV = ..., allows for multiple variables to be set at one time. Notice that the second form uses the equals sign (=) in the syntax, while the first form does not. Like command line parsing, quotes and backslashes can be used to include spaces within values.


ENV JAVA_HOME /dir_to_java

ADD:

The ADD has two forms:


ADD "src"... "dest"
ADD ["src",... "dest"] (this form is required for paths containing whitespace)

The ADD instruction copies new files, directories or remote file URLs from and adds them to the filesystem of the image at the path .

Multiple resource may be specified but if they are files or directories then they must be relative to the source directory that is being built (the context of the build).


ADD test relativeDir/          # adds "test" to `WORKDIR`/relativeDir/
ADD test /absoluteDir/         # adds "test" to /absoluteDir/

COPY:

The COPY has two forms:


COPY "src"... "dest
COPY ["src",... "dest"] (this form is required for paths containing whitespace)

The COPY instruction copies new files or directories from and adds them to the filesystem of the container at the path .

Multiple resource may be specified but they must be relative to the source directory that is being built (the context of the build).


COPY test relativeDir/   # adds "test" to `WORKDIR`/relativeDir/
COPY test /absoluteDir/  # adds "test" to /absoluteDir/




mercredi 26 octobre 2016

Docker ... let's start

Introduction :

First, to know docker, I invite you to read what is written on their website. but what they mean by it all. In fact, simply, is to create a server that will contain everything you want: application server, RDBMS, web server, application software ....



But how to do all this : 

well it's simple: just install docker on your machine (it's exist for any OS).

And whats : 
I told you, it's simple, if you want a server ready to use without any customization: then you can go on the docker hub website.
Well, if you chose to install your server, then run the docker run command is well documented on the site.

Example : 

I take the case of jenkins, jenkins if you are looking on the search bar: jenkins, you have this:



I recommend you always use the official repo.You will find how to perform this official image.

  docker run jenkins 

Congrats, now you have a jenkins server installed on your machine.

vendredi 18 décembre 2015

First step with Java EE 7

Introduction :

First, to explore the Java EE standard , I'll start by writing an article to simplify the development of applications that rely on Java EE 7.

Now, let's configure :


To begin, we will create a maven project and to do so, we can use the plugin maven below : 

mvn -DarchetypeGroupId=org.wildfly.archetype 
    -DarchetypeArtifactId=wildfly-javaee7-webapp-blank-archetype 
    -DarchetypeVersion=8.2.0.Final 
    -DgroupId=fr.blogspot.mjhazbri 
    -DartifactId=ContactManagement 
    -Dversion=1.0.0-SNAPSHOT 
    -Dpackage=fr.blogspot.mjhazbri 
    -Darchetype.interactive=false 
    --batch-mode 
    --update-snapshots 
     archetype:generate 


And as a result, we have a project called ContactManagement.

Framework :


The list of frameworks that will be used is EJB3.2 , JPA2.1.

Generated file :


There is a portion of source code and configuration that are generated and which are :

persistence.xml



   
      
      
      java:jboss/datasources/ContactsDS
      
         
         
         
      
   

If you notice well , we see a datasource was declared , the data dource is under the WEB- INF folder in the webapp folder : 





 
 
  jdbc:mysql://localhost:3306/contacts
  mysql
  
   root
   
  
 

 

This datasource refers to the RDBMS MySQL then the driver must be provided and also create the associated database , so the driver can be downloaded from internet and we must put it under the deployments directory of our Wildfly server.

 
To create the database , simply go on MySQL Workbench and execute the following query

create database contacts;


Now, let's code :

The first thing to do is to code entities , I'll create three entities User, Group and Right :

package fr.blogspot.mjhazbri.entities;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

/**
 * @author jhazbri
 *
 */
@Entity
@Table(name = "USERS")
public class User {

 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private Integer id;

 @Column(name = "usr_login")
 private String login;

 @Column(name = "usr_password")
 private String password;

 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "usr_group")
 private Group group;

 public Integer getId() {
  return id;
 }

 public void setId(Integer id) {
  this.id = id;
 }

 public String getLogin() {
  return login;
 }

 public void setLogin(String login) {
  this.login = login;
 }

 public String getPassword() {
  return password;
 }

 public void setPassword(String password) {
  this.password = password;
 }

 public Group getGroup() {
  return group;
 }

 public void setGroup(Group group) {
  this.group = group;
 }
}

package fr.blogspot.mjhazbri.entities;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table;

/**
 * @author jhazbri
 *
 */
@Entity
@Table(name = "GROUPS")
public class Group {

 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private Integer id;

 @Column(name = "grp_name")
 private String groupName;

 @OneToMany(targetEntity = User.class, mappedBy = "group")
 private Set users = new HashSet();

 @ManyToMany(targetEntity = Right.class)
 private Set rights = new HashSet();

 public Integer getId() {
  return id;
 }

 public void setId(Integer id) {
  this.id = id;
 }

 public String getGroupName() {
  return groupName;
 }

 public void setGroupName(String groupName) {
  this.groupName = groupName;
 }

 public Set getUsers() {
  return users;
 }

 public void setUsers(Set users) {
  this.users = users;
 }

 public Set getRights() {
  return rights;
 }

 public void setRights(Set rights) {
  this.rights = rights;
 }
}

package fr.blogspot.mjhazbri.entities;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

/**
 * @author jhazbri
 *
 */
@Entity
@Table(name = "RIGHTS")
public class Right {

 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private Integer id;

 @Column(name = "rht_name")
 private String rightValue;

 @ManyToMany(targetEntity = Group.class, mappedBy = "rights")
 private Set groups = new HashSet();

 public Integer getId() {
  return id;
 }

 public void setId(Integer id) {
  this.id = id;
 }

 public String getRightValue() {
  return rightValue;
 }

 public void setRightValue(String rightValue) {
  this.rightValue = rightValue;
 }

 public Set getGroups() {
  return groups;
 }

 public void setGroups(Set groups) {
  this.groups = groups;
 }

}

package fr.blogspot.mjhazbri.dao;

import java.util.logging.Logger;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import fr.blogspot.mjhazbri.entities.User;

/**
 * @author jhazbri
 *
 */
@Stateless
public class UserDao {

 private final static Logger logger = Logger.getLogger(UserDao.class
   .getName());

 @PersistenceContext()
 private EntityManager em;

 @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
 @PostConstruct
 public void init() {
  logger.info("init EJB method ... ");
 }

 @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
 @PreDestroy
 public void destroy() {
  logger.info("destory EJB method ... ");
 }

 @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
 public User create(User user) {
  em.persist(user);
  return user;
 }

 @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
 public User update(User user) {
  em.merge(user);
  return user;
 }

 @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
 public User search(Integer userId) {
  return em.find(User.class, userId);
 }
}

So to test the injection of EJB , I create a service where I will inject Dao :

/**
 * 
 */
package fr.blogspot.mjhazbri.services;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;

import fr.blogspot.mjhazbri.dao.UserDao;
import fr.blogspot.mjhazbri.entities.Group;
import fr.blogspot.mjhazbri.entities.User;

/**
 * @author jhazbri
 *
 */
@Stateless
public class UserManagementService {

 @EJB
 private UserDao userDao;

 @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
 private User addUserInGroup(User user, Group group) {
  user.setGroup(group);
  return userDao.create(user);
 }
}

mercredi 21 janvier 2015

CXF3 and Spring 4 : Using Interceptor ...

Introduction :

I continue with the exploration of the CXF framework and present my feedback with web services. With this present article, I will introduce interceptors and i will give an example among several use cases: I begin with introducing the example to more understand : if we want to handle all exceptions and not to return to the user a technical stack trace that can never understand, so instead we can return a customizable messages with any thrown exception. In this case, we must use CXF interceptors.

Let's code now:

As always I rely on my old article and I use the same sources. We will start by creating exceptions and first we will create an Enum for errors list :
package fr.mjhazbri.webservices.exception;
/**
 * 
 * @author jhazbri
 *
 */
public enum ExceptionErrorCode {

 GENERAL_ERROR("GENERAL_ERROR"), 
 VALIDATION_ERROR("VALIDATION_ERROR"), 
 CONNECTION_ERROR("CONNECTION_ERROR"), 
 INTERNAL_ERROR("INTERNAL_ERROR"), 
 UPLOAD_ERROR("UPLOAD_ERROR"), 
 STORAGE_ERROR("STORAGE_ERROR"), 
 UNKOWN_ERROR("UNKOWN_ERROR");

 private String value;

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

 /**
  * @param value
  */
 private ExceptionErrorCode(String value) {
  this.value = value;
 }
}

Then we will create an exception called BusinessException to handle all errors:

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

/**
 * @author jhazbri
 * 
 */
public class BusinessException extends Exception {

 private static final long serialVersionUID = 6379178121998659740L;
 private ExceptionErrorCode errorCode;

 public BusinessException(String message, Throwable cause,ExceptionErrorCode errorCode) 
 {
  super(message, cause);
  this.setErrorCode(errorCode);
 }

 public BusinessException(String message, ExceptionErrorCode errorCode) 
 {
  super(message);
  this.setErrorCode(errorCode);
 }

 public BusinessException(Throwable cause, ExceptionErrorCode errorCode) 
 {
  super(cause);
  this.setErrorCode(errorCode);
 }

 /**
  * @return the errorCode
  */
 public ExceptionErrorCode getErrorCode() 
 {
  return errorCode;
 }

 /**
  * @param errorCode
  *            the errorCode to set
  */
 public void setErrorCode(ExceptionErrorCode errorCode) 
 {
  this.errorCode = errorCode;
 }

 public String getCodeValue() 
 {
  if (errorCode == null)
   return "-1";
  else
   return errorCode.getValue();
 }
}


Now a ExceptionManager interface to manage and manufacture BusinessException:

/**
 * 
 */
package fr.mjhazbri.webservices.exception.api;

import fr.mjhazbri.webservices.exception.BusinessException;
import fr.mjhazbri.webservices.exception.ExceptionErrorCode;

/**
 * @author jhazbri
 *
 */
public interface ExceptionManager {
 BusinessException buildBusinessException (ExceptionErrorCode errorCode); 
 String getMessageByErrorCode (ExceptionErrorCode exceptionErrorCode); 
}


An implementation for this interface is ExceptionManagerImpl and load the properties file messages.properties that contains the error messages list :

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
import org.springframework.core.env.Environment;

import fr.mjhazbri.webservices.exception.api.ExceptionManager;

/**
 * @author jhazbri
 * 
 */
@Configuration
@PropertySources(@PropertySource("classpath:messages.properties"))
public class ExceptionManagerImpl implements ExceptionManager {

 @Autowired
 private Environment env;

 @Override
 public BusinessException buildBusinessException(ExceptionErrorCode errorCode) {
  String msg = getMessageByErrorCode(errorCode);
  return new BusinessException(msg, errorCode);
 }

 @Override
 public String getMessageByErrorCode(ExceptionErrorCode exceptionErrorCode) {
  return env.getProperty(exceptionErrorCode.getValue());
 }
}


And that is the content of the file messages.properties

GENERAL_ERROR = GENERAL_ERROR
VALIDATION_ERROR = VALIDATION_ERROR
CONNECTION_ERROR = CONNECTION_ERROR
INTERNAL_ERROR = INTERNAL_ERROR
UNKOWN_ERROR = UNKOWN_ERROR

Interceptor :

Now let's see the CXF Interceptor :
/**
 * 
 */
package fr.mjhazbri.webservices.interceptor;

import javax.xml.namespace.QName;
import javax.xml.ws.WebServiceException;

import org.apache.cxf.common.injection.NoJSR250Annotations;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import fr.mjhazbri.webservices.exception.BusinessException;
import fr.mjhazbri.webservices.exception.ExceptionErrorCode;
import fr.mjhazbri.webservices.exception.api.ExceptionManager;

@NoJSR250Annotations
public class ExceptionInterceptor extends AbstractPhaseInterceptor<Message> {
 /**
  * Class logger.
  */
 private static final Logger logger = Logger.getLogger(ExceptionInterceptor.class);
 
 @Autowired
 private ExceptionManager exceptionManager ; 
 
 public ExceptionInterceptor() {
  super(Phase.MARSHAL);
 }
 
 public void handleMessage(Message message) throws Fault {
  logger.debug("ExceptionInterceptor () : handleMessage ... () ");
  Fault fault = (Fault) message.getContent(Exception.class);
  if (fault != null )
  {
   if (fault.getCause() instanceof BusinessException )
   {
    BusinessException ex = (BusinessException) fault.getCause();
    logger.debug("BusinessException  ....." );
    RuntimeException exception=  new WebServiceException(ex.getMessage());
    Fault faultResponse = new Fault(exception);
    faultResponse.setFaultCode(new QName(ex.getErrorCode().getValue()));
    message.setContent(Exception.class, faultResponse); 
   }
   else 
   {
    Throwable ex = fault.getCause();
    logger.debug("ExceptionInterceptor () : handleMessage for class " + ex.getClass().getName());
    logger.error("Exception not managed : "+ ex.getClass().getName(),ex);
    // préparer le message à retourner.
    RuntimeException exception=  new WebServiceException(exceptionManager.getMessageByErrorCode(ExceptionErrorCode.INTERNAL_ERROR));
    Fault faultResponse = new Fault(exception);
    faultResponse.setFaultCode(new QName(ExceptionErrorCode.INTERNAL_ERROR.name()));
    message.setContent(Exception.class, faultResponse); 
   }
   
  }
 }
}

And finally let's configure the cxf-servlet.xml




 
  
 

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;
 }
}

CXF3 and Spring 4 : Parameter validation with XSD ...

Introduction :

For many times, we still believe validate our web services parameters against a xsd file. During this short tutorial, we will learn how to generate a xsd file from our Java classes in a context of maven project and then we will validate the data sent by the client with our xsd already generated.

Generate XSD :

There are the jaxb2-maven-plugin to manipulate Java and XSD :This plugin uses jaxb2 to generate Java classes from XML Schemas (and binding files) and to create XML Schemas for Existing Java classes. For using this plugin, we should know goals plugins : 

  • jaxb2:schemagen Creates XML Schema Definition (XSD) file(s) from annotated Java sources. 
  • jaxb2:testSchemagen Creates XML Schema Definition (XSD) file(s) from annotated Java test sources. 
  • jaxb2:xjc Generates Java sources from XML Schema(s). 
  • jaxb2:testXjc Generates Java test sources from XML Schema(s).

And now, to generate our file, we will use the first goal : schemagen. To do this, it's so simple, we should add in our pom.xml this plugin and configure the how to access java classes :

 org.codehaus.mojo
 jaxb2-maven-plugin
 1.5
 
  
   
    schemagen
   
   generate-sources
   
    ${project.build.directory}/schemas
    ${project.build.directory}/generated-sources/jaxb
    
     fr/mjhazbri/webservices/schema/*.java
     fr/mjhazbri/webservices/validation/parameter/*.java
    
    
     
      http://www.mjhazbri.fr/parameter
      parameter.xsd
     
    
   
  
 

With this addition to our pom.xml was that each file in the directory fr/mjhazbri/webservices/validation/parameter/*.java will be generated as a parameter to our web services and that will be generated with the namespace http://www.mjhazbri.fr/parameter For this, we will add a small package-info in this same directory :
@javax.xml.bind.annotation.XmlSchema(
  namespace="http://www.mjhazbri.fr/parameter",
  elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package fr.mjhazbri.webservices.schema;

Parameter validation with our XSD generated:

To do this, we will create a first interface to represents parameter, it look like this :
package fr.mjhazbri.webservices.validation.parameter;

public interface Parameter {

}
The result of the web services validation :
package fr.mjhazbri.webservices.validation.result;

public class Result {

 /**
  * Is validation ok.
  */
 private boolean isValid = true;

 /**
  * Message from validation.
  */
 private String message = null;

 public final boolean isValid() {
  return isValid;
 }

 public final void setValid(boolean isValid) {
  this.isValid = isValid;
 }

 public final String getMessage() {
  return message;
 }

 public final void setMessage(String message) {
  this.message = message;
 }
}
And a second interface to represent the methods needed :
**
 * 
 */
package fr.mjhazbri.webservices.validation.service.api;

import java.io.File;

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

/**
 * @author jhazbri
 * 
 */
public interface ParameterValidationService<T extends Parameter> {

 Result validateParam(final T param, final File xsdFile);
}
And now, we will code the class ParameterValidationService that implements the logic of validation :
/**
 * 
 */
package fr.mjhazbri.webservices.validation.service;

import java.io.File;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.util.JAXBSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.apache.log4j.Logger;
import org.xml.sax.SAXParseException;

import fr.mjhazbri.webservices.validation.parameter.Parameter;
import fr.mjhazbri.webservices.validation.result.Result;
import fr.mjhazbri.webservices.validation.service.api.ParameterValidationService;

/**
 * @author jhazbri
 * 
 */
public class ParameterValidationServiceImpl<T extends Parameter> implements ParameterValidationService<T> {

	private static final Logger LOGGER = Logger.getLogger(ParameterValidationServiceImpl.class);

	private static final SchemaFactory SCHEMA_FACTORY = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
	private static final ConcurrentHashMap<Class<?>, JAXBContext> CONTEXTS = new ConcurrentHashMap<Class<?>, JAXBContext>();
	private static final ConcurrentMap<String, Validator> VALIDATORS = new ConcurrentHashMap<String, Validator>();

 @Override
 public synchronized Result validateParam(T param, File xsdFile)
 {
  Result result = new Result() ; 
  try 
  {
   // Validate source.
   LOGGER.debug(String.format("Begins validation - param %s - xsdPath %s !", param.getClass().toString(), xsdFile.toString()));
   Validator validator = VALIDATORS.get(xsdFile.toString());
   if (validator == null )
   {
    LOGGER.debug("VALIDATOR - resources : " + ParameterValidationServiceImpl.class.getResource("."));
    LOGGER.debug("xsd File : " + xsdFile.toString());
    final Schema schema = SCHEMA_FACTORY.newSchema(xsdFile);
    validator = schema.newValidator();
    VALIDATORS.putIfAbsent(xsdFile.toString(), validator);
   }
   
   JAXBContext context = CONTEXTS.get(param.getClass());
   if (context == null) 
   {
    context = JAXBContext.newInstance(param.getClass());
    CONTEXTS.putIfAbsent(param.getClass(), context);
   }
   validator.validate(new JAXBSource(context ,param));
         LOGGER.debug("Ends validation !");
  } catch (SAXParseException spe)
  {
   LOGGER.warn(spe.getMessage(), spe);
   result.setValid(false);
   result.setMessage(spe.getMessage());
  }
  catch (Exception exception)
  {
   LOGGER.warn(exception.getMessage(), exception);
   result.setValid(false);
   result.setMessage(exception.getMessage());
  }
        LOGGER.debug("isValid : " + result.isValid());
  return result;
 }

}

lundi 19 janvier 2015

CXF3 and Spring 4 : from the begining ...

Introduction :

In our development, we often need to make web services if either SOAP or REST, one of the best frameworks that not only implements the standard JEE but offers many more possibilities for the web services dev is apache-cxf.

Personally, there are more than two years that I use apache-cxf to develop web services, but recently when I had to push things, I discovered how to do many other features with this framework that I would like to share on my blog.

Now, let's code :

So first we need to create a web project with maven: for this is simple just run this command on a system console :

mvn archetype:generate 
-DgroupId=fr.mjhazbri.webservices 
-DartifactId=ShowInterceptor 
-DarchetypeArtifactId=maven-archetype-webapp 
-DinteractiveMode=false

Now our project is created, but contains no great thing: neither config spring nor the config cxf. So we're going to edit web.xml : 

 
  Apache CXF binding
  cxf
  org.apache.cxf.transport.servlet.CXFServlet
  1
 
 
  cxf
  /*
 

Then we will create a file named cxf-servlet.xml in the same place as web.xml, so under WEB-INF directory, this file will contain the cxf and spring configuration, it look like this: 


 
 
 
  
 
 

 

Then we will create a file named cxf-servlet.xml in the same place as web.xml, so under WEB-INF directory, this file will contain the cxf and spring configuration, it look like this:  Now we should edit the pom file file to get cxf, spring dependencies, so we will add this to our pom.xml file (we must put these lines between the dependencies tags ):
  
   org.springframework
   spring-web
   4.0.5.RELEASE
   compile
  
  
   org.springframework
   spring-context
   4.0.5.RELEASE
   compile
  
  
   org.apache.cxf
   cxf-api
   2.7.14
   compile
  
  
   org.apache.cxf
   cxf-rt-frontend-jaxws
   2.7.14
   compile
  
  
   org.apache.cxf
   cxf-rt-transports-http
   2.7.14
   compile
  
  
   org.springframework
   spring-test
   4.0.5.RELEASE
   test
  
  
   junit
   junit
   4.8.2
   test
  
  
   log4j
   log4j
   1.2.17
  
Be careful before you have to update the list of repositories, it will look like this :
 
  
   springsource-repo
   SpringSource Repository
   http://repo.springsource.org/release
  
  
   maven2-repository.java.net
   Java.net Repository for Maven
   http://download.java.net/maven/2/
   default
  

First, the class Parameter in the package fr.mjhazbri.webservices.schema should be created to represent input data to our web service :
/**
 * 
 */
package fr.mjhazbri.webservices.schema;

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

/**
 * @author jhazbri
 * 
 */
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Parameter {
 private String name;

 /**
  * @return the name
  */
 public String getName() {
  return name;
 }

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

 @Override
 public String toString() {
  return "Parameter [name=" + name + "]";
 }

}

After this class, in the package fr.mjhazbri.webservices.api, we will create the interface : HelloWorld

package fr.mjhazbri.webservices.api;

import javax.jws.WebService;

import fr.mjhazbri.webservices.schema.Parameter;

/**
 * @author jhazbri
 *
 */
@WebService
public interface HelloWorld {
 
 String sayHello (Parameter parameter );

}

The class that implements HelloWorld interface will be in the fr.mjhazbri.webservices package and named HelloWorldImpl : it look like this :
package fr.mjhazbri.webservices;

import javax.jws.WebService;

import org.apache.log4j.Logger;

import fr.mjhazbri.webservices.api.HelloWorld;
import fr.mjhazbri.webservices.schema.Parameter;

@WebService(endpointInterface = "fr.mjhazbri.webservices.api.HelloWorld")
public class HelloWorldImpl implements HelloWorld {
 private static final Logger logger = Logger.getLogger(HelloWorldImpl.class);
 @Override
 public String sayHello(Parameter parameter) {
  logger.debug("calling sayHello with parameter : "+ parameter);
  return "Hello : " + parameter.getName();
 }
}

Finally, you can now deploy to web container and use your web service.

vendredi 5 décembre 2014

JPA-style positional param was not an integral ordinal

Introduction :

"JPA-style positional param was not an integral ordinal"

One problem that requires a bit of thought to solve this error or exception thrown when developping an application using JPA and Hibernate like a reference implementation.

To solve this problem, we must see the origin of this error, it is a poorly written application that can not interpreted by the Hibernate ORM.

Take an example of a native SQL query to understand who the resolve this problem : 

query = "SELECT u from User u"
      + "INNER JOIN ON g.grp_id Group g = u.grp_id"
      + "and grp.grp_name = ?1";

At the first sight, there is no space at the end od the second line of the concatenated String and Hibernate can not interpret this query. 

To solve this problem you must add a space in the end of the second line.

query = "SELECT u from User u"
      + "INNER JOIN ON g.grp_id Group g = u.grp_id "
      + "and grp.grp_name = ?1";

lundi 3 mars 2014

Hibernate MappingException : Could not determine type for: java.util.Collection, java.util.Set, java.util.List

Introduction :

"hibernate MappingException: Could not determine type for: java.util.Set"

I am currently in the process of working on a web project that combines Vaadin, Spring 3 and JPA 2 with the use of the reference implementation hibernate and suddenly I had a small problem that I think most geeks have java have this kind of problem: org.hibernate.MappingException: Could not determined the type for: java.util.Set, also the same with java.util.Collection and java.util.List, when using annotations @ OneToMany and @ ManyToOne. 

The solution for this problem is very easy but requires a lot of google search, so make sure that all annotations are on attributes and not on the getters. 

mercredi 19 février 2014

Interview about Tunis Java User Group : Out first meeting


For our first meeting for java and Tunis JUG I made a lot of talks and interviews :

With malisseOnline : 

There was almost a year ago that i interviewed about Java and Tunis JUG with Mohamed Ali Souissi who is a speaker and animator in Mosaique FM and who is interested in IT domain.
Here is the viedo of this interview, it was great and cool for me to discuss about Java a,d TunisJUG.


With Mosaique Fm in hightech  program : 

It was so funny to discuss about Java and Tunis JUG.


Many others sites and blog : 

it was at this time that I discovered that a lot of developers who are interested in Java technology and many sites write articles about our Communuty : 
- sabriboubaker.wordpress.com 
www.largestinfo.net 
- speakouttunisia.com
- ....

Arnaud in Tunis : 

Also after I planned with the god maven maven Arnaud Héritier evening, he speaks of it here
" Bon, peut être pas si loin que ça :-).La semaine du 18 juin je serai au soleil en Tunisie ( pour le travail avec les équipes d’eXo platform évidemment !! ).A cette occasion je devrais être de passage au TnJug (La date exacte n’est pas encore fixée). Si vous avez des idées de sujets que vous voulez que j’aborde n’hésitez pas à m’en parler ci-dessous dans les commentaires et je ferai mon possible pour vous faire une session en adéquation avec vos envies. Vous pouvez retrouver tout mon catalogue de présentations sur slideshare. "
But it did not end because we have a lot of organizational problem.




mercredi 12 février 2014

Hot-swap with Dynamic Code Evolution VM

Introduction :

I am currently working in my business on a project that contains over thirty sub maven projects. To do programming very well, we have to use every minute a java debboger this is a good link to know how to debbug java program in eclipse). I have presented in this context, the dcevm framework, and it's pleasure to share this experience with all. 

First Step : What is  DCEVM : 

I found this definition in the Dynamic Code Evolution VM site 
The Dynamic Code Evolution Virtual Machine (DCE VM) is a modification of the Java HotSpot(TM) VM that allows unlimited redefinition of loaded classes at runtime. The current hotswapping mechanism of the HotSpot(TM) VM allows only changing method bodies. Our enhanced VM allows adding and removing fields and methods as well as changes to the super types of a class.
For me, it's simple to define DCEVM : 
Is a technique that allows to modify java source code without restart or redeploy your packaging.

Second Step : Installation: 

The installation is so simple : 
1. You should download the jar file from dcevm site, there are many jar package for windows, mac and linux :
If you don't see your JVM version, you can get the sources and compil it to get the right version.

2. Now to lunch the installer under windows, you should write in command line the command : 
 java -jar dcevm-0.2-win.jar  


After this step, we will install the new JVM, to do this just click on install : 


3. To verify installation, you should turn application in debug mode.