001/*
002 * Copyright (c) 2014-2015 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2016-04-20 21:56:24 +0000 (Wed, 20 Apr 2016) $' 
007 * '$Revision: 34470 $'
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.io;
030
031import java.io.File;
032import java.io.IOException;
033import java.net.URI;
034
035import org.json.JSONException;
036import org.kepler.gis.actor.CRSActor;
037import org.kepler.gis.data.VectorToken;
038import org.kepler.gis.util.VectorUtilities;
039
040import ptolemy.actor.TypedIOPort;
041import ptolemy.actor.parameters.PortParameter;
042import ptolemy.data.StringToken;
043import ptolemy.data.type.BaseType;
044import ptolemy.kernel.CompositeEntity;
045import ptolemy.kernel.util.IllegalActionException;
046import ptolemy.kernel.util.NameDuplicationException;
047import ptolemy.kernel.util.SingletonAttribute;
048
049/** Actor that reads vectors/features from a file, WFS service,
050 *  or GeoJSON string.
051 *  <p>
052 *  The <i>crs</i> parameter can be used to specify the coordinate
053 *  reference system when one does not exist. If one does exist,
054 *  then this parameter is ignored.
055 *  </p>
056 *  
057 *  @author Daniel Crawl
058 *  @version $Id: VectorReader.java 34470 2016-04-20 21:56:24Z crawl $
059 */
060public class VectorReader extends CRSActor {
061
062    public VectorReader(CompositeEntity container, String name)
063            throws IllegalActionException, NameDuplicationException {
064        super(container, name);
065        
066        input = new PortParameter(this, "input");
067        input.setTypeEquals(BaseType.STRING);
068        input.setStringMode(true);
069        input.getPort().setTypeEquals(BaseType.STRING);
070        new SingletonAttribute(input.getPort(), "_showName");
071        
072        typeName = new PortParameter(this, "typeName");
073        typeName.setTypeEquals(BaseType.STRING);
074        typeName.setStringMode(true);
075        typeName.getPort().setTypeEquals(BaseType.STRING);
076        new SingletonAttribute(typeName.getPort(), "_showName");
077        
078        vector = new TypedIOPort(this, "vector", false, true);
079        vector.setTypeEquals(VectorToken.VECTOR);
080     
081    }
082    
083    @Override
084    public void fire() throws IllegalActionException {
085     
086        super.fire();
087        
088        input.update();
089        String inputStr = ((StringToken)input.getToken()).stringValue();
090        
091        typeName.update();
092        String typeNameStr = ((StringToken)typeName.getToken()).stringValue();
093        if(typeNameStr.trim().isEmpty()) {
094            typeNameStr = null;
095        }
096        
097        VectorToken vectorToken = null;
098
099        // see if local file URI
100        if(inputStr.startsWith("file:")) {
101            try {
102                vectorToken = VectorUtilities.readFile(new File(new URI(inputStr)), typeNameStr);
103            } catch (Exception e) {
104                throw new IllegalActionException(this, e,
105                        "Error reading from file.");
106            }
107        } else if(inputStr.startsWith("http:")) {
108            
109            try {
110                vectorToken = VectorUtilities.readWFS(inputStr, typeNameStr);
111            } catch (Exception e) {
112                throw new IllegalActionException(this, e,
113                        "Error reading from web service.");
114            }
115            
116        } else {
117            // see if local file name
118            File inputFile = new File(inputStr);
119            if(inputFile.exists()) {
120                try {
121                    vectorToken = VectorUtilities.readFile(inputFile, typeNameStr, _crs);
122                } catch (Exception e) {
123                    throw new IllegalActionException(this, e,
124                            "Error reading from file.");
125                }
126            }
127            
128            if(vectorToken == null) {
129                try {
130                    vectorToken = VectorUtilities.readGeoString(inputStr, _crs);
131                } catch (IOException | JSONException e) {
132                    // Ignore since string may not be GeoJSON.
133                }
134            }
135        }
136        
137        if(vectorToken == null) {
138            throw new IllegalActionException(this,
139                    "Unable to determine type of input of " + inputStr);
140        }
141
142        vector.broadcast(vectorToken);
143        
144    }
145    
146    @Override
147    public void wrapup() throws IllegalActionException {
148        
149        super.wrapup();
150        
151        VectorUtilities.closeDataStores();
152        
153        // if the port for "input" is connected, clear the expression
154        // in the parameter since it can be large and cause the ptolemy
155        // parser a long time to validate.
156        if(input.getPort().numberOfSources() > 0) {
157            input.setExpression("");
158        }
159    }
160    
161    /** The vectors/features to read. Can be a file name, a URL to a
162     *  WFS service, or a GeoJSON string.
163     */
164    public PortParameter input;
165    
166    /** The feature type. */
167    public PortParameter typeName;
168
169    /** The set of vectors/features. */
170    public TypedIOPort vector;
171    
172    /** The coordinate reference system (CRS) of the input. This
173     *  value is used only if the projection is unknown.
174     */
175    // TODO
176    //public StringParameter crs;
177
178}