/*
* This file is part of LibrePlan
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
* Copyright (C) 2010-2011 Igalia, S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.ws.common.impl;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.libreplan.business.common.IAdHocTransactionService;
import org.libreplan.business.common.IOnTransaction;
import org.libreplan.business.common.IntegrationEntity;
import org.libreplan.business.common.daos.IIntegrationEntityDAO;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.ws.common.api.InstanceConstraintViolationsDTO;
import org.libreplan.ws.common.api.InstanceConstraintViolationsListDTO;
import org.libreplan.ws.common.api.IntegrationEntityDTO;
import org.springframework.beans.factory.annotation.Autowired;
/**
* This class provides generic support for implementing REST services
* as subclasses of this. </code>.
*
* @author Fernando Bellas Permuy <fbellas@udc.es>
*/
public abstract class GenericRESTService<E extends IntegrationEntity,
DTO extends IntegrationEntityDTO> {
@Autowired
protected IAdHocTransactionService transactionService;
/**
* It retrieves all entities.
*/
protected List<DTO> findAll() {
return toDTO(getIntegrationEntityDAO().findAll());
}
/**
* It saves (inserts or updates) a list of entities. Each entity is
* saved in a separate transaction.
*/
protected InstanceConstraintViolationsListDTO save(
List<? extends DTO> entityDTOs) {
List<InstanceConstraintViolationsDTO> instanceConstraintViolationsList =
new ArrayList<InstanceConstraintViolationsDTO>();
long numItem = 1;
for (DTO entityDTO : entityDTOs) {
InstanceConstraintViolationsDTO instanceConstraintViolationsDTO =
null;
try {
insertOrUpdate(entityDTO);
} catch (ValidationException e) {
instanceConstraintViolationsDTO =
ConstraintViolationConverter.toDTO(
Util.generateInstanceConstraintViolationsDTOId(
numItem, entityDTO), e);
} catch (RecoverableErrorException e) {
instanceConstraintViolationsDTO =
ConstraintViolationConverter.toDTO(
Util.generateInstanceConstraintViolationsDTOId(
numItem, entityDTO), e);
} catch (RuntimeException e) {
instanceConstraintViolationsDTO =
ConstraintViolationConverter.toDTO(
Util.generateInstanceConstraintViolationsDTOId(
numItem, entityDTO), e);
}
if (instanceConstraintViolationsDTO != null) {
instanceConstraintViolationsList.add(
instanceConstraintViolationsDTO);
}
numItem++;
}
return new InstanceConstraintViolationsListDTO(
instanceConstraintViolationsList);
}
/**
* It saves (inserts or updates) an entity DTO by using a new transaction.
*
* @throws ValidationException if validations are not passed
* @throws RecoverableErrorException if a recoverable error occurs
*/
protected void insertOrUpdate(final DTO entityDTO)
throws ValidationException, RecoverableErrorException {
/*
* NOTE: ValidationException and RecoverableErrorException are runtime
* exceptions. In consequence, if any of them occurs, transaction is
* automatically rolled back.
*/
IOnTransaction<Void> save = new IOnTransaction<Void>() {
@Override
public Void execute() {
E entity = null;
IIntegrationEntityDAO<E> entityDAO =
getIntegrationEntityDAO();
/* Insert or update? */
try {
entity = entityDAO.findByCode(entityDTO.code);
updateEntity(entity, entityDTO);
} catch (InstanceNotFoundException e) {
entity = toEntity(entityDTO);
}
/*
* Validate and save (insert or update) the entity.
*/
entity.validate();
beforeSaving(entity);
entityDAO.saveWithoutValidating(entity);
afterSaving(entity);
return null;
}
};
transactionService.runOnAnotherTransaction(save);
}
/**
* It allows to add operations that must be done before saving.
*
* Default implementation is empty.
*/
protected void beforeSaving(E entity) {
}
/**
* It allows to add operations that must be done after saving.
*
* Default implementation is empty.
*/
protected void afterSaving(E entity) {
}
/**
* It creates an entity from a DTO.
*
* @throws ValidationException if it is not possible to create the entity
* because some very important constraint is violated
* @throws RecoverableErrorException if a recoverable
* error occurs
*/
protected abstract E toEntity(DTO entityDTO)
throws ValidationException, RecoverableErrorException;
/**
* It creates a DTO from an entity.
*/
protected abstract DTO toDTO(E entity);
/**
* It must return the DAO for the entity "E".
*/
protected abstract IIntegrationEntityDAO<E>
getIntegrationEntityDAO();
/**
* It must update the entity from the DTO.
*
* @throws ValidationException if updating is not possible because some
* very important constraint is violated
* @throws RecoverableErrorException if a recoverable error occurs
*/
protected abstract void updateEntity(E entity, DTO entityDTO)
throws ValidationException, RecoverableErrorException;
/**
* It returns a list of DTOs from a list of entities.
*/
protected List<DTO> toDTO(List<E> entities) {
List<DTO> dtos = new ArrayList<DTO>();
for (E entity : entities) {
dtos.add(toDTO(entity));
}
return dtos;
}
/**
* Returns a DTO searching by code. This will be useful for all REST
* services of IntegrationEntities
*
* @param code
* this is the code for the element which will be searched
* @return DTO which represents the IntegrationEntity with this code
* @throws InstanceNotFoundException
* If entity with this code is not found
*/
protected DTO findByCode(String code) throws InstanceNotFoundException {
return toDTO(getIntegrationEntityDAO().findByCode(code));
}
/**
* Wraps within a {@link Response} object the DTO searching the entity by
* code.
*
* If entity is not found returns 404 HTTP status code (NOT_FOUND).
*
* @param code
* this is the code for the element which will be searched
* @return The {@link Response} with DTO if OK or 404 if NOT_FOUND
*/
protected Response getDTOByCode(String code) {
try {
return Response.ok(findByCode(code)).build();
} catch (InstanceNotFoundException e) {
return Response.status(Status.NOT_FOUND).build();
}
}
}