package com.esri.geoevent.processor.cacheawarefieldcalculator; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; import com.esri.geoevent.processor.cacheawarefieldcalculator.expression.ExpressionBuilder; import com.esri.ges.core.component.ComponentException; import com.esri.ges.core.geoevent.DefaultFieldDefinition; import com.esri.ges.core.geoevent.FieldDefinition; import com.esri.ges.core.geoevent.FieldException; import com.esri.ges.core.geoevent.FieldType; import com.esri.ges.core.geoevent.GeoEvent; import com.esri.ges.core.geoevent.GeoEventDefinition; import com.esri.ges.core.geoevent.GeoEventPropertyName; import com.esri.ges.core.geoevent.Tag; import com.esri.ges.core.validation.ValidationException; import com.esri.ges.framework.i18n.BundleLogger; import com.esri.ges.framework.i18n.BundleLoggerFactory; import com.esri.ges.manager.geoeventdefinition.GeoEventDefinitionManager; import com.esri.ges.manager.geoeventdefinition.GeoEventDefinitionManagerException; import com.esri.ges.manager.tag.TagManager; import com.esri.ges.messaging.GeoEventCreator; import com.esri.ges.processor.CacheEnabledGeoEventProcessor; import com.esri.ges.processor.GeoEventProcessorDefinition; import com.esri.ges.util.Converter; import com.esri.ges.util.Validator; public class CacheAwareFieldCalculator extends CacheEnabledGeoEventProcessor implements ServiceTrackerCustomizer { private static final BundleLogger LOGGER = BundleLoggerFactory.getLogger(CacheAwareFieldCalculator.class); private Map<String, String> edMapper = new ConcurrentHashMap<String, String>(); private GeoEventDefinitionManager geoEventDefinitionManager; private ServiceTracker geoEventDefinitionManagerTracker; private GeoEventCreator geoEventCreator; private ResultDestination resultDestination; private String expression; private String fieldName; private FieldType fieldType; private FieldDefinition fieldDefinition; private String geoEventDefinitionName; private TagManager tagManager; private String fieldTagName; protected CacheAwareFieldCalculator(GeoEventProcessorDefinition definition) throws ComponentException { super(definition); if (geoEventDefinitionManagerTracker == null) geoEventDefinitionManagerTracker = new ServiceTracker(definition.getBundleContext(), GeoEventDefinitionManager.class.getName(), this); geoEventDefinitionManagerTracker.open(); } @Override public void afterPropertiesSet() { expression = getProperty("expression").getValueAsString().trim(); fieldName = null; resultDestination = Validator.valueOfIgnoreCase(ResultDestination.class, getProperty("resultDestination").getValueAsString(), null); geoEventMutator = false; if (resultDestination != null) if (ResultDestination.NEW_FIELD.equals(resultDestination)) { fieldName = getProperty("newFieldName").getValueAsString().trim(); fieldTagName = Validator.compactSpaces(getProperty("newFieldTag").getValueAsString()).trim(); } else if (ResultDestination.EXISTING_FIELD.equals(resultDestination)) { fieldName = getProperty("existingFieldName").getValueAsString().trim(); geoEventMutator = true; } fieldType = Validator.valueOfIgnoreCase(FieldType.class, getProperty("newFieldType").getValueAsString().trim(), null); geoEventDefinitionName = getProperty("newGeoEventDefinitionName").getValueAsString().trim(); fieldDefinition = null; } private Object calculate(final GeoEvent geoEvent) throws Exception { try { FieldDefinition fd = (ResultDestination.EXISTING_FIELD .equals(resultDestination)) ? geoEvent .getGeoEventDefinition().getFieldDefinition(fieldName) : fieldDefinition; if (fd != null) { Object result = new ExpressionBuilder(geoEvent, geoEventCache, expression).build().calculate(); if(result == null) return null; switch (fd.getType()) { case Date: return Converter.convertToDate(result); case Double: return Converter.convertToDouble(result); case Float: return Converter.convertToFloat(result); case Integer: return Converter.convertToInteger(result); case Long: return Converter.convertToLong(result); case Short: return Converter.convertToShort(result); case Boolean: return Converter.convertToBoolean(result); default: return result.toString(); } } return null; } catch (Exception e) { LOGGER.debug(e.getMessage()); throw(e); } } @Override public GeoEvent process(GeoEvent geoEvent) throws Exception { GeoEvent eventOut = null; if (geoEvent != null && geoEventDefinitionManager != null) { Object result = calculate(geoEvent); switch (resultDestination) { case NEW_FIELD: { GeoEventDefinition edOut = lookup(geoEvent.getGeoEventDefinition()); GeoEvent geoEventOut = geoEventCreator.create(edOut.getGuid(), new Object[] { geoEvent.getAllFields(), result }); geoEventOut.setProperty(GeoEventPropertyName.TYPE, "message"); geoEventOut.setProperty(GeoEventPropertyName.OWNER_ID, getId()); geoEventOut.setProperty(GeoEventPropertyName.OWNER_URI, definition.getUri()); for (Map.Entry<GeoEventPropertyName, Object> property : geoEvent.getProperties()) if (!geoEventOut.hasProperty(property.getKey())) geoEventOut.setProperty(property.getKey(), property.getValue()); eventOut = geoEventOut; break; } case EXISTING_FIELD: { try { geoEvent.setField(fieldName, result); eventOut = geoEvent; } catch (FieldException error) { LOGGER.error("SET_FIELD_ERROR", (result != null ? result.toString() : "null"), fieldName, geoEvent.getGeoEventDefinition().getName(), error.getMessage()); } break; } } } return eventOut; } synchronized private GeoEventDefinition lookup(GeoEventDefinition edIn) throws Exception { GeoEventDefinition edOut = edMapper.containsKey(edIn.getGuid()) ? geoEventDefinitionManager.getGeoEventDefinition(edMapper.get(edIn.getGuid())) : null; if (edOut == null) { edOut = edIn.augment(Arrays.asList(fieldDefinition)); edOut.setName(geoEventDefinitionName); edOut.setOwner(getId()); geoEventDefinitionManager.addTemporaryGeoEventDefinition(edOut, geoEventDefinitionName.isEmpty()); edMapper.put(edIn.getGuid(), edOut.getGuid()); } return edOut; } @Override public synchronized void validate() throws ValidationException { super.validate(); List<String> errors = new ArrayList<String>(); if (resultDestination == null) errors.add("Result Destination is unknown."); if (ResultDestination.NEW_FIELD.equals(resultDestination)) { try { fieldDefinition = new DefaultFieldDefinition(fieldName, fieldType); tag(fieldDefinition); } catch (Exception e) { errors.add(e.getMessage()); } } else if (ResultDestination.EXISTING_FIELD.equals(resultDestination)) if (fieldName.isEmpty()) errors.add(LOGGER.translate("VALIDATION_ERROR_FIELD_DOESNT_EXIST")); if (errors.size() > 0) { StringBuffer sb = new StringBuffer(); for (String message : errors) sb.append(message).append("\n"); throw new ValidationException(LOGGER.translate("VALIDATION_ERROR", sb.toString())); } } private void tag(FieldDefinition fd) { if (!fieldTagName.isEmpty() && Validator.isValidFieldDefinitionName(fieldTagName)) { Tag tag = tagManager.getTag(fieldTagName); if (tag != null) { List<String> types = tag.getTypes(); if (types != null && types.indexOf(fd.getType().toString()) != -1) fd.addTag(tag.getName()); } } } @Override public boolean isGeoEventMutator() { return geoEventMutator; } @Override public void shutdown() { super.shutdown(); clearGeoEventDefinitionMapper(); geoEventDefinitionManagerTracker.close(); } synchronized private void clearGeoEventDefinitionMapper() { if (!edMapper.isEmpty()) { for (String guid : edMapper.values()) { try { geoEventDefinitionManager.deleteGeoEventDefinition(guid); } catch (GeoEventDefinitionManagerException e) { ; } } edMapper.clear(); } } @Override public Object addingService(ServiceReference reference) { Object service = definition.getBundleContext().getService(reference); if (service instanceof GeoEventDefinitionManager) this.geoEventDefinitionManager = (GeoEventDefinitionManager) service; return service; } @Override public void modifiedService(ServiceReference reference, Object service) { ; } @Override public void removedService(ServiceReference reference, Object service) { if (service instanceof GeoEventDefinitionManager) { clearGeoEventDefinitionMapper(); this.geoEventDefinitionManager = null; } } public void setGeoEventCreator(GeoEventCreator geoEventCreator) { this.geoEventCreator = geoEventCreator; } public void setTagManager(TagManager tagManager) { this.tagManager = tagManager; } @Override public boolean isCacheRequired() { return new ExpressionBuilder(null, geoEventCache, expression).isCacheRequired(); } }