001 /* 002 * Copyright © 2008, 2009 Pedro Agulló Soliveres. 003 * 004 * This file is part of DirectJNgine. 005 * 006 * DirectJNgine is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU Lesser General Public License as published by 008 * the Free Software Foundation, either version 3 of the License. 009 * 010 * Commercial use is permitted to the extent that the code/component(s) 011 * do NOT become part of another Open Source or Commercially developed 012 * licensed development library or toolkit without explicit permission. 013 * 014 * DirectJNgine is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU Lesser General Public License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public License 020 * along with DirectJNgine. If not, see <http://www.gnu.org/licenses/>. 021 * 022 * This software uses the ExtJs library (http://extjs.com), which is 023 * distributed under the GPL v3 license (see http://extjs.com/license). 024 */ 025 026 package com.softwarementors.extjs.djn.router.processor.poll; 027 028 import java.io.IOException; 029 import java.io.Reader; 030 import java.io.Writer; 031 032 import org.apache.commons.io.IOUtils; 033 import org.apache.log4j.Logger; 034 035 import com.softwarementors.extjs.djn.StringUtils; 036 import com.softwarementors.extjs.djn.api.RegisteredMethod; 037 import com.softwarementors.extjs.djn.api.RegisteredPollMethod; 038 import com.softwarementors.extjs.djn.api.Registry; 039 import com.softwarementors.extjs.djn.config.GlobalConfiguration; 040 import com.softwarementors.extjs.djn.router.dispatcher.Dispatcher; 041 import com.softwarementors.extjs.djn.router.processor.RequestException; 042 import com.softwarementors.extjs.djn.router.processor.RequestProcessorBase; 043 import com.softwarementors.extjs.djn.router.processor.RequestProcessorUtils; 044 import com.softwarementors.extjs.djn.router.processor.ResponseData; 045 046 import edu.umd.cs.findbugs.annotations.NonNull; 047 048 public class PollRequestProcessor extends RequestProcessorBase { 049 @NonNull 050 private static Logger logger = Logger.getLogger(PollRequestProcessor.class); 051 public static final String PATHINFO_POLL_PREFIX = "/poll/"; 052 053 private String eventName; 054 private String requestString; 055 private String resultString; 056 057 public PollRequestProcessor(Registry registry, Dispatcher dispatcher, GlobalConfiguration globalConfiguration) { 058 super(registry, dispatcher, globalConfiguration); 059 } 060 061 private String getEventName(String pathInfo) { 062 assert !StringUtils.isEmpty(pathInfo); 063 064 return pathInfo.replace( PATHINFO_POLL_PREFIX, ""); 065 } 066 067 /* *************************************************** 068 * Customization support 069 * ***************************************************/ 070 // TODO: move to base class as abstract method! 071 protected Logger getLogger() { 072 return logger; 073 } 074 075 // TODO: move to base class as abstract method! 076 protected void logRequestEnterInfo() { 077 getLogger().debug( "Request data (POLL)=>" + this.requestString + " Event name='" + this.eventName + "'"); 078 } 079 080 // TODO: move to base class as abstract method! 081 protected void logRequestExitInfo(Logger logger) { 082 logger.debug( "ResponseData data (POLL)=>" + this.resultString ); 083 } 084 085 // TODO: move to base class as abstract method! 086 protected RegisteredMethod getMethod() { 087 RegisteredPollMethod method = getRegistry().getPollMethod( this.eventName ); 088 if( method == null ) { 089 RequestException ex = RequestException.forPollEventNotFound(this.eventName); 090 logger.error( ex.getMessage(), ex ); 091 throw ex; 092 } 093 return method; 094 } 095 096 // TODO: move to base class as abstract method! 097 protected Object[] getParameters() { 098 return new Object[] {RequestProcessorUtils.getDecodedRequestParameters(this.requestString) }; 099 } 100 101 // TODO: move to base class as abstract method! 102 protected ResponseData createSuccessResponse( Object result ) { 103 PollSuccessResponseData r = new PollSuccessResponseData( this.eventName); 104 r.setResult(result); 105 return r; 106 } 107 108 // TODO: move to base class as abstract method! 109 protected ResponseData createErrorResponse( String message, String where) { 110 PollErrorResponseData result = new PollErrorResponseData(); 111 result.setMessageAndWhere(message, where); 112 return result; 113 } 114 115 protected void logErrorResponse( Throwable t) { 116 assert t != null; 117 118 getLogger().error( "(Controlled) server error: " + t.getMessage() + " for Poll Event '" + this.eventName + "'", t); 119 } 120 121 122 private void logEnterInfo() { 123 if( getLogger().isDebugEnabled()) { 124 logRequestEnterInfo(); 125 } 126 } 127 128 private void logExitInfo() { 129 if( getLogger().isDebugEnabled()) { 130 logRequestExitInfo(logger); 131 } 132 } 133 134 public void process(Reader reader, Writer writer, String pathInfo) throws IOException { 135 assert !StringUtils.isEmpty(pathInfo); 136 137 this.requestString = IOUtils.toString(reader); 138 this.eventName = getEventName(pathInfo); 139 140 logEnterInfo(); 141 142 ResponseData response; 143 try { 144 RegisteredMethod method = getMethod(); 145 Object[] parameters = getParameters(); 146 Object result = getDispatcher().dispatch(method, parameters); 147 response = createSuccessResponse(result); 148 } 149 catch( Throwable t ) { 150 Throwable reportedException = RequestProcessorUtils.getExceptionToReport(t); 151 String message = RequestProcessorUtils.getExceptionMessage(reportedException); 152 String where = RequestProcessorUtils.getExceptionWhere(reportedException, getDebug()); 153 response = createErrorResponse( message, where); 154 155 logErrorResponse( t ); 156 } 157 StringBuilder result = new StringBuilder(); 158 appendIndividualResponseJsonString(response, result); 159 160 this.resultString = result.toString(); 161 writer.write( this.resultString ); 162 163 logExitInfo(); 164 } 165 166 }