001/* 002 * Copyright (c) 2017 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2017-03-27 21:55:16 +0000 (Mon, 27 Mar 2017) $' 007 * '$Revision: 34553 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029package org.kepler.gis.actor.pylaski; 030 031import java.text.DateFormat; 032import java.text.ParseException; 033import java.text.SimpleDateFormat; 034import java.util.ArrayList; 035import java.util.Date; 036 037import org.geotools.data.simple.SimpleFeatureCollection; 038import org.geotools.data.simple.SimpleFeatureIterator; 039import org.kepler.gis.data.VectorToken; 040import org.opengis.feature.simple.SimpleFeature; 041 042import ptolemy.actor.lib.Transformer; 043import ptolemy.actor.parameters.PortParameter; 044import ptolemy.data.ArrayToken; 045import ptolemy.data.DoubleToken; 046import ptolemy.data.IntToken; 047import ptolemy.data.StringToken; 048import ptolemy.data.Token; 049import ptolemy.data.type.ArrayType; 050import ptolemy.data.type.BaseType; 051import ptolemy.kernel.CompositeEntity; 052import ptolemy.kernel.util.IllegalActionException; 053import ptolemy.kernel.util.NameDuplicationException; 054import ptolemy.kernel.util.SingletonAttribute; 055 056/** Extract measurements in query results from GetPylaskiMeasurements. 057 * 058 * @author Ben Fleming 059 * @version $Id: PylaskiProperty.java 34553 2017-03-27 21:55:16Z crawl $ 060 */ 061public class PylaskiProperty extends Transformer 062{ 063 // 064 public PortParameter propertyName; 065 066 // The format of the date/time values provided by the Pylaski API 067 public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ssZ"; 068 069 /** 070 * 071 * @param container 072 * @param name 073 * @throws NameDuplicationException 074 * @throws IllegalActionException 075 */ 076 public PylaskiProperty(CompositeEntity container, String name) 077 throws NameDuplicationException, IllegalActionException 078 { 079 super(container, name); 080 081 input.setTypeEquals(VectorToken.VECTOR); 082 output.setTypeEquals(new ArrayType(BaseType.DOUBLE)); 083 084 propertyName = new PortParameter(this, "name"); 085 propertyName.setStringMode(true); 086 propertyName.setTypeEquals(BaseType.STRING); 087 propertyName.getPort().setTypeEquals(BaseType.STRING); 088 new SingletonAttribute(propertyName.getPort(), "_showName"); 089 } 090 091 /** 092 * 093 * @throws IllegalActionException 094 */ 095 @Override 096 public void fire() 097 throws IllegalActionException 098 { 099 super.fire(); 100 101 propertyName.update(); 102 103 StringToken nameToken = (StringToken) propertyName.getToken(); 104 String nameStr = (nameToken == null ? "" : nameToken.stringValue()).trim(); 105 106 if(nameStr.isEmpty()) 107 { 108 throw new IllegalActionException(this, "Property name must not be empty."); 109 } 110 111 ArrayList<Token> propertyValues = new ArrayList<>(); 112 113 VectorToken vectorToken = (VectorToken) input.get(0); 114 SimpleFeatureCollection features = vectorToken.getVectors(); 115 116 SimpleFeature closestDataFeature = null; 117 SimpleFeature closestForecastFeature = null; 118 119 try(SimpleFeatureIterator iterator = features.features()) 120 { 121 while(iterator.hasNext()) 122 { 123 SimpleFeature feature = iterator.next(); 124 125 // TODO Get closest distance 126 // So far can't do this as required data is stripped out 127 // Include a "must-have" property list IO port/parameter 128 129 Object distanceMap = feature.getAttribute("distanceFromLocation"); 130 //System.out.println(distanceMap); 131 // Object propertyValue = feature.getAttribute(nameStr); 132 133 if(closestDataFeature == null) 134 { 135 closestDataFeature = feature; 136 } 137 } 138 } 139 140 if(closestDataFeature != null) 141 { 142 propertyValues.addAll(_getPropertyValueTokens(nameStr, closestDataFeature)); 143 } 144 145 if(closestForecastFeature != null) 146 { 147 propertyValues.addAll(_getPropertyValueTokens(nameStr, closestForecastFeature)); 148 } 149 150 if(propertyValues.isEmpty()) 151 { 152 throw new IllegalActionException(this, "Property " + nameStr + " was not found in features."); 153 } 154 155 output.broadcast(new ArrayToken(propertyValues.toArray(new Token[propertyValues.size()]))); 156 } 157 158 /** 159 * 160 * @param property 161 * @param value 162 * @return 163 */ 164 private Token _getPropertyValueToken(String property, Object value) 165 throws IllegalActionException 166 { 167 switch(property) 168 { 169 case "temperature": 170 case "wind_speed": 171 { 172 return new DoubleToken(value == null ? 0 : (Double) value); 173 } 174 175 case "timestamp": 176 { 177 DateFormat df = new SimpleDateFormat(DATE_FORMAT); 178 179 try 180 { 181 Date timestamp = df.parse(value.toString()); 182 183 return new DoubleToken((double) timestamp.getTime()); 184 } 185 catch(ParseException e) 186 { 187 //System.out.println("TIMESTAMP COULD NOT BE PARSED"); 188 throw new IllegalActionException(this, e, "Timestamp couldn't be parsed."); 189 } 190 } 191 } 192 193 if(value instanceof Double) 194 { 195 return new DoubleToken((Double) value); 196 } 197 198 if(value instanceof Integer) 199 { 200 return new IntToken((Integer) value); 201 } 202 203 return new StringToken(value.toString()); 204 } 205 206 /** 207 * 208 * @param property 209 * @param values 210 * @return 211 */ 212 private ArrayList<Token> _getPropertyValueTokens(String property, Object values) 213 throws IllegalActionException 214 { 215 ArrayList<Token> tokenValues = new ArrayList<>(); 216 217 if(values instanceof ArrayList) 218 { 219 for(Object value : (ArrayList<?>) values) 220 { 221 tokenValues.add(_getPropertyValueToken(property, value)); 222 } 223 } 224 else 225 { 226 tokenValues.add(_getPropertyValueToken(property, values)); 227 } 228 229 return tokenValues; 230 } 231 232 /** 233 * 234 * @param property 235 * @param feature 236 * @return 237 */ 238 private ArrayList<Token> _getPropertyValueTokens(String property, SimpleFeature feature) 239 throws IllegalActionException 240 { 241 return _getPropertyValueTokens(property, feature.getAttribute(property)); 242 } 243}