Java tutorial
/* Copyright 2011-2012 the original author or authors: * * Marc Palmer (marc@grailsrocks.com) * Stphane Maldini (stephane.maldini@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.grails.plugin.platform.events.push; import grails.events.GrailsEventsAware; import groovy.json.JsonSlurper; import groovy.lang.Closure; import org.apache.commons.io.IOUtils; import org.atmosphere.cache.UUIDBroadcasterCache; import org.atmosphere.config.service.MeteorService; import org.atmosphere.cpr.*; import org.codehaus.groovy.grails.commons.ApplicationAttributes; import org.codehaus.groovy.grails.commons.GrailsApplication; import org.grails.plugins.events.reactor.api.EventsApi; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; import reactor.event.registry.Registration; import reactor.event.selector.Selector; import reactor.event.selector.Selectors; import reactor.groovy.config.ReactorBuilder; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.nio.channels.Pipe; import java.util.*; import static org.grails.plugin.platform.events.push.EventsPushConstants.*; /** * @author Stephane Maldini <smaldini@gopivotal.com> * @version 1.0 * @file * @date 16/05/12 * @section DESCRIPTION * <p/> * [Does stuff] */ @MeteorService public class EventsPushHandler extends HttpServlet { static private Logger log = LoggerFactory.getLogger(EventsPushHandler.class); private EventsApi grailsEvents; private BroadcasterFactory broadcasterFactory; private AtmosphereResourceEventListener bridgeListener = null; @Override public void init() throws ServletException { super.init(); broadcasterFactory = BroadcasterFactory.getDefault(); ApplicationContext applicationContext = null; GrailsApplication grailsApplication = null; try { applicationContext = ((ApplicationContext) getServletContext() .getAttribute(ApplicationAttributes.APPLICATION_CONTEXT)); } catch (Exception c) { log.error("Couldn't manage to retrieve appContext, servlet ordering problem ?", c); } if (applicationContext != null) { try { grailsEvents = applicationContext.getBean(EventsApi.class); grailsApplication = applicationContext.getBean(GrailsApplication.class); } catch (Exception c) { log.error("Couldn't manage to retrieve beans", c); } } if (grailsEvents != null) { Broadcaster b = broadcasterFactory.lookup(GLOBAL_TOPIC, true); if (b.getBroadcasterConfig().getBroadcasterCache() == null) { b.getBroadcasterConfig().setBroadcasterCache(new UUIDBroadcasterCache()); } defineBridgeListener(grailsApplication, grailsEvents); } } protected void defineBridgeListener(GrailsApplication application, EventsApi grailsEvents) { Object bridgeConfig = application.getConfig().flatten().get(CONFIG_BRIDGE); if (bridgeConfig == null) return; if (Boolean.class.isAssignableFrom(bridgeConfig.getClass()) && (Boolean) bridgeConfig) { bridgeListener = new BridgeWSListener(); } else if (Class.class.isAssignableFrom(bridgeConfig.getClass()) && AtmosphereResourceEventListener.class.isAssignableFrom(((Class) bridgeConfig))) { try { bridgeListener = (AtmosphereResourceEventListener) ((Class) bridgeConfig).newInstance(); } catch (InstantiationException e) { log.error("Failed to create listener", e); } catch (IllegalAccessException e) { log.error("Failed to find constructor for bridge listener", e); } } if (bridgeListener != null) { log.info("Bridge listener created, all browsers events will be dispatched to " + bridgeListener.toString()); if (GrailsEventsAware.class.isAssignableFrom(bridgeListener.getClass())) { ((GrailsEventsAware) bridgeListener).setGrailsEvents(grailsEvents); log.debug("Grails Events are successfully bridged to " + bridgeListener.toString()); } } } @SuppressWarnings("unchecked") protected Set<Registration<?>> registerTopics(Object topic, final AtmosphereResource resource) { Collection<ReactorBuilder> pushBuilders = grailsEvents.getGroovyEnvironment() .reactorBuildersByExtension(EventsPushConstants.TO_BROWSERS); Closure broadcastClientFilter; Object cursor; Selector selector; Object key; Iterator iterableConfiguration; Set<Registration<?>> registrations = new HashSet<Registration<?>>(); for (ReactorBuilder pushBuilder : pushBuilders) { cursor = pushBuilder.ext(EventsPushConstants.TO_BROWSERS); if (!Map.class.isAssignableFrom(cursor.getClass()) && !Collection.class.isAssignableFrom(cursor.getClass())) { continue; } iterableConfiguration = Map.class.isAssignableFrom(cursor.getClass()) ? ((Map) cursor).entrySet().iterator() : ((Collection) cursor).iterator(); while (iterableConfiguration.hasNext()) { cursor = iterableConfiguration.next(); broadcastClientFilter = null; if (Map.Entry.class.isAssignableFrom(cursor.getClass())) { key = ((Map.Entry) cursor).getKey(); if (((Map.Entry) cursor).getValue() != null && Map.class.isAssignableFrom(((Map.Entry) cursor).getValue().getClass())) { broadcastClientFilter = (Closure) ((Map) ((Map.Entry) cursor).getValue()) .get(CLIENT_FILTER_PARAM); } } else { key = cursor; } if (key != null) { selector = Selector.class.isAssignableFrom(key.getClass()) ? (Selector) key : Selectors.$(key); if (selector.matches(topic)) { registrations.add(pushBuilder.get().on(Selectors.$(topic), new AtmosphereConsumer(resource, broadcastClientFilter))); } } } } return registrations; } @Override public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException { Meteor m = Meteor.build(req); Broadcaster b = broadcasterFactory.lookup(GLOBAL_TOPIC); req.setAttribute(AtmosphereResourceImpl.SKIP_BROADCASTER_CREATION, Boolean.TRUE); // Log all events on the console, including WebSocket events. if (bridgeListener != null) m.addListener(bridgeListener); m.resumeOnBroadcast(m.transport() == AtmosphereResource.TRANSPORT.LONG_POLLING).suspend(-1); b.addAtmosphereResource(m.getAtmosphereResource()); if (req.getHeader(TOPICS_HEADER) != null) { Set<Registration<?>> registrations = new HashSet<Registration<?>>(); for (String topic : req.getHeader(TOPICS_HEADER).split(TOPICS_HEADER_DELIMITER)) { registrations.addAll(registerTopics(topic, m.getAtmosphereResource())); } m.getAtmosphereResource().addEventListener(new AtmosphereRegistrationsHandler(registrations)); } } public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException { InputStream stream = req.getInputStream(); final String topic = readPacket(stream); if (topic == null || topic.isEmpty()) { return; } final String type = readPacket(stream); if (type == null || type.isEmpty()) { return; } if (type.equals(TYPE_STRING)) { grailsEvents.event(topic, readPacket(stream), EventsPushConstants.FROM_BROWSERS, null, null, null); } else if (type.equals(TYPE_JSON)) { grailsEvents.event(topic, new JsonSlurper().parse(new BufferedReader(new InputStreamReader(stream))), EventsPushConstants.FROM_BROWSERS, null, null, null); } else if (type.equals(TYPE_BINARY)) { PipedOutputStream pipeOut = new PipedOutputStream(); PipedInputStream pipeIn = new PipedInputStream(pipeOut, 4096); grailsEvents.event(topic, pipeIn, EventsPushConstants.FROM_BROWSERS, null, null, null); IOUtils.copy(stream, pipeOut); pipeOut.close(); } else if (type.equals(TYPE_REGISTER)) { AtmosphereResource targetResource = null; for (AtmosphereResource r : broadcasterFactory.lookup(EventsPushConstants.GLOBAL_TOPIC) .getAtmosphereResources()) { if (r.uuid().equalsIgnoreCase(((AtmosphereRequest) req).resource().uuid())) { targetResource = r; break; } } if (targetResource != null) { targetResource.addEventListener( new AtmosphereRegistrationsHandler(registerTopics(topic, targetResource))); } } else if (type.equals(TYPE_UNREGISTER)) { } } private String readPacket(InputStream is) throws IOException { StringBuffer res = new StringBuffer(); int i; while (-1 != (i = is.read())) { if (((char) i) == DELIMITER) break; res.append((char) i); } return res.toString(); } }