001/* 002 * Copyright (c) 2003-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: welker $' 006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 007 * '$Revision: 24234 $' 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 */ 029 030package org.ecoinformatics.seek.gis.gdal; 031 032import java.io.File; 033 034import org.kepler.objectmanager.cache.DataCacheFileObject; 035import org.kepler.objectmanager.cache.DataCacheManager; 036 037import ptolemy.actor.TypedAtomicActor; 038import ptolemy.actor.TypedIOPort; 039import ptolemy.data.IntToken; 040import ptolemy.data.StringToken; 041import ptolemy.data.expr.Parameter; 042import ptolemy.data.expr.StringParameter; 043import ptolemy.data.type.BaseType; 044import ptolemy.kernel.CompositeEntity; 045import ptolemy.kernel.Port; 046import ptolemy.kernel.util.IllegalActionException; 047import ptolemy.kernel.util.InternalErrorException; 048import ptolemy.kernel.util.NameDuplicationException; 049 050/** 051 * <p> 052 * This actor provides projection capabilities provided through the GDAL GIS 053 * library. It attempts to find the projected file in the kepler file cache 054 * before doing the projection. If the file is found, the projection is not 055 * performed but the cached file is passed on. The file is cached by it's 056 * filename (minus the extension after the '.') and the output format so the 057 * cached result can be read from the cache with a tuple like 058 * {outputFilename.substring(0, outputFilename.lastIndexOf(".")), outputFormat}. 059 * </p> 060 * <p> 061 * The parameters inputParams and outputParams must be of the form used when 062 * passing values to the -s_srs and -t_srs params on the gdalwarp command line 063 * See the gdalwarp docs for more info. <br/> 064 * http://www.remotesensing.org/gdal/gdalwarp.html 065 * </p> 066 * <p> 067 * Note that the 'cache options' parameter has a choice of 'no cache'. This 068 * option will not only not store files in the cache, but it will also ignore 069 * previously stored cache items. It can thus be used to force a new calculation 070 * even if the item was previousl cached (Dan Higgins) 071 * </p> 072 */ 073public class GDALWarpActor extends TypedAtomicActor { 074 /** The -s_srs params from the command line. **/ 075 public StringParameter inputParams = new StringParameter(this, 076 "input params"); 077 /** the -t_srs params from the cammand line. **/ 078 public StringParameter outputParams = new StringParameter(this, 079 "output params"); 080 /** 081 * The format of the output file taken from the list provided by gdalwarp 082 * --formats on the command line 083 */ 084 public StringParameter outputFormat = new StringParameter(this, 085 "output format"); 086 /** how to use the cache, if at all */ 087 public StringParameter cacheOutput = new StringParameter(this, 088 "Cache options"); 089 /** the filename of the input file **/ 090 public TypedIOPort inputFilename = new TypedIOPort(this, "inputFilename", 091 true, false); 092 /** the filename (cacheid) of the outputfile **/ 093 public TypedIOPort outputFilename = new TypedIOPort(this, "outputFilename", 094 false, true); 095 public TypedIOPort outputCachename = new TypedIOPort(this, 096 "outputCachename", false, true); 097 public TypedIOPort outputCacheType = new TypedIOPort(this, 098 "outputCacheType", false, true); 099 /** trigger */ 100 public TypedIOPort trigger = new TypedIOPort(this, "trigger", true, false); 101 /** production rate param to handle the multiport input **/ 102 public Parameter outputFilenameTokenProductionRate; 103 // cache manager 104 private DataCacheManager cacheManager; 105 106 /** 107 * Constructor 108 */ 109 public GDALWarpActor(CompositeEntity container, String name) 110 throws NameDuplicationException, IllegalActionException { 111 super(container, name); 112 inputFilename.setTypeEquals(BaseType.STRING); 113 inputFilename.setMultiport(true); 114 outputFilename.setTypeEquals(BaseType.STRING); 115 outputCachename.setTypeEquals(BaseType.STRING); 116 outputCacheType.setTypeEquals(BaseType.STRING); 117 outputFilenameTokenProductionRate = new Parameter(outputFilename, 118 "tokenProductionRate"); 119 outputFilenameTokenProductionRate.setExpression("0"); 120 cacheManager = DataCacheManager.getInstance(); 121 } 122 123 /** 124 * Notify this entity that the links to the specified port have been 125 * altered. This sets the production rate of the output port and notifies 126 * the director that the schedule is invalid, if there is a director. 127 * 128 * @param port 129 */ 130 public void connectionsChanged(Port port) { 131 super.connectionsChanged(port); 132 if (port == inputFilename) { 133 try { 134 outputFilenameTokenProductionRate.setToken(new IntToken( 135 inputFilename.getWidth())); 136 // NOTE: schedule is invalidated automatically already 137 // by the changed connections. 138 } catch (IllegalActionException ex) { 139 throw new InternalErrorException(this, ex, 140 "Failed to set the token production rate of the " 141 + "outputFilename port"); 142 } 143 } 144 } 145 146 /** 147 * Initialize 148 */ 149 public void initialize() throws IllegalActionException { 150 } 151 152 /** 153 * Prefire 154 */ 155 public boolean prefire() throws IllegalActionException { 156 return super.prefire(); 157 } 158 159 /** 160 * Fire 161 */ 162 public void fire() throws IllegalActionException { 163 super.fire(); 164 if (trigger.getWidth() > 0 && !trigger.hasToken(0)) { // make sure we're 165 // ready to fire 166 return; 167 } 168 169 // get the params 170 String inputParamsStr = inputParams.stringValue(); 171 String outputParamsStr = outputParams.stringValue(); 172 String outputFormatStr = outputFormat.stringValue(); 173 String cacheOutputStr = cacheOutput.stringValue(); 174 String outputCachenameStr = ""; 175 176 // what kind of cache should we use 177 int cacheOption = DataCacheFileObject.COPY_FILE_TO_CACHE; 178 if (cacheOutputStr.equals("Cache Files but Preserve Location")) { 179 cacheOption = DataCacheFileObject.EXTERNAL; 180 } else if (cacheOutputStr.equals("No Caching")) { 181 cacheOption = -666; 182 } 183 184 int inputFilenameWidth = inputFilename.getWidth(); 185 186 for (int i = 0; i < inputFilenameWidth; i++) { // loop through each 187 // input on the port 188 StringToken inputFilenameToken = (StringToken) inputFilename.get(i); 189 String inputFilenameStr = inputFilenameToken.stringValue(); 190 String outputFilenameStr; 191 192 if (inputFilenameStr.indexOf(".") != -1) { // get rid of the . and 193 // the extension on the 194 // filename 195 outputCachenameStr = inputFilenameStr.substring(0, 196 inputFilenameStr.lastIndexOf(".")); 197 outputFilenameStr = outputCachenameStr + "." + outputFormatStr; 198 } else { 199 outputFilenameStr = inputFilenameStr; 200 outputCachenameStr = inputFilenameStr; 201 } 202 203 try { 204 if (cacheOption != -666) { // if we are using caching... 205 // try to get the output file from the cache 206 DataCacheFileObject fileItem = cacheManager.getFile( 207 outputCachenameStr, outputFormatStr); 208 outputFilename.broadcast(new StringToken(fileItem.getFile() 209 .getAbsolutePath())); 210 outputCachename.broadcast(new StringToken( 211 outputCachenameStr)); 212 outputCacheType.broadcast(new StringToken(outputFormatStr)); 213 } else { 214 throw new NullPointerException(); 215 } 216 } catch (NullPointerException npe) { // if the file doesn't exist in 217 // the cache, reproject 218 // it.*/ 219 try { 220 File f = new File(outputFilenameStr); 221 if (f.exists()) { // delete the old output file if there is 222 // one. 223 f.delete(); 224 } 225 GDALJniGlue g = new GDALJniGlue(); 226 String results = g.GDALWarp(inputParamsStr, 227 outputParamsStr, outputFormatStr, inputFilenameStr, 228 outputFilenameStr); 229 if (results != null) { 230 throw new IllegalActionException(results); 231 } 232 // put the output file into the cache 233 if (cacheOption != -666) { 234 DataCacheFileObject fileItem = DataCacheManager 235 .putFile(outputFilenameStr, outputCachenameStr, 236 outputFormatStr, cacheOption); 237 outputFilename.broadcast(new StringToken(fileItem 238 .getFile().getAbsolutePath())); 239 outputCachename.broadcast(new StringToken( 240 outputCachenameStr)); 241 outputCacheType.broadcast(new StringToken( 242 outputFormatStr)); 243 } else { 244 outputFilename.broadcast(new StringToken( 245 outputFilenameStr)); 246 } 247 } catch (Exception e) { 248 throw new IllegalActionException( 249 "Error running jni code for GDAL: " 250 + e.getMessage()); 251 } 252 } 253 } 254 } 255}