/** * Copyright 2015 Santhosh Kumar Tekuri * * The JLibs authors license this file to you 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 jlibs.nbp; import java.io.IOException; import java.nio.CharBuffer; import java.nio.channels.ReadableByteChannel; import java.nio.charset.CharacterCodingException; /** * @author Santhosh Kumar T */ public class Feeder{ public static final int DEFAULT_BUFFER_SIZE = 8192; public final NBParser parser; protected ReadableCharChannel channel; protected final CharBuffer charBuffer = CharBuffer.allocate(DEFAULT_BUFFER_SIZE); public Feeder(NBParser parser, ReadableCharChannel channel){ this(parser); this.channel = channel; } protected Feeder(NBParser parser){ this.parser = parser; } public ReadableCharChannel channel(){ return channel; } public final void setChannel(ReadableCharChannel channel){ readMore = true; this.channel = channel; child = null; charBuffer.clear(); } public final ReadableByteChannel byteChannel(){ return channel instanceof NBChannel ? ((NBChannel)channel).getChannel() : null; } protected Feeder child; private Feeder parent; public final void setChild(Feeder child){ this.child = child; child.parent = this; parser.stop = true; } public final Feeder getParent(){ return parent; } /*-------------------------------------------------[ Eating ]---------------------------------------------------*/ private void closeAll(){ Feeder feeder = this; while(feeder.parent!=null) feeder = feeder.parent; while(feeder!=null){ try{ if(feeder.channel!=null) feeder.channel.close(); }catch(IOException ignore){ // ignore } feeder = feeder.child; } } public final Feeder feed() throws IOException{ try{ try{ Feeder current = this; Feeder next; do{ next = current.read(); if(next==current) return current; current = next; }while(current!=null); }catch(CharacterCodingException ex){ throw parser.ioError(ex.getClass().getSimpleName()+": "+ex.getMessage()); } return null; }catch(Throwable thr){ closeAll(); if(thr instanceof RuntimeException) throw (RuntimeException)thr; else if(thr instanceof Error) throw (Error)thr; else throw (IOException)thr; } } private boolean readMore = true; protected Feeder read() throws IOException{ final char[] chars = charBuffer.array(); if(channel!=null){ if(!readMore){ charBuffer.position(parser.consume(chars, charBuffer.position(), charBuffer.limit(), false)); if(child!=null) return child; else{ charBuffer.compact(); readMore = true; } } int read; while((read=channel.read(charBuffer))>0){ charBuffer.flip(); charBuffer.position(parser.consume(chars, charBuffer.position(), charBuffer.limit(), false)); if(child!=null){ readMore = false; return child; } charBuffer.compact(); } if(read==-1){ charBuffer.flip(); channel.close(); channel = null; } } if(channel==null){ boolean canSendEOF = parent==null || this.parser!=parent.parser; charBuffer.position(parser.consume(chars, charBuffer.position(), charBuffer.limit(), canSendEOF)); if(child!=null) return child; if(!canSendEOF && charBuffer.hasRemaining()) throw new IOException("NotImplemented: remaining "+charBuffer.position()); if(parent!=null) parent.child = null; return parent; }else return this; } }