001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.mina.filter.codec.statemachine;
021
022import org.apache.mina.core.buffer.IoBuffer;
023import org.apache.mina.filter.codec.ProtocolDecoderException;
024import org.apache.mina.filter.codec.ProtocolDecoderOutput;
025
026/**
027 * {@link DecodingState} which consumes all received bytes until the session is
028 * closed.
029 *
030 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
031 */
032public abstract class ConsumeToEndOfSessionDecodingState implements DecodingState {
033
034    private IoBuffer buffer;
035
036    private final int maxLength;
037
038    /**
039     * Creates a new instance using the specified maximum length.
040     * 
041     * @param maxLength the maximum number of bytes which will be consumed. If
042     *        this max is reached a {@link ProtocolDecoderException} will be 
043     *        thrown by {@link #decode(IoBuffer, ProtocolDecoderOutput)}.
044     */
045    public ConsumeToEndOfSessionDecodingState(int maxLength) {
046        this.maxLength = maxLength;
047    }
048
049    /**
050     * {@inheritDoc}
051     */
052    public DecodingState decode(IoBuffer in, ProtocolDecoderOutput out) throws Exception {
053        if (buffer == null) {
054            buffer = IoBuffer.allocate(256).setAutoExpand(true);
055        }
056
057        if (buffer.position() + in.remaining() > maxLength) {
058            throw new ProtocolDecoderException("Received data exceeds " + maxLength + " byte(s).");
059        }
060        buffer.put(in);
061        return this;
062    }
063
064    /**
065     * {@inheritDoc}
066     */
067    public DecodingState finishDecode(ProtocolDecoderOutput out) throws Exception {
068        try {
069            if (buffer == null) {
070                buffer = IoBuffer.allocate(0);
071            }
072            buffer.flip();
073            return finishDecode(buffer, out);
074        } finally {
075            buffer = null;
076        }
077    }
078
079    /**
080     * Invoked when this state has consumed all bytes until the session is 
081     * closed.
082     * 
083     * @param product the bytes read.
084     * @param out the current {@link ProtocolDecoderOutput} used to write 
085     *        decoded messages.
086     * @return the next state if a state transition was triggered (use 
087     *         <code>this</code> for loop transitions) or <code>null</code> if 
088     *         the state machine has reached its end.
089     * @throws Exception if the read data violated protocol specification.
090     */
091    protected abstract DecodingState finishDecode(IoBuffer product, ProtocolDecoderOutput out) throws Exception;
092}