0

I've got web servlet class which stores all the responses for requests in synchronizedMap. Also I have RabbitMQ message handler (listener) which runs in separate thread. On message receive this message handler sends response and removes request from the map. I put elements in the map on every request:

@WebServlet({"/create_conf_link", "/invite_participant", "/get_conf_credentials", "/get_web_conf_credentials"})
public class VcmsServlet extends HttpServlet implements AutoCloseable {
    private static final long serialVersionUID = 1L;

private final VcmsWsMessageHandler mMessageHandler;

private volatile Map<String, HttpServletResponse> mResponses = Collections.synchronizedMap(new HashMap<String, HttpServletResponse>());

/**
 * @see HttpServlet#HttpServlet()
 */
public VcmsServlet() 
{    
    super();

    mMessageHandler = new VcmsWsMessageHandler(mResponses);
}


/** 
 * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
 * @param request servlet request
 * @param response servlet response
 */
 protected void handleRequest(HttpServletRequest request, HttpServletResponse response)
         throws ServletException, IOException
 {
     String corrID = java.util.UUID.randomUUID().toString();
     mResponses.put(corrID, response);

On message handle handle method is called in MessageHandler class

public class VcmsWsMessageHandler implements IMessageHandler 
{
    public VcmsWsMessageHandler(Map<String, HttpServletResponse> responses) 
    {
        mResponses = responses;
    }

@Override
public void handle(final String inMethod, final String inMessage, final BasicProperties inProperties)
{
    String corrID = inProperties.getCorrelationId();
    LOG.info("VCMS response for " + corrID + ": " + inMessage);
    synchronized (mResponses)
    {
        HttpServletResponse response = mResponses.get(corrID);

        if(response == null)
            LOG.error("Failed to find response object for corrilcation ID " + corrID);
        try
        {
            response.setStatus(200);
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().write(inMessage);
            mResponses.remove(corrID);
        }
        catch(IOException ex)
        {
            LOG.error("Error sending response");
            response.setStatus(HttpServletResponse.SC_CONFLICT);
        }
    }
}

private volatile Map<String, HttpServletResponse> mResponses;
}

The problem is in that there is no response for corresponding corrID in MessageHandler class, though map element is added in handleRequest method of servlet. HttpServletResponse response = mResponses.get(corrID); returns null. But in some rare cases mResponses.get(corrID); returns valid response and everything is OK. How should I work with map to sync it between classes? Thanks.

rudolfninja
  • 467
  • 7
  • 24
  • Are you sure the servlet and RabbitMQ are sharing the same VcmsWsMessageHandler instance? Why not include the response in the message itself? Also, the synchronized map may cause performance issues with concurrent requests. – Andrew S Dec 15 '17 at 14:39
  • @AndrewS, yes, they use one instance of MessageHandler: `mRabbitReceiver = new Receiver(mMessageHandler, rcv_cfg);` - this string is performed in the servlet constructor. I'm not sure I understand the idea to include response in the message. – rudolfninja Dec 15 '17 at 15:18
  • Instead of sending the message which only has an ID (which is used to find the response in the map), include the response in the message directly. This will remove the need of the map. [This](https://stackoverflow.com/questions/15524029/send-an-object-using-rabbitmq) might help with sending a message which includes a complex object. – Andrew S Dec 15 '17 at 18:39

0 Answers0