/** This software is licensed under the Apache 2 license, quoted below. Copyright 2012 Joonas Javanainen 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 fi.jawsy.jawwa.zk.atmosphere; import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.atmosphere.cpr.AtmosphereHandler; import org.atmosphere.cpr.AtmosphereRequest; import org.atmosphere.cpr.AtmosphereResource; import org.atmosphere.cpr.AtmosphereResourceEvent; import org.atmosphere.cpr.AtmosphereResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.zkoss.zk.ui.Desktop; import org.zkoss.zk.ui.Session; import org.zkoss.zk.ui.http.WebManager; import org.zkoss.zk.ui.sys.DesktopCtrl; import org.zkoss.zk.ui.sys.WebAppCtrl; /** * Atmosphere handler that integrates Atmosphere with ZK server push. * Adapted from https://github.com/Gekkio/jawwa/tree/develop/zk-atmosphere version 0.3.1-SNAPSHOT */ public class ZkAtmosphereHandler implements AtmosphereHandler { private static final String SESSION_NOT_FOUND = "SessionNotFound"; private static final String DESKTOP_NOT_FOUND = "DesktopNotFound"; private final Logger log = LoggerFactory.getLogger(this.getClass()); @Override public void destroy() { } /** * Get Zk {@link Desktop} instance from session by desktop id * @param session * @param dtid desktop id * @return left as error message and right as {@link Desktop} reference */ private Either getDesktop(Session session, String dtid) { if (session.getWebApp() instanceof WebAppCtrl) { WebAppCtrl webAppCtrl = (WebAppCtrl) session.getWebApp(); Desktop desktop = webAppCtrl.getDesktopCache(session).getDesktopIfAny(dtid); if (desktop == null) { if (log.isDebugEnabled()) log.debug("Could not find desktop: " + dtid); } return new Either(DESKTOP_NOT_FOUND, desktop); } return new Either("Webapp does not implement WebAppCtrl", null); } /** * Get Zk {@link Desktop} id from HttpServletRequest parameter (dtid) * @param request * @return left as desktop id and right as error message */ private Either getDesktopId(HttpServletRequest request) { String dtid = request.getParameter("dtid"); return new Either(dtid, DESKTOP_NOT_FOUND); } /** * Get {@link AtmosphereServerPush} instance from {@link AtmosphereResource} * @param resource {@link AtmosphereResource} * @return left as error message and right as AtmosphereServerPush reference */ private Either getServerPush(AtmosphereResource resource) { AtmosphereRequest request = resource.getRequest(); Either sessionEither = getSession(resource, request); if (sessionEither.getRightValue() == null) { return new Either(sessionEither.getLeftValue(), null); } Session session = sessionEither.getRightValue(); { Either dtidEither = getDesktopId(request); if (dtidEither.getLeftValue() == null || dtidEither.getLeftValue().trim().length() == 0) { return new Either(dtidEither.getRightValue(), null); } String dtid = dtidEither.getLeftValue(); { Either desktopEither = getDesktop(session, dtid); if (desktopEither.getRightValue() == null) { return new Either (desktopEither.getLeftValue(), null); } Desktop desktop = desktopEither.getRightValue(); return getServerPush(desktop); } } } /** * Get {@link AtmosphereServerPush} instance from {@link Desktop} * @param desktop * @return left as error message and right as {@link AtmosphereServerPush} reference */ private Either getServerPush(Desktop desktop) { if (desktop instanceof DesktopCtrl) { DesktopCtrl desktopCtrl = (DesktopCtrl) desktop; if (desktopCtrl.getServerPush() == null) return new Either("Server push is not enabled", null); if (desktopCtrl.getServerPush() instanceof AtmosphereServerPush) { return new Either(null, (AtmosphereServerPush) desktopCtrl.getServerPush()); } return new Either("Server push implementation is not AtmosphereServerPush", null); } return new Either("Desktop does not implement DesktopCtrl", null); } /** * Get {@link Session} from request * @param resource * @param request * @return left as error message and right as Session reference */ private Either getSession(AtmosphereResource resource, HttpServletRequest request) { Session session = WebManager.getSession(resource.getAtmosphereConfig().getServletContext(), request, false); if (session == null) { log.warn("Could not find session: " + request.getRequestURI()); return new Either(SESSION_NOT_FOUND, null); } else { return new Either(null, session); } } @Override public void onRequest(AtmosphereResource resource) throws IOException { AtmosphereResponse response = resource.getResponse(); response.setContentType("text/plain"); Either serverPushEither = getServerPush(resource); String error = serverPushEither.getLeftValue(); if (error != null && serverPushEither.getRightValue() == null) { if (log.isDebugEnabled()) log.warn("Bad Request. Error="+error+", Request="+resource.getRequest().getRequestURI()); response.setStatus(HttpServletResponse.SC_BAD_REQUEST, error); response.getWriter().write(""); response.getWriter().flush(); return; } AtmosphereServerPush serverPush = serverPushEither.getRightValue(); serverPush.onRequest(resource); } @Override public void onStateChange(AtmosphereResourceEvent event) throws IOException { AtmosphereResource resource = event.getResource(); if (event.isCancelled() || event.isResumedOnTimeout()) { AtmosphereServerPush serverPush = getServerPush(resource).getRightValue(); if (serverPush != null) { serverPush.clearResource(resource); } } } }