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 translation capabilities provided through the GDAL GIS
053 * library. It attempts to find the translated file in the kepler file cache
054 * before doing the translation. If the file is found, the translation 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 * Note that the 'cache options' parameter has a choice of 'no cache'. This
062 * option will not only not store files in the cache, but it will also ignore
063 * previously stored cache items. It can thus be used to force a new calculation
064 * even if the item was previousl cached (Dan Higgins)
065 * </p>
066 */
067public class GDALTranslateActor extends TypedAtomicActor {
068        /** the type of output...byte, int, etc. **/
069        public StringParameter outputType = new StringParameter(this, "output type");
070        /** the format of the output...ascii, raw, binary, etc **/
071        public StringParameter outputFormat = new StringParameter(this,
072                        "output format");
073        /** how to use the cache, if at all */
074        public StringParameter cacheOutput = new StringParameter(this,
075                        "Cache options");
076        /** the filename of the input file **/
077        public TypedIOPort inputFilename = new TypedIOPort(this, "inputFilename",
078                        true, false);
079        /** trigger */
080        public TypedIOPort trigger = new TypedIOPort(this, "trigger", true, false);
081        /** the filename (cacheid) of the outputfile **/
082        public TypedIOPort outputFilename = new TypedIOPort(this, "outputFilename",
083                        false, true);
084        public TypedIOPort outputCachename = new TypedIOPort(this,
085                        "outputCachename", false, true);
086        public TypedIOPort outputCacheType = new TypedIOPort(this,
087                        "outputCacheType", false, true);
088        /** production rate param to handle the multiport input **/
089        public Parameter outputFilenameTokenProductionRate;
090        // cache manager
091        private DataCacheManager cacheManager;
092
093        /**
094         * Constructor
095         */
096        public GDALTranslateActor(CompositeEntity container, String name)
097                        throws NameDuplicationException, IllegalActionException {
098                super(container, name);
099                inputFilename.setTypeEquals(BaseType.STRING);
100                inputFilename.setMultiport(true);
101                outputFilename.setTypeEquals(BaseType.STRING);
102                outputCachename.setTypeEquals(BaseType.STRING);
103                outputCacheType.setTypeEquals(BaseType.STRING);
104                outputFilenameTokenProductionRate = new Parameter(outputFilename,
105                                "tokenProductionRate");
106                outputFilenameTokenProductionRate.setExpression("0");
107                cacheManager = DataCacheManager.getInstance();
108        }
109
110        /**
111         * Notify this entity that the links to the specified port have been
112         * altered. This sets the production rate of the output port and notifies
113         * the director that the schedule is invalid, if there is a director.
114         * 
115         * @param port
116         */
117        public void connectionsChanged(Port port) {
118                super.connectionsChanged(port);
119                if (port == inputFilename) {
120                        try {
121                                outputFilenameTokenProductionRate.setToken(new IntToken(
122                                                inputFilename.getWidth()));
123                                // NOTE: schedule is invalidated automatically already
124                                // by the changed connections.
125                        } catch (IllegalActionException ex) {
126                                throw new InternalErrorException(this, ex,
127                                                "Failed to set the token production rate of the "
128                                                                + "outputFilename port");
129                        }
130                }
131        }
132
133        /**
134         * Initialize
135         */
136        public void initialize() throws IllegalActionException {
137        }
138
139        /**
140         * Prefire
141         */
142        public boolean prefire() throws IllegalActionException {
143                return super.prefire();
144        }
145
146        /**
147         * Fire
148         */
149        public void fire() throws IllegalActionException {
150                super.fire();
151                if (trigger.getWidth() > 0 && !trigger.hasToken(0)) { // make sure we're
152                                                                                                                                // ready to fire
153                        return;
154                }
155
156                String outputTypeStr = outputType.stringValue();
157                String outputFormatStr = outputFormat.stringValue();
158                String cacheOutputStr = cacheOutput.stringValue();
159
160                // what kind of cache should we use
161                int cacheOption = DataCacheFileObject.COPY_FILE_TO_CACHE;
162                if (cacheOutputStr.equals("Cache Files but Preserve Location")) {
163                        cacheOption = DataCacheFileObject.EXTERNAL;
164                } else if (cacheOutputStr.equals("No Caching")) {
165                        cacheOption = -666;
166                }
167
168                int inputFilenameWidth = inputFilename.getWidth();
169
170                for (int i = 0; i < inputFilenameWidth; i++) { // loop through each
171                                                                                                                // input on the port
172                        StringToken inputFilenameToken = (StringToken) inputFilename.get(i);
173                        String inputFilenameStr = inputFilenameToken.stringValue();
174                        String outputFilenameStr;
175                        if (inputFilenameStr.indexOf(".") != -1) { // get rid of the . and
176                                                                                                                // the extension on the
177                                                                                                                // filename
178                                outputFilenameStr = inputFilenameStr.substring(0,
179                                                inputFilenameStr.lastIndexOf("."));
180                        } else {
181                                outputFilenameStr = inputFilenameStr;
182                        }
183
184                        try {
185                                // try to get the output file from the cache
186                                if (cacheOption != -666) {
187                                        DataCacheFileObject fileItem = cacheManager.getFile(
188                                                        outputFilenameStr, outputFormatStr);
189                                        outputFilename.broadcast(new StringToken(fileItem.getFile()
190                                                        .getAbsolutePath()));
191                                        outputCachename
192                                                        .broadcast(new StringToken(outputFilenameStr));
193                                        outputCacheType.broadcast(new StringToken(outputFormatStr));
194                                } else {
195                                        throw new NullPointerException();
196                                }
197                        } catch (NullPointerException npe) { // if the file doesn't exist in
198                                                                                                        // the cache, translate it.
199                                try {
200                                        // add the new extension to the filename for output
201                                        String outFile = outputFilenameStr + "." + outputFormatStr;
202                                        File f = new File(outFile);
203                                        if (f.exists()) { // delete the old output file if there is
204                                                                                // one.
205                                                f.delete();
206                                        }
207                                        GDALJniGlue g = new GDALJniGlue();
208                                        String results = g.GDALTranslate(outputTypeStr,
209                                                        outputFormatStr, inputFilenameStr, outFile);
210                                        if (results != null) {
211                                                throw new IllegalActionException(results);
212                                        }
213
214                                        if (cacheOption != -666) {
215                                                // put the output file into the cache
216                                                DataCacheFileObject fileItem = DataCacheManager
217                                                                .putFile(outFile, outputFilenameStr,
218                                                                                outputFormatStr, cacheOption);
219                                                outputFilename.broadcast(new StringToken(fileItem
220                                                                .getFile().getAbsolutePath()));
221                                                outputCachename.broadcast(new StringToken(
222                                                                outputFilenameStr));
223                                                outputCacheType.broadcast(new StringToken(
224                                                                outputFormatStr));
225                                        } else {
226                                                outputFilename.broadcast(new StringToken(outFile));
227                                        }
228                                } catch (Exception e) {
229                                        throw new IllegalActionException(
230                                                        "Error running jni code for GDAL: "
231                                                                        + e.getMessage());
232                                }
233                        }
234                }
235        }
236}