1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *
19 */
20 package org.apache.mina.filter.codec.statemachine;
21
22 import java.util.Queue;
23
24 import org.apache.mina.core.buffer.IoBuffer;
25 import org.apache.mina.core.session.IoSession;
26 import org.apache.mina.filter.codec.ProtocolDecoder;
27 import org.apache.mina.filter.codec.ProtocolDecoderOutput;
28 import org.apache.mina.util.CircularQueue;
29
30 /**
31 * {@link ProtocolDecoder} which uses a {@link DecodingState} to decode data.
32 * Use a {@link DecodingStateMachine} as {@link DecodingState} to create
33 * a state machine which can decode your protocol.
34 * <p>
35 * NOTE: This is a stateful decoder. You should create one instance per session.
36 * </p>
37 *
38 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
39 */
40 public class DecodingStateProtocolDecoder implements ProtocolDecoder {
41 private final DecodingState state;
42 private final Queue<IoBuffer> undecodedBuffers = new CircularQueue<IoBuffer>();
43 private IoSession session;
44
45 /**
46 * Creates a new instance using the specified {@link DecodingState}
47 * instance.
48 *
49 * @param state the {@link DecodingState}.
50 * @throws NullPointerException if the specified state is <code>null</code>.
51 */
52 public DecodingStateProtocolDecoder(DecodingState state) {
53 if (state == null) {
54 throw new NullPointerException("state");
55 }
56 this.state = state;
57 }
58
59 /**
60 * {@inheritDoc}
61 */
62 public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
63 throws Exception {
64 if (this.session == null) {
65 this.session = session;
66 } else if (this.session != session) {
67 throw new IllegalStateException(
68 getClass().getSimpleName() + " is a stateful decoder. " +
69 "You have to create one per session.");
70 }
71
72 undecodedBuffers.offer(in);
73 for (;;) {
74 IoBuffer b = undecodedBuffers.peek();
75 if (b == null) {
76 break;
77 }
78
79 int oldRemaining = b.remaining();
80 state.decode(b, out);
81 int newRemaining = b.remaining();
82 if (newRemaining != 0) {
83 if (oldRemaining == newRemaining) {
84 throw new IllegalStateException(
85 DecodingState.class.getSimpleName() + " must " +
86 "consume at least one byte per decode().");
87 }
88 } else {
89 undecodedBuffers.poll();
90 }
91 }
92 }
93
94 /**
95 * {@inheritDoc}
96 */
97 public void finishDecode(IoSession session, ProtocolDecoderOutput out)
98 throws Exception {
99 state.finishDecode(out);
100 }
101
102 /**
103 * {@inheritDoc}
104 */
105 public void dispose(IoSession session) throws Exception {
106 // Do nothing
107 }
108 }