package org.myrobotlab.codec.serial; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Properties; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.service.interfaces.LoggingSink; import org.slf4j.Logger; public abstract class Codec { public final static Logger log = LoggerFactory.getLogger(Codec.class); // TODO - use ByteBuffer for codecs - only concern is the level of Java // supported // including the level of Android OS - Android did not have a ByteBuffer // until ??? version // TODO - possibly model after the apache codec / encoder / decoder design /* * Object encode(Object source) ; * * Object decode(Object source) ; */ BlockingQueue<String> queue = new LinkedBlockingQueue<String>(); // Integer timeout = null; Integer timeout = 1000; int maxQueue = 1024; LoggingSink sink = null;; static Properties keyToType = new Properties();; static { keyToType.put("asc", "Ascii"); keyToType.put("ascii", "Ascii"); keyToType.put("hex", "Hex"); keyToType.put("dec", "Decimal"); keyToType.put("decimal", "Decimal"); keyToType.put("ard", "ArduinoMsg"); keyToType.put("arduino", "ArduinoMsg"); } static public Codec getDecoder(String key, LoggingSink sink) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { if (key == null) { return null; } String fullTypeName = String.format("org.myrobotlab.codec.serial.%sCodec", keyToType.getProperty(key.toLowerCase(), "decimal")); Codec formatter = null; Class<?> clazz = Class.forName(fullTypeName); if (sink == null) { formatter = (Codec) clazz.newInstance(); } else { Constructor<?> c = clazz.getConstructor(new Class[] { LoggingSink.class }); formatter = (Codec) c.newInstance(sink); } return formatter; } public Codec() { } // FIXME - register - each codec dynamically registers public Codec(LoggingSink sink) { this.sink = sink; } public void clear() { queue.clear(); } public String decode() { try { if (timeout != null) { return queue.poll(timeout, TimeUnit.MILLISECONDS); } return queue.take(); } catch (Exception e) { // don't care } return null; } final public String decode(int newByte) { String decoded = decodeImpl(newByte); if (decoded != null && maxQueue > queue.size()) { queue.add(decoded); } return decoded; } abstract public String decode(int[] msgs); abstract public String decodeImpl(int newByte); abstract public int[] encode(String source); public void error(String format, Object... args) { if (sink != null) { sink.error(format, args); } else { log.error(String.format(format, args)); } } abstract public String getCodecExt(); abstract public String getKey(); public int getMaxQueue() { return maxQueue; } public BlockingQueue<String> getQueue() { return queue; } public Integer getTimeout() { return timeout; } public void setMaxQueue(int maxQueue) { this.maxQueue = maxQueue; } public void setQueue(BlockingQueue<String> queue) { this.queue = queue; } public Integer setTimeout(Integer timeoutms) { this.timeout = timeoutms; return timeoutms; } }