/* * Copyright (c) 2013 Big Switch Networks, Inc. * * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/legal/epl-v10.html * * 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.sdnplatform.ovsdb.internal; import java.io.ByteArrayOutputStream; import java.io.EOFException; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.MappingJsonFactory; import org.codehaus.jackson.map.ObjectMapper; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferInputStream; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.frame.FrameDecoder; /** * FrameDecoder for using Jackson to read JSON-RPC as used by * the OVS DB. * @author readams * */ public class JSONDecoder extends FrameDecoder { // remainderBytes is used to save any bytes left over from // the previous frame, since Jackson will aggressively read // ahead in the buffer byte[] remainderBytes = null; ObjectMapper mapper = new ObjectMapper(); MappingJsonFactory mjf = new MappingJsonFactory(mapper); int ctr = -1; @Override protected Object decode(ChannelHandlerContext chc, Channel channel, ChannelBuffer cb) throws Exception { ctr++; cb.markReaderIndex(); ChannelBuffer compositeBuffer = cb; if (remainderBytes != null) { ChannelBuffer remainderBuffer = ChannelBuffers.wrappedBuffer(remainderBytes); compositeBuffer = ChannelBuffers.wrappedBuffer(remainderBuffer, cb); remainderBytes = null; } ChannelBufferInputStream cbis = new ChannelBufferInputStream(compositeBuffer); JsonParser jp = mjf.createJsonParser(cbis); JsonNode node = null; try { node = jp.readValueAsTree(); } catch (EOFException e) { return null; } catch (JsonProcessingException e) { // This is pretty inefficient but seems to be the only way // to deal with this. if (e.getMessage().contains("end-of-input")) { cb.resetReaderIndex(); return null; } else { throw e; } } ByteArrayOutputStream os = new ByteArrayOutputStream(); jp.releaseBuffered(os); if (os.size() > 0) { remainderBytes = os.toByteArray(); } return node; } }