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 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    }