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}