/** * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.web.analytics.rest; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.PathParam; import javax.ws.rs.core.MultivaluedMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.id.UniqueId; import com.opengamma.util.auth.AuthUtils; import com.opengamma.web.analytics.push.ConnectionManager; import com.opengamma.web.analytics.push.LongPollingServlet; import com.sun.jersey.api.core.HttpContext; import com.sun.jersey.spi.container.ContainerRequest; import com.sun.jersey.spi.container.ContainerRequestFilter; import com.sun.jersey.spi.container.ContainerResponse; import com.sun.jersey.spi.container.ContainerResponseFilter; import com.sun.jersey.spi.container.ResourceFilter; /** * Jersey filter that sets up subscriptions for entities returned from REST methods. When the entity changes * a notification is sent to the client containing the REST URL used to request the entity. * An instance of the filter is associated with each REST method annotated with {@link Subscribe}. */ public class EntitySubscriptionFilter implements ResourceFilter { private static final Logger s_logger = LoggerFactory.getLogger(EntitySubscriptionFilter.class); private final HttpContext _httpContext; private final List<String> _uidParamNames; private final ConnectionManager _restUpdateManager; private final HttpServletRequest _servletRequest; /** * @param uidParamNames Parameter names (specified by {@link PathParam}) that contain {@link UniqueId}s for which * subscriptions should be created * @param connectionManager For setting up the subscriptions * @param httpContext The HTTP context of the request * @param servletRequest The HTTP request */ public EntitySubscriptionFilter(List<String> uidParamNames, ConnectionManager connectionManager, HttpContext httpContext, HttpServletRequest servletRequest) { _httpContext = httpContext; _uidParamNames = uidParamNames; _restUpdateManager = connectionManager; _servletRequest = servletRequest; } /** * @return null */ @Override public ContainerRequestFilter getRequestFilter() { return null; } /** * @return A {@link ResponseFilter} for setting up the subscription */ @Override public ContainerResponseFilter getResponseFilter() { return new ResponseFilter(_uidParamNames); } /** * Filter that examines the response and sets up the subscription with * {@link ConnectionManager#subscribe(String, String, UniqueId, String)}. */ private class ResponseFilter implements ContainerResponseFilter { private final List<String> uidParamNames; // CSIGNORE /** * @param uidParamNames Names of the method parameters that contain {@link UniqueId}s. These are the names * specified in the {@link PathParam} annotations and they are also annotated with {@link Subscribe}. */ public ResponseFilter(List<String> uidParamNames) { this.uidParamNames = uidParamNames; } /** * Extracts the client ID from the query parameter named {@link LongPollingServlet#CLIENT_ID} and subscribes * for updates for {@link UniqueId}s in the parameters named {@link #uidParamNames}. * @param request The request * @param response The response * @return The unmodified response * TODO this is almost identical to MasterSubscriptionFilter, common superclass? helper method / class? */ @Override public ContainerResponse filter(ContainerRequest request, ContainerResponse response) { // TODO check the response status, only subscribe if successful // TODO don't subscribe if specific version was requested - probably need @NoSubscribe annotation on sub-resource methods for versions String clientId = FilterUtils.getClientId(request, _httpContext); // don't subscribe if there's no client ID if (clientId == null) { return response; } String userId = (AuthUtils.isPermissive() ? null : FilterUtils.getUserId(_httpContext)); subscribe(userId, clientId, _servletRequest.getRequestURI(), _httpContext.getUriInfo().getPathParameters()); return response; } private void subscribe(String userId, String clientId, String url, MultivaluedMap<String, String> pathParameters) { for (String paramName : uidParamNames) { List<String> uidStrs = pathParameters.get(paramName); s_logger.debug(paramName + ": " + uidStrs); for (String uidStr : uidStrs) { UniqueId uniqueId = null; try { uniqueId = UniqueId.parse(uidStr); } catch (IllegalArgumentException e) { s_logger.warn("Unable to parse unique ID: " + uidStr, e); } if (uniqueId != null) { try { _restUpdateManager.subscribe(userId, clientId, uniqueId, url); } catch (OpenGammaRuntimeException e) { s_logger.warn("Failed to subscribe for updates to REST entity, userId: " + userId + ", clientId: " + clientId + ", url: " + url, e); } } } } } } }