/* * FinTP - Financial Transactions Processing Application * Copyright (C) 2013 Business Information Systems (Allevo) S.R.L. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/> * or contact Allevo at : 031281 Bucuresti, 23C Calea Vitan, Romania, * phone +40212554577, office@allevo.ro <mailto:office@allevo.ro>, www.allevo.ro. */ package ro.allevo.fintpws.resources; import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityNotFoundException; import javax.persistence.Query; import javax.persistence.RollbackException; import javax.persistence.TypedQuery; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.Response.Status; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; import org.springframework.security.access.AccessDeniedException; import ro.allevo.fintpws.exceptions.ApplicationJsonException; import ro.allevo.fintpws.model.EntryQueueEntity; import ro.allevo.fintpws.model.QueueEntity; import ro.allevo.fintpws.model.RoutedMessageEntity; import ro.allevo.fintpws.model.messagesViews.MessageTypeToViewsEnum; import ro.allevo.fintpws.model.messagesViews.MtView; import ro.allevo.fintpws.security.RolesUtils; import ro.allevo.fintpws.util.JsonResponseWrapper; import ro.allevo.fintpws.util.ReflectionUtils; import ro.allevo.fintpws.util.ResourcesUtils; /** * Resource class implementing /messages/{id} path methods. * * @author costi * @version $Revision: 1.0 $ */ public class MessageResource { /** * Field logger. */ private static Logger logger = LogManager.getLogger(MessageResource.class .getName()); /** * Field ERROR_MESSAGE_GET_MESSAGE. (value is ""Error returning message : * "") */ static final String ERROR_MESSAGE_GET_MESSAGE = "Error returning message : "; /** * Field ERROR_MESSAGE_PUT_MESSAGE. (value is ""Error updating message : "") */ static final String ERROR_MESSAGE_PUT_MESSAGE = "Error updating message : "; /** * Field ERROR_MESSAGE_Q_NOT_FOUND. (value is ""Queue with name [%s] not * found"") */ static final String ERROR_MESSAGE_M_NOT_FOUND = "Message with guid [%s] not found"; /** * Field ERROR_REASON_JSON. (value is ""json"") */ static final String ERROR_REASON_JSON = "json"; /** * Field ERROR_REASON_NUMBER_FORMAT. (value is ""number format"") */ static final String ERROR_REASON_NUMBER_FORMAT = "number format"; /** * Field ERROR_REASON_TIME_FORMAT. (value is ""time format"") */ static final String ERROR_REASON_TIME_FORMAT = "time format"; /** * Field ERROR_REASON_ROLLBACK. (value is ""rollback"") */ static final String ERROR_REASON_ROLLBACK = "rollback"; /** * Field ERROR_REASON_REFLECTION_ERROR. * (value is ""reflection error"") */ static final String ERROR_REASON_REFLECTION_ERROR = "reflection error"; // actual uri info provided by parent resource /** * Field uriInfo. */ private UriInfo uriInfo; /** * Field entityManagerData. */ private EntityManager entityManagerData; /** * Field entityManagerConfig. */ private EntityManager entityManagerConfig; // the JPA entity /** * Field messageEntity. */ private RoutedMessageEntity messageEntity; /** * Field messageQueueEntity. */ private EntryQueueEntity messageQueueEntity; /** * Field viewEntity */ private MtView viewEntity; /** * Field isMessageInQueue. */ private boolean isMessageInQueue = false; /** * Field needsPayload. */ private boolean needsPayload = false; /** * Field messageId. */ private String messageId; /** * Field queueEntity. */ private QueueEntity queueEntity = null; /** * Creates a new instance of MessageResource * * @param uriInfo * UriInfo actual uri passed by parent resource * @param entityManagerData * EntityManager passed by parent resource * * @param messageId * String * @param isMessageInQueue * boolean * @param needsPayload * boolean * @param entityManagerConfig EntityManager */ public MessageResource(UriInfo uriInfo, EntityManager entityManagerData, EntityManager entityManagerConfig, String messageId, boolean isMessageInQueue, boolean needsPayload, QueueEntity queueEntity) { this.uriInfo = uriInfo; this.entityManagerData = entityManagerData; this.entityManagerConfig = entityManagerConfig; this.messageEntity = null; this.isMessageInQueue = isMessageInQueue; this.needsPayload = needsPayload; this.messageId = messageId; this.queueEntity = queueEntity; if(uriInfo.getQueryParameters().containsKey("type")){ MessageTypeToViewsEnum messageType = MessageTypeToViewsEnum .getMessageType(uriInfo.getQueryParameters().getFirst( "type")); Query query = messageType.getFindByGuidQuery(entityManagerData, messageId); @SuppressWarnings("unchecked") List<? extends MtView> results = query.getResultList(); if(!results.isEmpty()){ viewEntity = results.get(0); } return; } if(isMessageInQueue){ TypedQuery<EntryQueueEntity> query = entityManagerData.createNamedQuery( "EntryQueueEntity.findByGuid", EntryQueueEntity.class); List<EntryQueueEntity> results = query.setHint("eclipselink.left-join-fetch", "b.routedmessage") .setParameter("guid", messageId).getResultList(); if (!results.isEmpty()) { messageQueueEntity = results.get(0); } }else{ TypedQuery<RoutedMessageEntity> query = entityManagerData.createNamedQuery( "RoutedMessageEntity.findByGuid", RoutedMessageEntity.class); List<RoutedMessageEntity> results = query.setParameter("guid", messageId).getResultList(); if (!results.isEmpty()) { messageEntity = results.get(0); } } } /** * Method findDetailsMessage. * @param message JSONObject * @return JSONObject * @throws IllegalAccessException * @throws InstantiationException * @throws ClassNotFoundException * @throws JSONException * @throws NoSuchMethodException * @throws InvocationTargetException * @throws SecurityException * @throws IllegalArgumentException */ public JSONObject findDetailsMessage(JSONObject message) throws IllegalAccessException, InstantiationException, ClassNotFoundException, JSONException, IllegalArgumentException, SecurityException { String msgType = ""; if (null == messageEntity) { if ( null != messageQueueEntity.getRoutedmessage()) { msgType = messageQueueEntity.getRoutedmessage().getMsgtype(); } } else { if ( null != messageEntity.getMsgtype()) { msgType = messageEntity.getMsgtype(); } } TypedQuery<String> query = entityManagerConfig.createNamedQuery( "MsgTypeListEntity.findByMsgType", String.class); List<String> results = query.setParameter("messagetype", msgType).getResultList(); if (!results.isEmpty()) { //get table name with message details (Ex. ro.allevo.fintpws.resources.Mt103tab) //RoutedMessageEntity and Mt103tab(Mt202tab etc) are in the same package String tableNameMessageDetails = RoutedMessageEntity.class.getPackage().getName() + "." + StringUtils.capitalize(results.get(0).toLowerCase()) + "Entity"; Object entityDetailsMessage = Class.forName(tableNameMessageDetails).newInstance(); entityDetailsMessage = entityManagerData.find( entityDetailsMessage.getClass(), messageEntity.getCorrelationid()); if( null != entityDetailsMessage){ return ReflectionUtils.asReflectedJson(entityDetailsMessage, message); } } return message; } /** * GET method : returns an application/json formatted message * @return JSONObject the message */ @GET @Produces(MediaType.APPLICATION_JSON) public JSONObject getMessage() { // authorization if (isMessageInQueue) { if (!RolesUtils.hasReadAuthorityOnQueue(queueEntity)) { throw new ApplicationJsonException(new AccessDeniedException("forbidden"), "forbidden", Status.FORBIDDEN.getStatusCode()); } } else { if (!RolesUtils.hasReportsRole()) { throw new ApplicationJsonException(new AccessDeniedException("forbidden"), "forbidden", Status.FORBIDDEN.getStatusCode()); } } if (null == messageEntity && null == messageQueueEntity && null == viewEntity) { logger.error(String.format(ERROR_MESSAGE_M_NOT_FOUND, messageId)); throw new EntityNotFoundException(String.format( ERROR_MESSAGE_M_NOT_FOUND, messageId)); } try { if(null != viewEntity){ return viewEntity.toJSON(); } if (null == messageEntity){ return findDetailsMessage(MessageResource.asJson( messageQueueEntity, isMessageInQueue, needsPayload, uriInfo.getPath())); }else{ return findDetailsMessage(MessageResource.asJson( messageEntity, isMessageInQueue, needsPayload, uriInfo.getPath())); } } catch (JSONException je) { logger.error(ERROR_MESSAGE_GET_MESSAGE + ERROR_REASON_JSON, je); throw new ApplicationJsonException(je, ERROR_MESSAGE_GET_MESSAGE + ERROR_REASON_JSON, Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); } catch (IllegalAccessException ias) { logger.error(ERROR_MESSAGE_GET_MESSAGE + ERROR_REASON_JSON, ias); throw new ApplicationJsonException(ias, ERROR_MESSAGE_GET_MESSAGE + ERROR_REASON_REFLECTION_ERROR, Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); } catch (InstantiationException ie) { logger.error(ERROR_MESSAGE_GET_MESSAGE + ERROR_REASON_JSON, ie); throw new ApplicationJsonException(ie, ERROR_MESSAGE_GET_MESSAGE + ERROR_REASON_REFLECTION_ERROR, Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); } catch (ClassNotFoundException clnfe) { logger.error(ERROR_MESSAGE_GET_MESSAGE + ERROR_REASON_JSON, clnfe); throw new ApplicationJsonException(clnfe, ERROR_MESSAGE_GET_MESSAGE + ERROR_REASON_REFLECTION_ERROR, Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); } catch (IllegalArgumentException e) { throw new ApplicationJsonException(e, ERROR_MESSAGE_GET_MESSAGE + ERROR_REASON_REFLECTION_ERROR, Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); } catch (SecurityException e) { throw new ApplicationJsonException(e, ERROR_MESSAGE_GET_MESSAGE + ERROR_REASON_REFLECTION_ERROR, Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); } } /** * Method getEvents. * * @return EventsResource */ @Path("events") public EventsResource getEvents() { if (null == this.messageEntity) { logger.error(String.format(ERROR_MESSAGE_M_NOT_FOUND, this.messageId)); throw new EntityNotFoundException(String.format( ERROR_MESSAGE_M_NOT_FOUND, this.messageId)); } return new EventsResource(uriInfo, entityManagerData, messageEntity); } /** * PUT method : updates the message * @param jsonEntity * JSONObject the message holding new values * @return Response */ @PUT @Consumes(MediaType.APPLICATION_JSON) public Response updateMessage(JSONObject jsonEntity) { if (isMessageInQueue) { if (!RolesUtils.hasWriteAuthorityOnQueue(queueEntity)) { throw new ApplicationJsonException(new AccessDeniedException("forbidden"), "forbidden", Status.FORBIDDEN.getStatusCode()); } } else { if (!RolesUtils.hasReportsRole()) { throw new ApplicationJsonException(new AccessDeniedException("forbidden"), "forbidden", Status.FORBIDDEN.getStatusCode()); } } if (null == messageQueueEntity) { logger.error(String.format(ERROR_MESSAGE_M_NOT_FOUND, messageId)); throw new EntityNotFoundException(String.format( ERROR_MESSAGE_M_NOT_FOUND, messageId)); } try { if(jsonEntity.has("guid")){ messageQueueEntity.setGuid(jsonEntity.getString("guid")); } if(jsonEntity.has("batchid")){ messageQueueEntity.setBatchid(jsonEntity.optString("batchid")); } if(jsonEntity.has("correlationid")){ messageQueueEntity.setCorrelationid(jsonEntity.optString("correlationid")); } if(jsonEntity.has("requestorservice")){ messageQueueEntity.setRequestorservice(jsonEntity .getString("requestorservice")); } if(jsonEntity.has("responderservice")){ messageQueueEntity.setResponderservice(jsonEntity .optString("responderservice")); } if(jsonEntity.has("requesttype")){ messageQueueEntity .setRequesttype(jsonEntity.getString("requesttype")); } if(jsonEntity.has("feedback")){ messageQueueEntity.setFeedback(jsonEntity.optString("feedback")); } if(jsonEntity.has("sessionid")){ messageQueueEntity.setSessionid(jsonEntity.optString("sessionid")); } if(jsonEntity.has("priority")){ messageQueueEntity.setPriority(new BigDecimal(jsonEntity .getInt("priority"))); } if(jsonEntity.has("holdstatus")){ messageQueueEntity.setHoldstatus(new BigDecimal(jsonEntity .getInt("holdstatus"))); } if(jsonEntity.has("sequence")){ messageQueueEntity.setSequence(new BigDecimal(jsonEntity .getInt("sequence"))); } if(jsonEntity.has("payload")){ messageQueueEntity.setPayload(jsonEntity.getString("payload")); } if(jsonEntity.has("queuename")){ messageQueueEntity.setQueuename(jsonEntity.getString("queuename")); } entityManagerData.getTransaction().begin(); entityManagerData.merge(messageQueueEntity); entityManagerData.getTransaction().commit(); } catch (JSONException je) { logger.error(ERROR_MESSAGE_PUT_MESSAGE + ERROR_REASON_JSON, je); throw new ApplicationJsonException(je, ERROR_MESSAGE_PUT_MESSAGE + ERROR_REASON_JSON, Response.Status.BAD_REQUEST.getStatusCode()); } catch (NumberFormatException nfe) { logger.error( ERROR_MESSAGE_PUT_MESSAGE + ERROR_REASON_NUMBER_FORMAT, nfe); throw new ApplicationJsonException(nfe, ERROR_MESSAGE_PUT_MESSAGE + ERROR_REASON_NUMBER_FORMAT, Response.Status.BAD_REQUEST.getStatusCode()); } catch (RollbackException re) { // traverse the cause to find a possible constraint violation ApplicationJsonException.handleSQLException(re, ERROR_MESSAGE_PUT_MESSAGE, logger); // log and rethrow the original error logger.error(ERROR_MESSAGE_PUT_MESSAGE + ERROR_REASON_ROLLBACK, re); throw re; } finally { // Tomcat does not support container managed transactions if (null != entityManagerData) { entityManagerData.close(); } } return JsonResponseWrapper.getResponse(Response.Status.OK, "message updated"); } /** * DELETE method : deletes the message * @return Response */ @DELETE public Response deleteMessage() { if (isMessageInQueue) { if (!RolesUtils.hasWriteAuthorityOnQueue(queueEntity)) { throw new ApplicationJsonException(new AccessDeniedException("forbidden"), "forbidden", Status.FORBIDDEN.getStatusCode()); } } else { if (!RolesUtils.hasReportsRole()) { throw new ApplicationJsonException(new AccessDeniedException("forbidden"), "forbidden", Status.FORBIDDEN.getStatusCode()); } } if (null == messageEntity && null == messageQueueEntity ) { logger.error(String.format(ERROR_MESSAGE_M_NOT_FOUND, messageId)); throw new EntityNotFoundException(String.format( ERROR_MESSAGE_M_NOT_FOUND, messageId)); } try { entityManagerData.getTransaction().begin(); entityManagerData.remove((null == messageEntity)?messageQueueEntity:messageEntity); entityManagerData.getTransaction().commit(); } finally { if (null != entityManagerData) { entityManagerData.close(); } } return JsonResponseWrapper.getResponse(Response.Status.OK, "message deleted"); } /** * Returns the resource formatted as json * * @param messageEntity * BusinessMessage * @param path * String * @param isMessageInQueue * boolean * @param needsPayload * boolean * @return JSONObject * @throws JSONException */ public static JSONObject asJson(RoutedMessageEntity messageEntity, boolean isMessageInQueue, boolean needsPayload, String path) throws JSONException { JSONObject messageAsJson = ApiResource.getMetaResource(path, MessageResource.class); messageAsJson.put("guid", messageEntity.getGuid()) .put("batchid", messageEntity.getEntryQueue().getBatchid()) .put("correlationid", messageEntity.getEntryQueue().getCorrelationid()) .put("responderservice", messageEntity.getEntryQueue().getResponderservice()) .put("requestorservice", messageEntity.getEntryQueue().getRequestorservice()) .put("requesttype", messageEntity.getEntryQueue().getRequesttype()) .put("feedback", messageEntity.getEntryQueue().getFeedback()) .put("sessionid", messageEntity.getEntryQueue().getSessionid()) .put("priority", messageEntity.getEntryQueue().getPriority()) .put("holdstatus", messageEntity.getEntryQueue().getHoldstatus()) .put("sequence", messageEntity.getEntryQueue().getSequence()) .put("msgtype", messageEntity.getMsgtype()) .put("sender", messageEntity.getSender()) .put("receiver", messageEntity.getReceiver()) .put("trn", messageEntity.getTrn()) .put("currentqueue", messageEntity.getCurrentqueue()) .put("amount", messageEntity.getAmount()); if (needsPayload){ messageAsJson.put("payload", messageEntity.getEntryQueue() .getPayload()); } ResourcesUtils.createLink(messageAsJson, path + "/events", "events"); return messageAsJson; } public static JSONObject asJson(EntryQueueEntity messageEntity, boolean isMessageInQueue, boolean needsPayload, String path) throws JSONException { JSONObject messageAsJson = ApiResource.getMetaResource(path, MessageResource.class); messageAsJson.put("guid", messageEntity.getGuid()) .put("batchid", messageEntity.getBatchid()) .put("correlationid", messageEntity.getCorrelationid()) .put("responderservice", messageEntity.getResponderservice()) .put("requestorservice", messageEntity.getRequestorservice()) .put("requesttype", messageEntity.getRequesttype()) .put("feedback", messageEntity.getFeedback()) .put("sessionid", messageEntity.getSessionid()) .put("priority", messageEntity.getPriority()) .put("holdstatus", messageEntity.getHoldstatus()) .put("sequence", messageEntity.getSequence()) .put("queuename", messageEntity.getQueuename()); if( null != messageEntity.getRoutedmessage()){ messageAsJson .put("msgtype", messageEntity.getRoutedmessage().getMsgtype()) .put("sender", messageEntity.getRoutedmessage().getSender()) .put("receiver", messageEntity.getRoutedmessage().getReceiver()) .put("trn", messageEntity.getRoutedmessage().getTrn()) .put("currentqueue", messageEntity.getRoutedmessage().getCurrentqueue()) .put("amount", messageEntity.getRoutedmessage().getAmount()); } if (needsPayload){ messageAsJson.put("payload", messageEntity.getPayload()); } ResourcesUtils.createLink(messageAsJson, path + "/events", "events"); return messageAsJson; } /** * Method toString. * * @return String */ public String toString() { return messageEntity.getGuid(); } }