/* *************************************************************************************** * 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.esper.epl.core.eval; import com.espertech.esper.client.EventBean; import com.espertech.esper.client.EventType; import com.espertech.esper.epl.core.EngineImportService; import com.espertech.esper.epl.core.SelectExprProcessor; import com.espertech.esper.epl.expression.core.*; import com.espertech.esper.event.*; import com.espertech.esper.event.map.MapEventType; import com.espertech.esper.util.TypeWidener; import com.espertech.esper.util.TypeWidenerFactory; import java.util.ArrayList; import java.util.List; import java.util.Set; public class EvalSelectStreamWUndRecastMapFactory { public static SelectExprProcessor make(EventType[] eventTypes, SelectExprContext selectExprContext, int streamNumber, EventType targetType, ExprNode[] exprNodes, EngineImportService engineImportService, String statementName, String engineURI) throws ExprValidationException { MapEventType mapResultType = (MapEventType) targetType; MapEventType mapStreamType = (MapEventType) eventTypes[streamNumber]; // (A) fully assignment-compatible: same number, name and type of fields, no additional expressions: Straight repackage String typeSameMssage = BaseNestableEventType.isDeepEqualsProperties(mapResultType.getName(), mapResultType.getTypes(), mapStreamType.getTypes()); if (typeSameMssage == null && selectExprContext.getExpressionNodes().length == 0) { return new MapInsertProcessorSimpleRepackage(selectExprContext, streamNumber, targetType); } // (B) not completely assignable: find matching properties Set<WriteablePropertyDescriptor> writables = selectExprContext.getEventAdapterService().getWriteableProperties(mapResultType, true); List<Item> items = new ArrayList<Item>(); List<WriteablePropertyDescriptor> written = new ArrayList<WriteablePropertyDescriptor>(); // find the properties coming from the providing source stream int count = 0; for (WriteablePropertyDescriptor writeable : writables) { String propertyName = writeable.getPropertyName(); if (mapStreamType.getTypes().containsKey(propertyName)) { Object setOneType = mapStreamType.getTypes().get(propertyName); Object setTwoType = mapResultType.getTypes().get(propertyName); boolean setTwoTypeFound = mapResultType.getTypes().containsKey(propertyName); String message = BaseNestableEventUtil.comparePropType(propertyName, setOneType, setTwoType, setTwoTypeFound, mapResultType.getName()); if (message != null) { throw new ExprValidationException(message); } items.add(new Item(count, propertyName, null, null)); written.add(writeable); count++; } } // find the properties coming from the expressions of the select clause for (int i = 0; i < selectExprContext.getExpressionNodes().length; i++) { String columnName = selectExprContext.getColumnNames()[i]; ExprEvaluator evaluator = selectExprContext.getExpressionNodes()[i]; ExprNode exprNode = exprNodes[i]; WriteablePropertyDescriptor writable = findWritable(columnName, writables); if (writable == null) { throw new ExprValidationException("Failed to find column '" + columnName + "' in target type '" + mapResultType.getName() + "'"); } TypeWidener widener = TypeWidenerFactory.getCheckPropertyAssignType(ExprNodeUtility.toExpressionStringMinPrecedenceSafe(exprNode), exprNode.getExprEvaluator().getType(), writable.getType(), columnName, false, null, statementName, engineURI); items.add(new Item(count, null, evaluator, widener)); written.add(writable); count++; } // make manufacturer Item[] itemsArr = items.toArray(new Item[items.size()]); EventBeanManufacturer manufacturer; try { manufacturer = selectExprContext.getEventAdapterService().getManufacturer(mapResultType, written.toArray(new WriteablePropertyDescriptor[written.size()]), engineImportService, true); } catch (EventBeanManufactureException e) { throw new ExprValidationException("Failed to write to type: " + e.getMessage(), e); } return new MapInsertProcessorAllocate(streamNumber, itemsArr, manufacturer, targetType); } private static WriteablePropertyDescriptor findWritable(String columnName, Set<WriteablePropertyDescriptor> writables) { for (WriteablePropertyDescriptor writable : writables) { if (writable.getPropertyName().equals(columnName)) { return writable; } } return null; } private static class MapInsertProcessorSimpleRepackage implements SelectExprProcessor { private final SelectExprContext selectExprContext; private final int underlyingStreamNumber; private final EventType resultType; private MapInsertProcessorSimpleRepackage(SelectExprContext selectExprContext, int underlyingStreamNumber, EventType resultType) { this.selectExprContext = selectExprContext; this.underlyingStreamNumber = underlyingStreamNumber; this.resultType = resultType; } public EventType getResultEventType() { return resultType; } public EventBean process(EventBean[] eventsPerStream, boolean isNewData, boolean isSynthesize, ExprEvaluatorContext exprEvaluatorContext) { MappedEventBean theEvent = (MappedEventBean) eventsPerStream[underlyingStreamNumber]; return selectExprContext.getEventAdapterService().adapterForTypedMap(theEvent.getProperties(), resultType); } } private static class MapInsertProcessorAllocate implements SelectExprProcessor { private final int underlyingStreamNumber; private final Item[] items; private final EventBeanManufacturer manufacturer; private final EventType resultType; private MapInsertProcessorAllocate(int underlyingStreamNumber, Item[] items, EventBeanManufacturer manufacturer, EventType resultType) { this.underlyingStreamNumber = underlyingStreamNumber; this.items = items; this.manufacturer = manufacturer; this.resultType = resultType; } public EventType getResultEventType() { return resultType; } public EventBean process(EventBean[] eventsPerStream, boolean isNewData, boolean isSynthesize, ExprEvaluatorContext exprEvaluatorContext) { MappedEventBean theEvent = (MappedEventBean) eventsPerStream[underlyingStreamNumber]; Object[] props = new Object[items.length]; for (Item item : items) { Object value; if (item.getOptionalPropertyName() != null) { value = theEvent.getProperties().get(item.getOptionalPropertyName()); } else { value = item.getEvaluator().evaluate(eventsPerStream, isNewData, exprEvaluatorContext); if (item.getOptionalWidener() != null) { value = item.getOptionalWidener().widen(value); } } props[item.getToIndex()] = value; } return manufacturer.make(props); } } private static class Item { private final int toIndex; private final String optionalPropertyName; private final ExprEvaluator evaluator; private final TypeWidener optionalWidener; private Item(int toIndex, String optionalPropertyName, ExprEvaluator evaluator, TypeWidener optionalWidener) { this.toIndex = toIndex; this.optionalPropertyName = optionalPropertyName; this.evaluator = evaluator; this.optionalWidener = optionalWidener; } public int getToIndex() { return toIndex; } public String getOptionalPropertyName() { return optionalPropertyName; } public ExprEvaluator getEvaluator() { return evaluator; } public TypeWidener getOptionalWidener() { return optionalWidener; } } }