/* *************************************************************************************** * Copyright (C) 2006 EsperTech, Inc. All rights reserved. * * http://www.espertech.com/esper * * http://www.espertech.com * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the GPL license * * a copy of which has been included with this distribution in the license.txt file. * *************************************************************************************** */ package com.espertech.esperio.socket.core; import com.espertech.esper.client.EventBean; import com.espertech.esper.client.EventType; import com.espertech.esper.core.service.EPServiceProviderSPI; import com.espertech.esper.event.EventBeanManufactureException; import com.espertech.esper.event.EventBeanManufacturer; import com.espertech.esper.event.EventTypeSPI; import com.espertech.esper.event.WriteablePropertyDescriptor; import com.espertech.esper.util.SimpleTypeParser; import com.espertech.esper.util.SimpleTypeParserFactory; import com.espertech.esperio.socket.config.DataType; import com.espertech.esperio.socket.config.SocketConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.net.Socket; import java.util.*; public class WorkerThread extends Thread { private static Logger log = LoggerFactory.getLogger(WorkerThread.class); private final EPServiceProviderSPI engine; private final EsperSocketServiceRunnable runnable; private final String serviceName; private final Socket socket; private final Map<String, WriterCacheEntry> streamCache = new HashMap<String, WriterCacheEntry>(); private final SocketConfig socketConfig; private ObjectInputStream ois; private BufferedReader br; private boolean isShutdown; public WorkerThread(String serviceName, EPServiceProviderSPI engine, EsperSocketServiceRunnable runnable, Socket socket, SocketConfig socketConfig) throws IOException { this.serviceName = serviceName; this.engine = engine; this.runnable = runnable; this.socket = socket; this.socketConfig = socketConfig; if (socketConfig.getDataType() == DataType.PROPERTY_ORDERED_CSV) { if (socketConfig.getStream() == null || socketConfig.getStream().length() == 0) { throw new IllegalArgumentException("Invalid null or empty value provided for required 'stream' parameter"); } if (socketConfig.getPropertyOrder() == null || socketConfig.getPropertyOrder().length() == 0) { throw new IllegalArgumentException("Invalid null or empty value provided for required 'propertyOrder' parameter"); } } if ((socketConfig.getDataType() == null) || (socketConfig.getDataType() == DataType.OBJECT)) { ois = new ObjectInputStream(socket.getInputStream()); } else { br = new BufferedReader(new InputStreamReader(socket.getInputStream())); } } public void setShutdown(boolean shutdown) { isShutdown = shutdown; } public void run() { try { while (!Thread.interrupted() && socket.isConnected()) { if (ois != null) { Object object = ois.readObject(); handleObject(object); } else { String str = br.readLine(); if (str != null) { handleString(str); } else { break; } } } } catch (EOFException ex) { log.debug("EOF received from connection"); } catch (IOException ex) { if (!isShutdown) { log.error("I/O error: " + ex.getMessage(), ex); } } catch (ClassNotFoundException ex) { log.error("Class not found: " + ex.getMessage()); } finally { try { socket.close(); runnable.remove(this); } catch (IOException ignore) { } } } private void handleObject(Object input) { try { if (input instanceof Map) { Map map = (Map) input; String type = (String) map.get("stream"); if (type == null) { log.warn("Expected value for event type not found in map event provided to adapter"); return; } engine.getEPRuntime().sendEvent(map, type); } else { engine.getEPRuntime().sendEvent(input); } } catch (Throwable t) { log.error("Unexpected exception encountered sending event " + input + " service '" + serviceName + "' :" + t.getMessage(), t); } } private void handleString(String input) { if (input == null) { return; } try { Map<String, String> parameters = new HashMap<String, String>(); WStringTokenizer tokenizer = new WStringTokenizer(input, ","); String eventTypeName; if (socketConfig.getDataType() != DataType.PROPERTY_ORDERED_CSV) { while (tokenizer.hasMoreTokens()) { String item = tokenizer.nextToken(); int index = item.indexOf("="); if (index != -1) { String value = item.substring(index + 1, item.length()); String unescaped = socketConfig.isUnescape() ? UnescapeUtil.unescapeJavaString(value) : value; parameters.put(item.substring(0, index), unescaped); } } eventTypeName = parameters.get("stream"); } else { // handle property-ordered-csv int idx = -1; String[] propertyOrder = socketConfig.getPropertyOrder().split(","); while (tokenizer.hasMoreTokens()) { idx++; String value = tokenizer.nextToken(); String unescaped = socketConfig.isUnescape() ? UnescapeUtil.unescapeJavaString(value) : value; if (idx < propertyOrder.length) { parameters.put(propertyOrder[idx].trim(), unescaped); } } eventTypeName = socketConfig.getStream(); } WriterCacheEntry cacheEntry = streamCache.get(eventTypeName); if (cacheEntry == null) { cacheEntry = makeCacheEntry(eventTypeName); streamCache.put(eventTypeName, cacheEntry); } if (cacheEntry == null) { return; } Object[] values = new Object[cacheEntry.getParsers().length]; for (int i = 0; i < cacheEntry.getParsers().length; i++) { String value = parameters.get(cacheEntry.getWritableProperties()[i].getPropertyName()); if (value == null) { continue; } values[i] = cacheEntry.getParsers()[i].parse(value); } EventBean theEvent = cacheEntry.getEventBeanManufacturer().make(values); engine.getEPRuntime().sendEvent(theEvent); } catch (Throwable t) { log.error("Unexpected exception encountered sending event " + input + " service '" + serviceName + "' :" + t.getMessage(), t); } } private WriterCacheEntry makeCacheEntry(String eventTypeName) { EventType eventType = engine.getEventAdapterService().getExistsTypeByName(eventTypeName); if (eventType == null) { log.info("Event type by name '" + eventTypeName + "' not found."); return null; } if (!(eventType instanceof EventTypeSPI)) { log.info("Event type by name '" + eventTypeName + "' is not writable."); return null; } EventTypeSPI eventTypeSPI = (EventTypeSPI) eventType; Set<WriteablePropertyDescriptor> writablesSet = engine.getEventAdapterService().getWriteableProperties(eventTypeSPI, false); List<WriteablePropertyDescriptor> writablePropertiesList = new ArrayList<WriteablePropertyDescriptor>(); List<SimpleTypeParser> parserList = new ArrayList<SimpleTypeParser>(); for (WriteablePropertyDescriptor writableDesc : writablesSet) { SimpleTypeParser parser = SimpleTypeParserFactory.getParser(writableDesc.getType()); if (parser == null) { log.debug("No parser found for type '" + writableDesc.getType() + "'"); continue; } writablePropertiesList.add(writableDesc); parserList.add(parser); } WriteablePropertyDescriptor[] writableProperties = writablePropertiesList.toArray(new WriteablePropertyDescriptor[writablePropertiesList.size()]); SimpleTypeParser[] parsers = parserList.toArray(new SimpleTypeParser[parserList.size()]); EventBeanManufacturer eventBeanManufacturer; try { eventBeanManufacturer = engine.getEventAdapterService().getManufacturer(eventType, writableProperties, engine.getEngineImportService(), false); } catch (EventBeanManufactureException e) { log.info("Unable to create manufacturer for event type: " + e.getMessage(), e); return null; } return new WriterCacheEntry(eventBeanManufacturer, writableProperties, parsers); } }