/* | Copyright 2014 Esri | | Licensed 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 com.esri.geoevent.solutions.processor.updateOnly; import java.util.Date; import java.util.HashMap; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.esri.ges.core.component.ComponentException; import com.esri.ges.core.geoevent.GeoEvent; import com.esri.ges.core.property.Property; import com.esri.ges.processor.GeoEventProcessorBase; import com.esri.ges.processor.GeoEventProcessorDefinition; public class UpdateOnlyProcessor extends GeoEventProcessorBase { // This class attempts to reduce the volume of output geoevents by filtering out events that have no updates // (i.e. the TIME_START tagged field is no later than last time a TRACK_ID was processed) // Use of this processor requires that incoming geoevent definitions has TRACK_ID and TIME_START tags applied to their fields protected static String CLEAR_CACHE_PROPERTY_NAME = "ClearCache"; private static final Log LOG = LogFactory.getLog(UpdateOnlyProcessor.class); private Map<String, Date> trackCache = new HashMap<String, Date>(); protected UpdateOnlyProcessor(GeoEventProcessorDefinition definition) throws ComponentException { super(definition); } @Override public GeoEvent process(GeoEvent geoEvent) throws Exception { String trackID = geoEvent.getTrackId(); Date startTime = geoEvent.getStartTime(); if (trackCache.containsKey(trackID)) { Date lastTime = trackCache.get(trackID); // Filter out any tracks that haven't been updated since last time if (!startTime.after(lastTime)) { LOG.trace("UpdateOnlyProcessor ignoring track as nothing new since last time: " + trackID + " : " + startTime.toString()); return null; } LOG.trace("UpdateOnlyProcessor is handling new data for track " + trackID + " : " + startTime.toString() + " is more recent than " + lastTime.toString()); } else { LOG.trace("UpdateOnlyProcessor is handling a new track: " + trackID + " : " + startTime.toString()); } // If we've reached here, then either there's an update to a track in the cache, or there's a new track, so record it in the cache trackCache.put(trackID, startTime); //... and allow the geoEvent through return geoEvent; } @Override public void afterPropertiesSet() { // If a user sets the "Clear Cache" property, then clear it, and un-set the property again // Users might want to clear the cache when another element later in the process chain has broken, or the outbound connector failed, // ... as this could mean the cache has a record of updates that never reached their final destination Boolean propValue = (Boolean)getProperty(CLEAR_CACHE_PROPERTY_NAME).getValue(); if (propValue) { trackCache.clear(); LOG.info("UpdateOnlyProcessor cache was cleared by user setting the Clear Cache property. Resetting to false..."); getProperty(CLEAR_CACHE_PROPERTY_NAME).setValue(false); } super.afterPropertiesSet(); } @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append(definition.getName()); sb.append("/"); sb.append(definition.getVersion()); sb.append("["); for (Property p : getProperties()) { sb.append(p.getDefinition().getPropertyName()); sb.append(":"); sb.append(p.getValue()); sb.append(" "); } sb.append("]"); return sb.toString(); } }