/**
* Copyright (C) 2008-2010, Squale Project - http://www.squale.org
*
* This file is part of Squale.
*
* Squale is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or any later version.
*
* Squale is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Squale. If not, see <http://www.gnu.org/licenses/>.
*/
package org.squale.squaleweb.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpStatus;
import org.squale.jraf.commons.exception.JrafDaoException;
import org.squale.jraf.commons.exception.JrafEnterpriseException;
import org.squale.jraf.helper.AccessDelegateHelper;
import org.squale.jraf.spi.accessdelegate.IApplicationComponent;
import org.squale.squalecommon.datatransfertobject.component.AuditDTO;
import org.squale.squalecommon.datatransfertobject.component.ComponentDTO;
import org.squale.squalecommon.datatransfertobject.component.ModuleLightDTO;
import org.squale.squalecommon.datatransfertobject.component.UserDTO;
import org.squale.squalecommon.enterpriselayer.applicationcomponent.rest.RestComponentAccess;
import org.squale.squalerest.model.ApplicationRest;
import org.squale.squalerest.root.Applications;
import org.squale.squalerest.root.ByApplication;
import org.squale.squalerest.root.ByAudit;
import org.squale.squalerest.root.IRootObject;
import org.squale.squalerest.util.MimeType;
import org.squale.squaleweb.connection.AuthenticationBean;
import org.squale.squaleweb.connection.UserBeanAccessorHelper;
import org.squale.squaleweb.rest.util.TransformToXstreamObject;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
/**
* LoginTest
*/
public class RestServlet
extends HttpServlet
{
/**
* UID
*/
private static final long serialVersionUID = 8329888787227913756L;
/**
* log
*/
private static final Log LOG = LogFactory.getLog( RestComponentAccess.class );
/**
* Get method of http
*
* @param request The http servlet request
* @param response The http servlet response
*/
public void doGet( HttpServletRequest request, HttpServletResponse response )
{
try
{
// Authentication of the user and retrieve of its informations
UserDTO userDto = authent( request );
// If the authentication failed then userDto has for id : -1L
if ( userDto == null )
{
// If the user authentication failed, then the servlet return a 403 error page
String s = "Basic realm=\"Login Test Servlet Users\"";
response.setHeader( "WWW-Authenticate", s );
response.setStatus( HttpStatus.SC_UNAUTHORIZED );
}
else
{
// Else the servlet execute the search
String pathInfo = request.getPathInfo();
MimeType type = returnType( request );
Locale locale = request.getLocale();
IRootObject dataToWrite = prepareResponse( pathInfo, userDto, locale );
if ( dataToWrite != null )
{
response.setCharacterEncoding( "UTF-8" );
writeResponse( response, type, dataToWrite );
}
else
{
response.setStatus( HttpStatus.SC_NOT_IMPLEMENTED );
}
}
}
catch ( JrafEnterpriseException e )
{
LOG.error( "An error occurs during the rest execution", e );
response.setStatus( HttpStatus.SC_INTERNAL_SERVER_ERROR );
}
}
/**
* This method select the action to do according to the pathInfo
*
* @param pathInfo The information request by the user
* @param userDto The authenticated user
* @param locale The current locale
* @return The information request
* @throws JrafEnterpriseException Exception occurs during the search of the informations
*/
private IRootObject prepareResponse( String pathInfo, UserDTO userDto, Locale locale )
throws JrafEnterpriseException
{
IRootObject dataToReturn = null;
if ( pathInfo != null )
{
if ( pathInfo.matches( "/applications(/)?+" ) )
{
dataToReturn = applicationsFullInfo( userDto, locale,false);
}
else if ( pathInfo.matches( "/applications_full(/)?+" ) )
{
dataToReturn = applicationsFullInfo( userDto, locale,true) ;
}
else if ( pathInfo.matches( "/application/(\\d)++(/)?+" ) )
{
String[] splitPathInfo = pathInfo.split( "/application/" );
String info = cleanInfo( splitPathInfo[1] );
dataToReturn = byApplication( userDto, info, locale );
}
else if ( pathInfo.matches( "/audit/(\\d)++(/)?+" ) )
{
String[] splitPathInfo = pathInfo.split( "/audit/" );
String info = cleanInfo( splitPathInfo[1] );
dataToReturn = byAudit( userDto, info, locale );
}
}
return dataToReturn;
}
/**
* This method removes the slash "/" at the end of the string given in argument if there is one
*
* @param info The string to clean
* @return The cleaning string
*/
private String cleanInfo( String info )
{
String cleanInfo = info;
if ( cleanInfo.endsWith( "/" ) )
{
cleanInfo = cleanInfo.substring( 0, info.length() - 1 );
}
return cleanInfo;
}
/**
* This method retrieves the factor for the audit given in argument
*
* @param userDto The authenticated user
* @param auditId The audit id
* @param locale The current locale
* @return The data to write
* @throws JrafEnterpriseException Exceptions occurs during the search
*/
private ByApplication byAudit( UserDTO userDto, String auditId, Locale locale )
throws JrafEnterpriseException
{
ByApplication dataToReturn = new ByApplication();
IApplicationComponent ac = AccessDelegateHelper.getInstance( "rest" );
Object[] param = new Object[] { Long.parseLong( auditId ) };
AuditDTO audit = (AuditDTO) ac.execute( "audit", param );
if ( audit != null && audit.getID() != -1L )
{
ComponentDTO application = searchApp( userDto, Long.toString( audit.getApplicationId() ) );
if ( application != null )
{
param = new Object[] { (Long) application.getID(), (Long) audit.getID() };
List<ModuleLightDTO> moduleList = (List<ModuleLightDTO>) ac.execute( "moduleList", param );
ApplicationRest applicationRest = TransformToXstreamObject.createFullApplicationRest( audit, application, moduleList, locale );
dataToReturn.setApplication( applicationRest );
}
}
return dataToReturn;
}
/**
* This method retrieves the factor and the list of successful audit for the application which corresponding to the
* appId given in argument If the user has no rights for the application or if the application doesn't exist, then
* the method returns an empty ByApplication object
*
* @param userDto The authenticated user
* @param appId The application
* @param locale The current locale
* @return The factor and the list of successful audit for the application
* @throws JrafEnterpriseException Exception occurs during the search
*/
private ByApplication byApplication( UserDTO userDto, String appId, Locale locale )
throws JrafEnterpriseException
{
ByApplication data = new ByApplication();
ComponentDTO application = searchApp( userDto, appId );
if ( application != null )
{
ApplicationRest applicationRest = transformFullApplication( application, locale );
data.setApplication( applicationRest );
}
return data;
}
/**
* @param application
* @param locale
* @return
* @throws JrafEnterpriseException
*/
private ApplicationRest transformFullApplication( ComponentDTO application, Locale locale )
throws JrafEnterpriseException
{
Object[] param = new Object[] { (Long) application.getID() };
IApplicationComponent ac = AccessDelegateHelper.getInstance( "rest" );
List<AuditDTO> allSuccessfullAudit = (List<AuditDTO>) ac.execute( "availableAudits", param );
Long lastSuccessfulAuditId = (Long) allSuccessfullAudit.get( 0 ).getID();
List<AuditDTO> allPartialAudit = (List<AuditDTO>) ac.execute( "partialAudits", param );
List<AuditDTO> allFailedAudit = (List<AuditDTO>) ac.execute( "failedAudits", param );
param = new Object[] { (Long) application.getID(), lastSuccessfulAuditId };
List<ModuleLightDTO> moduleList = (List<ModuleLightDTO>) ac.execute( "moduleList", param );
return TransformToXstreamObject.createApplicationRestWithAudits( application, allSuccessfullAudit, allPartialAudit,
allFailedAudit, moduleList, locale );
}
/**
* This method tries to retrieve the application linked the technical given in argument. This method returns null if
* the application is not found
*
* @param userDto The current authentified user
* @param appId The technical id of the application to search
* @return The application found, null if it's not found
* @throws JrafEnterpriseException exception occurs during the search
*/
private ComponentDTO searchApp( UserDTO userDto, String appId )
throws JrafEnterpriseException
{
ComponentDTO application = null;
IApplicationComponent ac = AccessDelegateHelper.getInstance( "rest" );
Object[] param = new Object[] { userDto };
List<ComponentDTO> appList = (List<ComponentDTO>) ac.execute( "visibleApplication", param );
Iterator<ComponentDTO> it = appList.iterator();
boolean found = false;
while ( it.hasNext() && !found )
{
application = it.next();
if ( application.getID() == Long.parseLong( appId ) )
{
found = true;
}
}
return application;
}
/**
* This method retrieves the list of application available for the authenticated user and which has at least one
* successful audit
*
* @param userDto The authenticated user
* @param locale The current locale
* @param full All information for the application
* @return The list of application available for the authenticated user and which has at least one successful audit
* @throws JrafEnterpriseException Exceptions occurs during the search
*/
private Applications applicationsFullInfo( UserDTO userDto, Locale locale, boolean full )
throws JrafEnterpriseException
{
Applications data = new Applications();
IApplicationComponent ac = AccessDelegateHelper.getInstance( "rest" );
Object[] param = new Object[] { userDto };
List<ComponentDTO> appList = (List<ComponentDTO>) ac.execute( "visibleApplication", param );
ApplicationRest applicationRest = null;
for ( ComponentDTO application : appList )
{
if(full)
{
applicationRest = transformFullApplication( application, locale );
}
else
{
applicationRest = TransformToXstreamObject.createApplicationRest( application );
}
data.addApplication( applicationRest );
}
return data;
}
/**
* This method write the response
*
* @param response The servlet response
* @param type The mime type for the response
* @param dataToWrite The data to write
* @throws JrafEnterpriseException Exception occurs during the writing of the response
*/
private void writeResponse( HttpServletResponse response, MimeType type, IRootObject dataToWrite )
throws JrafEnterpriseException
{
try
{
PrintWriter out = response.getWriter();
if ( type == MimeType.xml )
{
response.setContentType( MimeType.xml.getRealValue() );
XStream xstream = new XStream();
xstream.processAnnotations( dataToWrite.getClass() );
xstream.toXML( dataToWrite, out );
}
else
{
response.setContentType( MimeType.json.getRealValue() );
XStream xstream = new XStream( new JsonHierarchicalStreamDriver() );
xstream.setMode( XStream.NO_REFERENCES );
xstream.processAnnotations( dataToWrite.getClass() );
xstream.toXML( dataToWrite, out );
}
}
catch ( IOException e )
{
throw new JrafEnterpriseException( e );
}
}
/**
* This method define the type of response to return : xml or json (by default it's xml)
*
* @param request The http servlet request
* @return The mime type for the servlet response
*/
private MimeType returnType( HttpServletRequest request )
{
MimeType type = MimeType.xml;
String acceptHeader = request.getHeader( "Accept" );
if ( acceptHeader != null && acceptHeader.equalsIgnoreCase( MimeType.json.getRealValue() ) )
{
type = MimeType.json;
}
return type;
}
/**
* This method do the authentication. It returns an empty UserBO if the authentication failed else it returns the
* UserBo corresponding the authenticated user.
*
* @param request The http servlet request
* @return an empty UserBO if the authentication failed, else the UserBO corresponding to the authenticated user
* @throws JrafEnterpriseException Exception occurs during the authentication
* @throws JrafDaoException
*/
private UserDTO authent( HttpServletRequest request )
throws JrafEnterpriseException
{
UserDTO userDto = null;
String authHeader = request.getHeader( "Authorization" );
if ( authHeader != null )
{
StringTokenizer st = new StringTokenizer( authHeader );
if ( st.hasMoreTokens() )
{
String basic = st.nextToken();
// We only handle HTTP Basic authentication
if ( basic.equalsIgnoreCase( "Basic" ) )
{
String credentials = st.nextToken();
Base64 deco = new Base64();
String userPass = new String( deco.decode( credentials.getBytes() ) );
userDto = authentSearch( userPass );
}
}
}
return userDto;
}
/**
* This method search the user which corresponding to the credential given in argument. If no corresponding user is
* found, an empty user object is return.
*
* @param userPass The http header credential
* @param session
* @return The user found
* @throws JrafEnterpriseException Exception occurs during the search
* @throws JrafDaoException
*/
private UserDTO authentSearch( String userPass )
throws JrafEnterpriseException
{
UserDTO userToReturn = null;
int p = userPass.indexOf( ":" );
if ( p != -1 )
{
String userID = userPass.substring( 0, p );
String password = userPass.substring( p + 1 );
if ( ( !userID.trim().equals( "" ) ) && ( !password.trim().equals( "" ) ) )
{
UserDTO userDto = new UserDTO( userID, password );
AuthenticationBean isUser = UserBeanAccessorHelper.getUserBeanAccessor().isUser( userDto );
if ( isUser != null && isUser.getIdentifier() != null )
{
IApplicationComponent ac = AccessDelegateHelper.getInstance( "Login" );
Object[] param = new Object[] { userDto };
userToReturn = (UserDTO) ac.execute( "getUserByIdentifier", param );
}
}
}
return userToReturn;
}
}