View Javadoc

    1   /*******************************************************************************
    2    * Copyright (c) 2011 Michael Mimo Moratti.
    3    *
    4    * Michael Mimo Moratti licenses this file to you under the Apache License, version 2.0
    5    * (the "License"); you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at:
    7    *     http://www.apache.org/licenses/LICENSE-2.0
    8    * Unless required by applicable law or agreed to in writing, software
    9    * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    10   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
    11   * License for the specific language governing permissions and limitations
    12   * under the License.
    13   *******************************************************************************/
    14  package ch.mimo.netty.handler.codec.icap;
    15
    16  import org.jboss.netty.buffer.ChannelBuffer;
    17  import org.jboss.netty.channel.Channel;
    18  import org.jboss.netty.channel.ChannelHandlerContext;
    19  import org.jboss.netty.handler.codec.replay.ReplayingDecoder;
    20  import org.jboss.netty.logging.InternalLogger;
    21  import org.jboss.netty.logging.InternalLoggerFactory;
    22
    23  /**
    24   * Main ICAP message decoder implementation. this decoder is bases on a @see {@link ReplayingDecoder}
    25   *
    26   * Due to the complexity of an ICAP message the decoder was implement with individual states that reside
    27   * in their own classes.
    28   *
    29   * For a full list of states that are used within this decoder: @see {@link StateEnum}
    30   *
    31   * @author Michael Mimo Moratti (mimo@mimo.ch)
    32   *
    33   * @see IcapRequestDecoder
    34   * @see IcapResponseDecoder
    35   */
    36
    37  public abstract class IcapMessageDecoder extends ReplayingDecoder<StateEnum> {
    38
    39  	private final InternalLogger LOG;
    40
    41      protected final int maxInitialLineLength;
    42      protected final int maxIcapHeaderSize;
    43      protected final int maxHttpHeaderSize;
    44      protected final int maxChunkSize;
    45
    46  	protected IcapMessage message;
    47
    48  	protected int currentChunkSize;
    49
    50
    51
    52      /**
    53       * Creates a new instance with the default
    54       * {@code maxInitialLineLength (4096}}, {@code maxIcapHeaderSize (8192)}, {@code maxHttpHeaderSize (8192)}, and
    55       * {@code maxChunkSize (8192)}.
    56       */
    57      protected IcapMessageDecoder() {
    58          this(4096,8192,8192,8192);
    59      }
    60
    61      /**
    62       * Creates a new instance with the specified parameters.
    63       * @param maxInitialLineLength
    64       * @param maxIcapHeaderSize
    65       * @param maxHttpHeaderSize
    66       * @param maxChunkSize
    67       */
    68      protected IcapMessageDecoder(int maxInitialLineLength, int maxIcapHeaderSize, int maxHttpHeaderSize, int maxChunkSize) {
    69          super(StateEnum.SKIP_CONTROL_CHARS,true);
    70          LOG = InternalLoggerFactory.getInstance(getClass());
    71          if (maxInitialLineLength <= 0) {
    72              throw new IllegalArgumentException("maxInitialLineLength must be a positive integer: " + maxInitialLineLength);
    73          }
    74          if (maxIcapHeaderSize <= 0) {
    75              throw new IllegalArgumentException("maxIcapHeaderSize must be a positive integer: " + maxIcapHeaderSize);
    76          }
    77          if(maxHttpHeaderSize <= 0) {
    78          	throw new IllegalArgumentException("maxHttpHeaderSize must be a positive integer: " + maxIcapHeaderSize);
    79          }
    80          if (maxChunkSize <= 0) {
    81              throw new IllegalArgumentException("maxChunkSize must be a positive integer: " + maxChunkSize);
    82          }
    83          this.maxInitialLineLength = maxInitialLineLength;
    84          this.maxIcapHeaderSize = maxIcapHeaderSize;
    85          this.maxHttpHeaderSize = maxHttpHeaderSize;
    86          this.maxChunkSize = maxChunkSize;
    87      }
    88
    89  	@SuppressWarnings({ "rawtypes", "unchecked" })
    90  	@Override
    91  	protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, StateEnum stateEnumValue) throws Exception {
    92  		if(stateEnumValue != null) {
    93  			try {
    94  				State state = stateEnumValue.getState();
    95  				LOG.debug("Executing state [" + state + ']');
    96  				state.onEntry(buffer,this);
    97  				StateReturnValue returnValue = state.execute(buffer,this);
    98  				LOG.debug("Return value from state [" + state + "] = [" + returnValue + "]");
    99  				StateEnum nextState = state.onExit(buffer,this,returnValue.getDecisionInformation());
    100 				LOG.debug("Next State [" + nextState + "]");
    101 				if(nextState != null) {
    102 					checkpoint(nextState);
    103 				} else {
    104 					reset();
    105 				}
    106 				if(returnValue.isRelevant()) {
    107 					return returnValue.getValue();
    108 				}
    109 			} catch(DecodingException e) {
    110 				reset();
    111 				throw e;
    112 			}
    113 		}
    114 		return null;
    115 	}
    116
    117 	/**
    118 	 * set the decoders message to NULL and the next checkpoint to @see {@link StateEnum#SKIP_CONTROL_CHARS}
    119 	 */
    120     private void reset() {
    121         this.message = null;
    122         checkpoint(StateEnum.SKIP_CONTROL_CHARS);
    123     }
    124
    125 	public abstract boolean isDecodingResponse();
    126
    127 	protected abstract IcapMessage createMessage(String[] initialLine);
    128 }