raimund@488: /* Copyright (C) 2013 by Bundesamt fuer Strahlenschutz raimund@488: * Software engineering by Intevation GmbH raimund@488: * rrenkert@628: * This file is Free Software under the GNU GPL (v>=3) rrenkert@628: * and comes with ABSOLUTELY NO WARRANTY! Check out rrenkert@628: * the documentation coming with IMIS-Labordaten-Application for details. raimund@488: */ raimund@488: package de.intevation.lada.rest; raimund@488: raimund@787: import java.util.List; raimund@787: raimund@488: import javax.enterprise.context.RequestScoped; raimund@488: import javax.inject.Inject; raimund@582: import javax.servlet.http.HttpServletRequest; raimund@488: import javax.ws.rs.DELETE; raimund@488: import javax.ws.rs.GET; raimund@488: import javax.ws.rs.POST; raimund@488: import javax.ws.rs.PUT; raimund@488: import javax.ws.rs.Path; raimund@488: import javax.ws.rs.PathParam; raimund@488: import javax.ws.rs.Produces; raimund@488: import javax.ws.rs.core.Context; raimund@488: import javax.ws.rs.core.HttpHeaders; raimund@488: import javax.ws.rs.core.MediaType; raimund@488: import javax.ws.rs.core.MultivaluedMap; raimund@488: import javax.ws.rs.core.UriInfo; raimund@488: raimund@787: import org.apache.log4j.Logger; raimund@787: raimund@595: import de.intevation.lada.lock.LockConfig; raimund@595: import de.intevation.lada.lock.LockType; raimund@595: import de.intevation.lada.lock.ObjectLocker; raimund@747: import de.intevation.lada.model.land.LMessung; raimund@745: import de.intevation.lada.model.land.LStatusProtokoll; raimund@488: import de.intevation.lada.util.annotation.AuthorizationConfig; raimund@488: import de.intevation.lada.util.annotation.RepositoryConfig; raimund@488: import de.intevation.lada.util.auth.Authorization; raimund@488: import de.intevation.lada.util.auth.AuthorizationType; raimund@774: import de.intevation.lada.util.auth.UserInfo; raimund@488: import de.intevation.lada.util.data.QueryBuilder; raimund@488: import de.intevation.lada.util.data.Repository; raimund@488: import de.intevation.lada.util.data.RepositoryType; raimund@582: import de.intevation.lada.util.rest.RequestMethod; raimund@488: import de.intevation.lada.util.rest.Response; raimund@787: import de.intevation.lada.validation.Validator; raimund@787: import de.intevation.lada.validation.Violation; raimund@787: import de.intevation.lada.validation.annotation.ValidationConfig; raimund@488: rrenkert@628: /** rrenkert@628: * REST service for Status objects. rrenkert@628: *

rrenkert@628: * The services produce data in the application/json media type. rrenkert@628: * All HTTP methods use the authorization module to determine if the user is rrenkert@628: * allowed to perform the requested action. rrenkert@628: * A typical response holds information about the action performed and the data. rrenkert@628: *

rrenkert@628:  * 
rrenkert@628:  * {
rrenkert@628:  *  "success": [boolean];
rrenkert@628:  *  "message": [string],
rrenkert@628:  *  "data":[{
rrenkert@628:  *      "id": [number],
rrenkert@628:  *      "erzeuger": [string],
rrenkert@628:  *      "messungsId": [number],
rrenkert@628:  *      "status": [number],
rrenkert@628:  *      "owner": [boolean],
rrenkert@628:  *      "readonly": [boolean],
rrenkert@628:  *      "treeModified": [timestamp],
rrenkert@628:  *      "parentModified": [timestamp],
rrenkert@628:  *      "sdatum": [timestamp],
rrenkert@628:  *      "skommentar": [string]
rrenkert@628:  *  }],
rrenkert@628:  *  "errors": [object],
rrenkert@628:  *  "warnings": [object],
rrenkert@628:  *  "readonly": [boolean],
rrenkert@628:  *  "totalCount": [number]
rrenkert@628:  * }
rrenkert@628:  * 
rrenkert@628:  * 
rrenkert@628: * rrenkert@628: * @author Raimund Renkert rrenkert@628: */ raimund@488: @Path("status") raimund@488: @RequestScoped raimund@488: public class StatusService { raimund@488: raimund@787: @Inject raimund@787: private Logger logger = Logger.getLogger(StatusService.class); raimund@787: rrenkert@628: /** rrenkert@628: * The data repository granting read/write access. rrenkert@628: */ raimund@488: @Inject raimund@488: @RepositoryConfig(type=RepositoryType.RW) raimund@488: private Repository defaultRepo; raimund@488: rrenkert@628: /** rrenkert@628: * The object lock mechanism. rrenkert@628: */ raimund@595: @Inject raimund@595: @LockConfig(type=LockType.TIMESTAMP) raimund@595: private ObjectLocker lock; raimund@595: rrenkert@628: /** rrenkert@628: * The authorization module. rrenkert@628: */ raimund@488: @Inject raimund@722: @AuthorizationConfig(type=AuthorizationType.HEADER) raimund@488: private Authorization authorization; raimund@488: raimund@787: @Inject raimund@787: @ValidationConfig(type="Status") raimund@787: private Validator validator; raimund@787: raimund@488: /** rrenkert@628: * Get all Status objects. rrenkert@628: *

rrenkert@628: * The requested objects can be filtered using a URL parameter named raimund@711: * messungsId. rrenkert@628: *

rrenkert@628: * Example: http://example.com/status?messungsId=[ID] raimund@488: * rrenkert@628: * @return Response object containing all Status objects. raimund@488: */ raimund@488: @GET raimund@488: @Path("/") raimund@488: @Produces(MediaType.APPLICATION_JSON) raimund@488: public Response get( raimund@488: @Context HttpHeaders headers, raimund@582: @Context UriInfo info, raimund@582: @Context HttpServletRequest request raimund@488: ) { raimund@488: MultivaluedMap params = info.getQueryParameters(); raimund@556: if (params.isEmpty() || !params.containsKey("messungsId")) { raimund@745: return defaultRepo.getAll(LStatusProtokoll.class, "land"); raimund@488: } raimund@556: String messungId = params.getFirst("messungsId"); raimund@745: QueryBuilder builder = raimund@745: new QueryBuilder( raimund@488: defaultRepo.entityManager("land"), raimund@745: LStatusProtokoll.class); raimund@488: builder.and("messungsId", messungId); raimund@582: return authorization.filter( raimund@582: request, raimund@582: defaultRepo.filter(builder.getQuery(), "land"), raimund@745: LStatusProtokoll.class); raimund@488: } raimund@488: raimund@488: /** rrenkert@628: * Get a single Status object by id. rrenkert@628: *

rrenkert@628: * The id is appended to the URL as a path parameter. rrenkert@628: *

rrenkert@628: * Example: http://example.com/status/{id} raimund@488: * rrenkert@628: * @return Response object containing a single Status. raimund@488: */ raimund@488: @GET raimund@488: @Path("/{id}") raimund@488: @Produces(MediaType.APPLICATION_JSON) raimund@488: public Response getById( raimund@488: @Context HttpHeaders headers, raimund@582: @Context HttpServletRequest request, raimund@488: @PathParam("id") String id raimund@488: ) { raimund@787: Response response = defaultRepo.getById( raimund@787: LStatusProtokoll.class, raimund@787: Integer.valueOf(id), raimund@787: "land"); raimund@787: LStatusProtokoll status = (LStatusProtokoll)response.getData(); raimund@787: Violation violation = validator.validate(status); raimund@787: if (violation.hasErrors() || violation.hasWarnings()) { raimund@787: response.setErrors(violation.getErrors()); raimund@787: response.setWarnings(violation.getWarnings()); raimund@787: } raimund@787: raimund@582: return authorization.filter( raimund@582: request, raimund@787: response, raimund@745: LStatusProtokoll.class); raimund@488: } raimund@488: rrenkert@628: /** rrenkert@628: * Create a Status object. rrenkert@628: *

rrenkert@628: * The new object is embedded in the post data as JSON formatted string. rrenkert@628: *

rrenkert@628: *

rrenkert@628:      * 
rrenkert@628:      * {
rrenkert@628:      *  "owner": [boolean],
rrenkert@628:      *  "messungsId": [number],
rrenkert@628:      *  "erzeuger": [string],
rrenkert@628:      *  "status": [number],
rrenkert@628:      *  "skommentar": [string],
rrenkert@628:      *  "treeModified":null,
rrenkert@628:      *  "parentModified":null,
rrenkert@628:      *  "sdatum": [date]
rrenkert@628:      * }
rrenkert@628:      * 
rrenkert@628:      * 
rrenkert@628: * rrenkert@628: * @return A response object containing the created Status. rrenkert@628: */ raimund@488: @POST raimund@488: @Path("/") raimund@488: @Produces(MediaType.APPLICATION_JSON) raimund@488: public Response create( raimund@488: @Context HttpHeaders headers, raimund@582: @Context HttpServletRequest request, raimund@745: LStatusProtokoll status raimund@488: ) { raimund@582: if (!authorization.isAuthorized( raimund@582: request, raimund@582: status, raimund@582: RequestMethod.POST, raimund@745: LStatusProtokoll.class) raimund@582: ) { raimund@488: return new Response(false, 699, null); raimund@488: } raimund@774: UserInfo userInfo = authorization.getInfo(request); raimund@774: LMessung messung = defaultRepo.getByIdPlain( raimund@774: LMessung.class, status.getMessungsId(), "land"); raimund@774: boolean next = false; raimund@774: boolean change = false; raimund@778: if (messung.getStatus() == null) { raimund@774: status.setStatusStufe(1); raimund@774: } raimund@774: else { raimund@778: LStatusProtokoll currentStatus = defaultRepo.getByIdPlain( raimund@778: LStatusProtokoll.class, messung.getStatus(), "land"); raimund@778: for (int i = 0; i < userInfo.getFunktionen().size(); i++) { raimund@778: if (userInfo.getFunktionen().get(i) > currentStatus.getStatusStufe()) { raimund@778: next = true; raimund@778: change = false; raimund@778: break; raimund@778: } raimund@778: else if (userInfo.getFunktionen().get(i) == currentStatus.getStatusStufe()) { raimund@778: change = true; raimund@778: } raimund@778: } raimund@778: if ((change || next) && status.getStatusWert() == 4) { raimund@778: status.setStatusStufe(1); raimund@778: } raimund@778: else if (change) { raimund@778: status.setStatusStufe(currentStatus.getStatusStufe()); raimund@778: } raimund@778: else if (next) { raimund@778: status.setStatusStufe(currentStatus.getStatusStufe() + 1); raimund@778: } raimund@778: else { raimund@778: return new Response(false, 699, null); raimund@778: } raimund@774: } raimund@787: Violation violation = validator.validate(status); raimund@787: if (violation.hasErrors()) { raimund@787: Response response = new Response(false, 604, status); raimund@787: response.setErrors(violation.getErrors()); raimund@787: response.setWarnings(violation.getWarnings()); raimund@787: return response; raimund@787: } raimund@747: Response response = defaultRepo.create(status, "land"); raimund@747: LStatusProtokoll created = (LStatusProtokoll)response.getData(); raimund@747: messung.setStatus(created.getId()); raimund@747: defaultRepo.update(messung, "land"); raimund@488: /* Persist the new object*/ raimund@601: return authorization.filter( raimund@601: request, raimund@747: response, raimund@745: LStatusProtokoll.class); raimund@488: } raimund@488: raimund@488: /** rrenkert@628: * Update an existing Status object. rrenkert@628: *

rrenkert@628: * The object to update should come as JSON formatted string. rrenkert@628: *

rrenkert@628:      * 
rrenkert@628:      * {
rrenkert@628:      *  "id": [number],
rrenkert@628:      *  "owner": [boolean],
rrenkert@628:      *  "messungsId": [number],
rrenkert@628:      *  "erzeuger": [string],
rrenkert@628:      *  "status": [number],
rrenkert@628:      *  "skommentar": [string],
rrenkert@628:      *  "treeModified": [timestamp],
rrenkert@628:      *  "parentModified": [timestamp],
rrenkert@628:      *  "sdatum": [date]
rrenkert@628:      * }
rrenkert@628:      * 
rrenkert@628:      * 
raimund@488: * rrenkert@628: * @return Response object containing the updated Status object. raimund@488: */ raimund@488: @PUT raimund@557: @Path("/{id}") raimund@488: @Produces(MediaType.APPLICATION_JSON) raimund@582: public Response update( raimund@582: @Context HttpHeaders headers, raimund@582: @Context HttpServletRequest request, raimund@745: LStatusProtokoll status raimund@582: ) { raimund@595: if (lock.isLocked(status)) { raimund@595: return new Response(false, 697, null); raimund@595: } raimund@774: raimund@774: UserInfo userInfo = authorization.getInfo(request); raimund@774: if (!userInfo.getMessstellen().contains(status.getErzeuger())) { raimund@774: return new Response(false, 699, null); raimund@774: } raimund@774: LMessung messung = defaultRepo.getByIdPlain( raimund@774: LMessung.class, status.getMessungsId(), "land"); raimund@777: LStatusProtokoll statusNew = new LStatusProtokoll(); raimund@777: statusNew.setDatum(status.getDatum()); raimund@777: statusNew.setErzeuger(status.getErzeuger()); raimund@777: statusNew.setMessungsId(status.getMessungsId()); raimund@777: statusNew.setStatusStufe(status.getStatusStufe()); raimund@777: statusNew.setStatusWert(status.getStatusWert()); raimund@777: statusNew.setText(status.getText()); raimund@787: Violation violation = validator.validate(statusNew); raimund@787: if (violation.hasErrors()) { raimund@787: Response response = new Response(false, 604, statusNew); raimund@787: response.setErrors(violation.getErrors()); raimund@787: response.setWarnings(violation.getWarnings()); raimund@787: return response; raimund@787: } raimund@787: raimund@777: Response response = defaultRepo.create(statusNew, "land"); raimund@774: LStatusProtokoll created = (LStatusProtokoll)response.getData(); raimund@774: messung.setStatus(created.getId()); raimund@774: defaultRepo.update(messung, "land"); raimund@774: raimund@601: return authorization.filter( raimund@601: request, raimund@774: response, raimund@745: LStatusProtokoll.class); raimund@488: } raimund@488: raimund@488: /** rrenkert@628: * Delete an existing Status object by id. rrenkert@628: *

rrenkert@628: * The id is appended to the URL as a path parameter. rrenkert@628: *

rrenkert@628: * Example: http://example.com/status/{id} raimund@488: * raimund@488: * @return Response object. raimund@488: */ raimund@488: @DELETE raimund@488: @Path("/{id}") raimund@488: @Produces(MediaType.APPLICATION_JSON) raimund@488: public Response delete( raimund@488: @Context HttpHeaders headers, raimund@582: @Context HttpServletRequest request, raimund@488: @PathParam("id") String id raimund@488: ) { raimund@488: /* Get the object by id*/ raimund@488: Response object = raimund@745: defaultRepo.getById(LStatusProtokoll.class, Integer.valueOf(id), "land"); raimund@745: LStatusProtokoll obj = (LStatusProtokoll)object.getData(); raimund@582: if (!authorization.isAuthorized( raimund@582: request, raimund@582: obj, raimund@582: RequestMethod.DELETE, raimund@745: LStatusProtokoll.class) raimund@582: ) { raimund@582: return new Response(false, 699, null); raimund@582: } raimund@595: if (lock.isLocked(obj)) { raimund@595: return new Response(false, 697, null); raimund@595: } raimund@488: /* Delete the object*/ raimund@488: return defaultRepo.delete(obj, "land"); raimund@488: } raimund@488: }