private Message handlePublishMessage(
      final ChannelFactory<?> channelFactory, final AsyncMessage message, final Channel channel) {

    GraniteContext context = GraniteContext.getCurrentInstance();

    // Get and check destination.
    Destination destination =
        context
            .getServicesConfig()
            .findDestinationById(message.getClass().getName(), message.getDestination());

    if (destination == null) return getInvalidDestinationError(message);

    if (message.getMessageId() == null) message.setMessageId(UUIDUtil.randomUUID());
    message.setTimestamp(System.currentTimeMillis());
    if (channel != null) message.setClientId(channel.getId());

    GravityInvocationContext invocationContext =
        new GravityInvocationContext(message, destination) {
          @Override
          public Object invoke() throws Exception {
            // Publish...
            Channel fromChannel = channel;
            if (fromChannel == null)
              fromChannel = getChannel(channelFactory, (String) message.getClientId());
            if (fromChannel == null) return handleUnknownClientMessage(message);

            ServiceAdapter adapter = adapterFactory.getServiceAdapter(message);

            AsyncMessage reply = (AsyncMessage) adapter.invoke(fromChannel, message);

            reply.setDestination(message.getDestination());
            reply.setClientId(fromChannel.getId());

            return reply;
          }
        };

    // Check security 1 (destination).
    if (destination.getSecurizer() instanceof GravityDestinationSecurizer) {
      try {
        ((GravityDestinationSecurizer) destination.getSecurizer()).canPublish(invocationContext);
      } catch (Exception e) {
        return new ErrorMessage(message, e, true);
      }
    }

    // Check security 2 (security service).
    GraniteConfig config = context.getGraniteConfig();
    try {
      if (config.hasSecurityService() && config.getSecurityService().acceptsContext())
        return (Message) config.getSecurityService().authorize(invocationContext);

      return (Message) invocationContext.invoke();
    } catch (Exception e) {
      return new ErrorMessage(message, e, true);
    }
  }
  private Message handleSubscribeMessage(
      final ChannelFactory<?> channelFactory,
      final CommandMessage message,
      final boolean saveMessageInSession) {

    final GraniteContext context = GraniteContext.getCurrentInstance();

    // Get and check destination.
    final Destination destination =
        context
            .getServicesConfig()
            .findDestinationById(message.getMessageRefType(), message.getDestination());

    if (destination == null) return getInvalidDestinationError(message);

    GravityInvocationContext invocationContext =
        new GravityInvocationContext(message, destination) {
          @Override
          public Object invoke() throws Exception {
            // Subscribe...
            Channel channel = getChannel(channelFactory, (String) message.getClientId());
            if (channel == null) return handleUnknownClientMessage(message);

            String subscriptionId =
                (String) message.getHeader(AsyncMessage.DESTINATION_CLIENT_ID_HEADER);
            if (subscriptionId == null) {
              subscriptionId = UUIDUtil.randomUUID();
              message.setHeader(AsyncMessage.DESTINATION_CLIENT_ID_HEADER, subscriptionId);
            }

            DistributedData gdd = graniteConfig.getDistributedDataFactory().getInstance();
            if (gdd != null) {
              if (!gdd.hasChannelId(channel.getId())) {
                gdd.addChannelId(
                    channel.getId(),
                    channel.getFactory().getClass().getName(),
                    context.getClientType());
                log.debug("Stored channel %s in distributed data", channel.getId());
              }

              if (Boolean.TRUE
                  .toString()
                  .equals(destination.getProperties().get("session-selector"))) {
                String selector = gdd.getDestinationSelector(destination.getId());
                log.debug("Session selector found: %s", selector);
                if (selector != null) message.setHeader(CommandMessage.SELECTOR_HEADER, selector);
              }
            }

            ServiceAdapter adapter = adapterFactory.getServiceAdapter(message);

            AsyncMessage reply = (AsyncMessage) adapter.manage(channel, message);

            postManage(channel);

            if (saveMessageInSession && !(reply instanceof ErrorMessage)) {
              // Save subscription message in distributed data (clustering).
              try {
                if (gdd != null) {
                  log.debug(
                      "Saving new subscription message for channel: %s - %s",
                      channel.getId(), message);
                  gdd.addSubcription(channel.getId(), message);
                }
              } catch (Exception e) {
                log.error(
                    e,
                    "Could not add subscription in distributed data: %s - %s",
                    channel.getId(),
                    subscriptionId);
              }
            }

            reply.setDestination(message.getDestination());
            reply.setClientId(channel.getId());
            reply.getHeaders().putAll(message.getHeaders());

            if (gdd != null && message.getDestination() != null) {
              gdd.setDestinationClientId(message.getDestination(), channel.getId());
              gdd.setDestinationSubscriptionId(message.getDestination(), subscriptionId);
            }

            return reply;
          }
        };

    // Check security 1 (destination).
    if (destination.getSecurizer() instanceof GravityDestinationSecurizer) {
      try {
        ((GravityDestinationSecurizer) destination.getSecurizer()).canSubscribe(invocationContext);
      } catch (Exception e) {
        return new ErrorMessage(message, e);
      }
    }

    // Check security 2 (security service).
    GraniteConfig config = context.getGraniteConfig();
    try {
      if (config.hasSecurityService() && config.getSecurityService().acceptsContext())
        return (Message) config.getSecurityService().authorize(invocationContext);

      return (Message) invocationContext.invoke();
    } catch (Exception e) {
      return new ErrorMessage(message, e, true);
    }
  }
Exemple #3
0
  public boolean runReceived(AsyncHttpContext asyncHttpContext) {

    boolean httpAsParam = (asyncHttpContext != null);
    LinkedList<AsyncMessage> messages = null;
    OutputStream os = null;

    try {
      receivedQueueLock.lock();
      try {
        // Do we have any pending messages?
        if (receivedQueue.isEmpty()) return false;

        // Do we have a valid http context?
        if (asyncHttpContext == null) {
          asyncHttpContext = acquireAsyncHttpContext();
          if (asyncHttpContext == null) return false;
        }

        // Both conditions are ok, get all pending messages.
        messages = receivedQueue;
        receivedQueue = new LinkedList<AsyncMessage>();
      } finally {
        receivedQueueLock.unlock();
      }

      HttpServletRequest request = asyncHttpContext.getRequest();
      HttpServletResponse response = asyncHttpContext.getResponse();

      // Set response messages correlation ids to connect request message id.
      String correlationId = asyncHttpContext.getConnectMessage().getMessageId();
      AsyncMessage[] messagesArray = new AsyncMessage[messages.size()];
      int i = 0;
      for (AsyncMessage message : messages) {
        message.setCorrelationId(correlationId);
        messagesArray[i++] = message;
      }

      // Setup serialization context (thread local)
      Gravity gravity = getGravity();
      GraniteContext context =
          HttpGraniteContext.createThreadIntance(
              gravity.getGraniteConfig(), gravity.getServicesConfig(), null, request, response);
      ((AMFContextImpl) context.getAMFContext())
          .setCurrentAmf3Message(asyncHttpContext.getConnectMessage());

      // Write messages to response output stream.

      response.setStatus(HttpServletResponse.SC_OK);
      response.setContentType(AMF0Message.CONTENT_TYPE);
      response.setDateHeader("Expire", 0L);
      response.setHeader("Cache-Control", "no-store");

      os = response.getOutputStream();
      ObjectOutput amf3Serializer = context.getGraniteConfig().newAMF3Serializer(os);

      log.debug("<< [MESSAGES for channel=%s] %s", this, messagesArray);

      amf3Serializer.writeObject(messagesArray);

      os.flush();
      response.flushBuffer();

      return true; // Messages were delivered, http context isn't valid anymore.
    } catch (IOException e) {
      log.warn(e, "Could not send messages to channel: %s (retrying later)", this);

      GravityConfig gravityConfig = getGravity().getGravityConfig();
      if (messages != null && gravityConfig.isRetryOnError()) {
        receivedQueueLock.lock();
        try {
          if (receivedQueue.size() + messages.size()
              > gravityConfig.getMaxMessagesQueuedPerChannel()) {
            log.warn(
                "Channel %s has reached its maximum queue capacity %s (throwing %s messages)",
                this, gravityConfig.getMaxMessagesQueuedPerChannel(), messages.size());
          } else receivedQueue.addAll(0, messages);
        } finally {
          receivedQueueLock.unlock();
        }
      }

      return true; // Messages weren't delivered, but http context isn't valid anymore.
    } finally {

      // Cleanup serialization context (thread local)
      try {
        GraniteContext.release();
      } catch (Exception e) {
        // should never happen...
      }

      // Close output stream.
      try {
        if (os != null) {
          try {
            os.close();
          } catch (IOException e) {
            log.warn(e, "Could not close output stream (ignored)");
          }
        }
      } finally {
        // Cleanup http context (only if this method wasn't explicitly called with a non null
        // AsyncHttpContext from the servlet).
        if (!httpAsParam) releaseAsyncHttpContext(asyncHttpContext);
      }
    }
  }