001/* 002 GRANITE DATA SERVICES 003 Copyright (C) 2011 GRANITE DATA SERVICES S.A.S. 004 005 This file is part of Granite Data Services. 006 007 Granite Data Services is free software; you can redistribute it and/or modify 008 it under the terms of the GNU Library General Public License as published by 009 the Free Software Foundation; either version 2 of the License, or (at your 010 option) any later version. 011 012 Granite Data Services is distributed in the hope that it will be useful, but 013 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License 015 for more details. 016 017 You should have received a copy of the GNU Library General Public License 018 along with this library; if not, see <http://www.gnu.org/licenses/>. 019*/ 020 021package org.granite.gravity.gae; 022 023import java.io.IOException; 024import java.util.List; 025 026import javax.servlet.ServletException; 027import javax.servlet.http.HttpServletRequest; 028import javax.servlet.http.HttpServletResponse; 029 030import org.granite.gravity.AbstractGravityServlet; 031import org.granite.gravity.Gravity; 032import org.granite.gravity.GravityManager; 033import org.granite.logging.Logger; 034 035import com.google.apphosting.api.DeadlineExceededException; 036 037import flex.messaging.messages.AsyncMessage; 038import flex.messaging.messages.Message; 039 040 041/** 042 * @author William DRAI 043 */ 044public class GravityGAEServlet extends AbstractGravityServlet { 045 046 private static final long serialVersionUID = 1L; 047 048 private static final Logger log = Logger.getLogger(GravityGAEServlet.class); 049 050 051 private static long GAE_TIMEOUT = 20000L; 052 private static long GAE_POLLING_INTERVAL = 500L; 053 054 055 @Override 056 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 057 doPost(req,resp); 058 } 059 060 @Override 061 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 062 063 Gravity gravity = GravityManager.getGravity(getServletContext()); 064 GAEChannelFactory channelFactory = new GAEChannelFactory((GAEGravity)gravity); 065 066 try { 067 // Setup context (thread local GraniteContext, etc.) 068 initializeRequest(gravity, request, response); 069 070 // New Request. 071 Message[] amf3Requests = deserialize(gravity, request); 072 073 log.debug(">> [AMF3 REQUESTS] %s", (Object)amf3Requests); 074 075 Message[] amf3Responses = null; 076 077 boolean accessed = false; 078 for (int i = 0; i < amf3Requests.length; i++) { 079 Message amf3Request = amf3Requests[i]; 080 081 // Ask gravity to create a specific response (will be null for connect request from tunnel). 082 Message amf3Response = gravity.handleMessage(channelFactory, amf3Request); 083 String channelId = (String)amf3Request.getClientId(); 084 085 // Mark current channel (if any) as accessed. 086 if (!accessed) 087 accessed = gravity.access(channelId); 088 089 // (Re)Connect message from tunnel. 090 if (amf3Response == null) { 091 if (amf3Requests.length > 1) 092 throw new IllegalArgumentException("Only one request is allowed on tunnel."); 093 094 GAEChannel channel = gravity.getChannel(channelFactory, channelId); 095 if (channel == null) 096 throw new NullPointerException("No channel on connect"); 097 098 long pollingInterval = gravity.getGravityConfig().getExtra().get("gae/@polling-interval", Long.TYPE, GAE_POLLING_INTERVAL); 099 100 long initialTime = System.currentTimeMillis(); 101 do { 102 // Get messages or wait 103 List<Message> messages = null; 104 synchronized (channel) { 105 // Get pending messages from client queue 106 messages = channel.takeMessages(); 107 } 108 109 // Send the messages 110 if (messages != null) { 111 amf3Responses = messages.toArray(new Message[0]); 112 ((AsyncMessage)amf3Responses[i]).setCorrelationId(amf3Requests[i].getMessageId()); 113 break; 114 } 115 116 try { 117 Thread.sleep(pollingInterval); 118 } 119 catch (InterruptedException e) { 120 break; 121 } 122 catch (DeadlineExceededException e) { 123 break; 124 } 125 } 126 while (System.currentTimeMillis()-initialTime < GAE_TIMEOUT); 127 128 if (amf3Responses == null) 129 amf3Responses = new Message[0]; 130 } 131 else { 132 if (amf3Responses == null) 133 amf3Responses = new Message[amf3Requests.length]; 134 amf3Responses[i] = amf3Response; 135 } 136 } 137 138 log.debug("<< [AMF3 RESPONSES] %s", (Object)amf3Responses); 139 140 serialize(gravity, response, amf3Responses); 141 } 142 catch (IOException e) { 143 log.error(e, "Gravity message error"); 144 throw e; 145 } 146 catch (Exception e) { 147 log.error(e, "Gravity message error"); 148 throw new ServletException(e); 149 } 150 finally { 151 // Cleanup context (thread local GraniteContext, etc.) 152 cleanupRequest(request); 153 } 154 } 155}