001 /* 002 * Copyright © 2008, 2012 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 static 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( Throwable exception, boolean debugOn ) { 110 PollErrorResponseData result = new PollErrorResponseData(exception, debugOn); 111 return result; 112 } 113 114 protected void logErrorResponse( Exception t) { 115 assert t != null; 116 117 getLogger().error( "(Controlled) server error: " + t.getMessage() + " for Poll Event '" + this.eventName + "'", t); 118 } 119 120 121 private void logEnterInfo() { 122 if( getLogger().isDebugEnabled()) { 123 logRequestEnterInfo(); 124 } 125 } 126 127 private void logExitInfo() { 128 if( getLogger().isDebugEnabled()) { 129 logRequestExitInfo(logger); 130 } 131 } 132 133 public void process(Reader reader, Writer writer, String pathInfo) throws IOException { 134 assert !StringUtils.isEmpty(pathInfo); 135 136 this.requestString = IOUtils.toString(reader); 137 this.eventName = getEventName(pathInfo); 138 139 logEnterInfo(); 140 141 ResponseData response; 142 try { 143 RegisteredMethod method = getMethod(); 144 Object[] parameters = getParameters(); 145 Object result = getDispatcher().dispatch(method, parameters); 146 response = createSuccessResponse(result); 147 } 148 catch( Exception t ) { 149 response = createErrorResponse( t, getDebug()); 150 151 logErrorResponse( t ); 152 } 153 StringBuilder result = new StringBuilder(); 154 appendIndividualResponseJsonString(response, result); 155 156 this.resultString = result.toString(); 157 writer.write( this.resultString ); 158 159 logExitInfo(); 160 } 161 162 }