/* | Copyright 2013 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.adapter.geomessage; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.joda.time.DateTime; import org.xml.sax.SAXException; import com.esri.core.geometry.MapGeometry; import com.esri.core.geometry.Point; import com.esri.core.geometry.SpatialReference; import com.esri.ges.adapter.AdapterDefinition; import com.esri.ges.adapter.InboundAdapterBase; import com.esri.ges.core.component.ComponentException; import com.esri.ges.core.geoevent.FieldDefinition; import com.esri.ges.core.geoevent.GeoEvent; import com.esri.ges.core.geoevent.GeoEventDefinition; import com.esri.ges.messaging.MessagingException; import com.esri.ges.util.DateUtil; public class DefenseInboundAdapter extends InboundAdapterBase { private static final Log LOG = LogFactory.getLog(DefenseInboundAdapter.class); private final MessageParser messageParser; private final SAXParserFactory saxFactory; private final SAXParser saxParser; // private SimpleDateFormat dateFormatLong = new SimpleDateFormat("dd HHmmss'Z' MMM yyyy"); // private SimpleDateFormat dateFormatShort = new SimpleDateFormat("dd HHmmss'Z' MMM yy"); private byte[] bytes = null; private final ArrayList<GeoEvent> queue = new ArrayList<GeoEvent>(); private final boolean tryingToRecoverPartialMessages = false; public DefenseInboundAdapter(AdapterDefinition definition) throws ComponentException, ParserConfigurationException, SAXException, IOException { super(definition); messageParser = new MessageParser(this); saxFactory = SAXParserFactory.newInstance(); saxParser = saxFactory.newSAXParser(); } @Override public void receive(ByteBuffer buffer, String channelId) { try { int remaining = buffer.remaining(); if (remaining <= 0) return; if (bytes == null) { bytes = new byte[remaining]; buffer.get(bytes); } else { byte[] temp = new byte[bytes.length + remaining]; System.arraycopy(bytes, 0, temp, 0, bytes.length); buffer.get(temp, bytes.length, remaining); bytes = temp; } try { saxParser.parse(new ByteArrayInputStream(bytes), messageParser); bytes = null; commit(); } catch (SAXException e) { LOG.error("SAXException while trying to parse the incoming xml.", e); // TODO : figure out a way to recover the lost bytes. for now, just // throwing them away. if (tryingToRecoverPartialMessages) { queue.clear(); } else { bytes = null; commit(); } } } catch (IOException e) { LOG.error("IOException while trying to route data from the byte buffer to the pipe.", e); } } private void commit() { for (GeoEvent geoEvent : queue) { if( geoEvent != null ) geoEventListener.receive(geoEvent); } queue.clear(); } @SuppressWarnings("incomplete-switch") public void queueGeoEvent(HashMap<String, String> fields) { // in.mark(4 * 1024); if (fields.containsKey("_type")) { String geoEventTypeName = fields.get("_type"); GeoEvent geoEvent = findAndCreate(geoEventTypeName); if (geoEvent == null) { LOG.error("The incoming GeoEvent of type \"" + geoEventTypeName + "\" does not have a corresponding Event Definition in the ArcGIS GeoEvent server."); } else { GeoEventDefinition definition = geoEvent.getGeoEventDefinition(); for (String fieldName : fields.keySet()) { String fieldValue = fields.get(fieldName); try { FieldDefinition fieldDefinition = definition.getFieldDefinition(fieldName); if (fieldDefinition == null) { LOG.error("The incoming GeoEvent of type \"" + geoEventTypeName + "\" had an attribute called \"" + fieldName + "\"that does not exist in the corresponding Event Definition."); continue; } switch (fieldDefinition.getType()) { case Integer: geoEvent.setField(fieldName, Integer.parseInt(fieldValue)); break; case Long: geoEvent.setField(fieldName, Long.parseLong(fieldValue)); break; case Short: geoEvent.setField(fieldName, Short.parseShort(fieldValue)); break; case Double: geoEvent.setField(fieldName, Double.parseDouble(fieldValue)); break; case Float: geoEvent.setField(fieldName, Float.parseFloat(fieldValue)); break; case Boolean: geoEvent.setField(fieldName, Boolean.parseBoolean(fieldValue)); break; case Date: geoEvent.setField(fieldName, DateUtil.convert(fieldValue)); break; case String: geoEvent.setField(fieldName, fieldValue); break; case Geometry: String geometryString = fieldValue; if (geometryString.contains(";")) geometryString = geometryString.substring(0, geometryString.indexOf(';') - 1); String[] g = geometryString.split(","); double x = Double.parseDouble(g[0]); double y = Double.parseDouble(g[1]); double z = 0; if (g.length > 2) z = Double.parseDouble(g[2]); int wkid = Integer.parseInt(fields.get("_wkid")); //Point point = spatial.createPoint(x, y, z, wkid); Point point = new Point(x, y, z); SpatialReference sref = SpatialReference.create(wkid); MapGeometry mapGeo = new MapGeometry(point, sref); //int geometryID = geoEvent.getGeoEventDefinition().getGeometryId(); geoEvent.setGeometry(mapGeo); break; } List<FieldDefinition> fdefs = geoEvent.getGeoEventDefinition().getFieldDefinitions(); Boolean hasStartTime = false; for(FieldDefinition fd: fdefs) { List<String>tags = fd.getTags(); if(!tags.isEmpty()) { if(tags.contains("TIME_START")) { hasStartTime=true; break; } } } if (hasStartTime) { if (geoEvent.getField("TIME_START") == null) { long currentTime = System.currentTimeMillis(); Date time = new Date(currentTime); geoEvent.setField("TIME_START", time); } } } catch (Exception ex) { LOG.warn("Error wile trying to parse the GeoEvent field " + fieldName + ":" + fieldValue, ex); } } } queue.add(geoEvent); } } private GeoEvent findAndCreate(String name) { Collection<GeoEventDefinition> results = geoEventCreator.getGeoEventDefinitionManager().searchGeoEventDefinitionByName(name); if (!results.isEmpty()) { try { return geoEventCreator.create(results.iterator().next().getGuid()); } catch (MessagingException e) { LOG.error("GeoEvent creation failed: " + e.getMessage()); } } else LOG.error("GeoEvent creation failed: GeoEvent definition '" + name + "' not found."); return null; } @Override protected GeoEvent adapt(ByteBuffer buffer, String channelId) { // Don't need to implement this class because we are overriding the base class's implementation of the receive() function, which prevents this method from being called. return null; } }