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); } }
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); } } }