/** * Copyright 2007-2015, Kaazing Corporation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kaazing.k3po.driver.internal.behavior.handler.codec; import static java.util.Objects.requireNonNull; import static org.jboss.netty.buffer.ChannelBuffers.EMPTY_BUFFER; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelHandlerContext; import org.kaazing.k3po.driver.internal.behavior.ScriptProgressException; import org.kaazing.k3po.lang.internal.RegionInfo; public abstract class MessageDecoder { private final RegionInfo regionInfo; private ChannelBuffer cumulation; protected MessageDecoder(RegionInfo regionInfo) { this.regionInfo = requireNonNull(regionInfo); } public ChannelBuffer decodeLast(ChannelBuffer buffer) throws Exception { return decode0(buffer, true); } // Returns the ChannelBuffer that should be passed on to the next // handler the pipeline, or null if more data is needed by the // decoder. public ChannelBuffer decode(ChannelBuffer buffer) throws Exception { return decode0(buffer, false); } protected RegionInfo getRegionInfo() { return regionInfo; } private ChannelBuffer decode0(ChannelBuffer buffer, boolean isLast) throws Exception { try { // If we don't have a cumulation buffer yet, create it if (cumulation == null) { cumulation = ChannelBuffers.dynamicBuffer(); } // Write the input bytes in the cumulation buffer cumulation.writeBytes(buffer); Object decoded; if (isLast) { decoded = decodeBufferLast(cumulation); } else { decoded = decodeBuffer(cumulation); } if (decoded == null) { // Not enough data yet, keeping accumulating more (unless last) return null; } ChannelBuffer remaining = EMPTY_BUFFER; if (cumulation.readable()) { // The decoder did not consume all of our accumulated bytes; create // the ChannelBuffer to pass on. remaining = cumulation.readBytes(cumulation.readableBytes()); } // Let the VM know we're done with the cumulation buffer cumulation = null; return remaining; } catch (ScriptProgressException e) { // clean up on failure to prevent side-effects when re-using decoder cumulation = null; throw e; } } protected ChannelBuffer createCumulationBuffer(ChannelHandlerContext ctx) { return ChannelBuffers.dynamicBuffer(); } protected Object decodeBufferLast(ChannelBuffer buffer) throws Exception { // by default, no distinct behavior between last and non-last return decodeBuffer(buffer); } protected abstract Object decodeBuffer(ChannelBuffer buffer) throws Exception; }