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.kepler.dataproxy.datasource.geon;
031
032import java.net.URL;
033import java.util.Iterator;
034import java.util.List;
035import java.util.Map;
036import java.util.TreeMap;
037
038import org.apache.commons.logging.Log;
039import org.apache.commons.logging.LogFactory;
040import org.kepler.dataproxy.datasource.DataSourceInterface;
041import org.kepler.dataproxy.metadata.ADN.ADNMetadataSpecification;
042import org.kepler.objectmanager.cache.DataCacheListener;
043import org.kepler.objectmanager.cache.DataCacheObject;
044import org.kepler.objectmanager.data.DataSourceControllerFactory;
045import org.sdm.spa.WebService;
046
047import ptolemy.actor.IOPort;
048import ptolemy.actor.TypedIOPort;
049import ptolemy.actor.gui.style.TextStyle;
050import ptolemy.data.BooleanToken;
051import ptolemy.data.StringToken;
052import ptolemy.data.expr.SingletonParameter;
053import ptolemy.data.expr.StringParameter;
054import ptolemy.data.type.BaseType;
055import ptolemy.kernel.CompositeEntity;
056import ptolemy.kernel.util.IllegalActionException;
057import ptolemy.kernel.util.NameDuplicationException;
058import ptolemy.kernel.util.Settable;
059import ptolemy.kernel.util.StringAttribute;
060
061/**
062 * A GEON shapefile resource.
063 */
064public class GEONShpResource extends WebService implements DataCacheListener,
065                DataSourceInterface {
066
067        private DataSourceControllerFactory _nodeController = null;
068
069        // Constants used for more efficient execution.
070
071        private static final int _VIEWMD = 0;
072        private static final int _DOWNLOADDATA = 1;
073        private static final int _VIEWDATA = 2;
074        private static final int _FORWARDID = 3;
075
076        private static final String _VIEWMDSTR = "view metadata";
077        private static final String _DOWNLOADDATASTR = "download data";
078        private static final String _VIEWDATASTR = "view data";
079        private static final String _FORWARDIDSTR = "forward geon id";
080
081        int _procType = 0;
082
083        private final static Map processMap = new TreeMap();
084
085        static {
086                processMap.put(_VIEWMDSTR, new Integer(_VIEWMD));
087                processMap.put(_DOWNLOADDATASTR, new Integer(_DOWNLOADDATA));
088                processMap.put(_VIEWDATASTR, new Integer(_VIEWDATA));
089                processMap.put(_FORWARDIDSTR, new Integer(_FORWARDID));
090        }
091
092        protected final static Log log;
093        static {
094                log = LogFactory
095                                .getLog("org.kepler.dataproxy.datasource.geon.GEONShpResource");
096        }
097
098        // private static final String ENDPOINT = "endpoint";
099        // private static final String RECORDID = "recordid";
100        // private static final String NAMESPACE = "namespace";
101
102        // protected static final String YELLOW = "{1.0, 1.0, 0.0, 1.0}";
103        // protected static final String RED = "{1.0, 0.0, 0.0, 1.0}";
104        // protected static final String BLACK = "{0.0, 0.0, 0.0, 1.0}";
105        // protected static final String MAGENTA = "{1.0, 0.0, 1.0, 1.0}";
106        // protected static final String TITLE_BINARY = "0101";
107        // protected static final String TITLE_BUSY = "BUSY";
108        // protected static final String TITLE_ERROR = "ERROR";
109
110        // /////////////////////////////////////////////////////////////////
111        // // ports and parameters ////
112
113        public StringParameter _process = null;
114
115        public StringAttribute _idAtt = null;
116
117        public StringAttribute _endpointAtt = null;
118
119        public StringAttribute _namespaceAtt = null;
120
121        public StringAttribute _descriptionAtt = null;
122
123        public SingletonParameter _hideOutput;
124
125        public SingletonParameter _hideErrorPort;
126
127        public TypedIOPort _forwardGEONId;
128
129        /**
130         * Construct an actor with the given container and name.
131         * 
132         * @param container
133         *            The container.
134         * @param name
135         *            The name of this actor.
136         * @exception IllegalActionException
137         *                If the actor cannot be contained by the proposed
138         *                container.
139         * @exception NameDuplicationException
140         *                If the container already has an actor with this name.
141         * @since
142         */
143        public GEONShpResource(CompositeEntity container, String name)
144                        throws NameDuplicationException, IllegalActionException {
145                super(container, name);
146
147                _forwardGEONId = new TypedIOPort(this, "forwardGEONId", false, true);
148                _forwardGEONId.setTypeEquals(BaseType.STRING);
149
150                _process = new StringParameter(this, "process");
151                // _process.setExpression(_VIEWMDSTR);
152                _process.setExpression(_FORWARDIDSTR);
153                // _process.addChoice(_VIEWMDSTR);
154                // _process.addChoice(_DOWNLOADDATASTR);
155                // _process.addChoice(_VIEWDATASTR);
156                _process.addChoice(_FORWARDIDSTR); // requires component to integrate
157                                                                                        // several services.
158
159                _idAtt = new StringAttribute(this, RECORDID);
160                _idAtt.setVisibility(Settable.NOT_EDITABLE);
161
162                _endpointAtt = new StringAttribute(this, ENDPOINT);
163                _endpointAtt.setVisibility(Settable.NOT_EDITABLE);
164
165                _namespaceAtt = new StringAttribute(this, NAMESPACE);
166                _namespaceAtt.setVisibility(Settable.NONE);
167
168                _descriptionAtt = new StringAttribute(this, "description");
169                TextStyle descTSatt = new TextStyle(_descriptionAtt, "descriptionTS");
170
171                _hideOutput = new SingletonParameter(_forwardGEONId, "_hide");
172                _hideOutput.setToken(BooleanToken.FALSE);
173
174                _hideErrorPort = new SingletonParameter(clientExecErrors, "_hide");
175                // _hideErrorPort.setToken(BooleanToken.TRUE);
176
177                wsdlUrl.setVisibility(Settable.NONE);
178                methodName.setVisibility(Settable.NONE);
179                userName.setVisibility(Settable.NONE);
180                password.setVisibility(Settable.NONE);
181
182                hasTrigger.moveToLast();
183
184                // Create a node controller to control the context menu
185                _nodeController = new DataSourceControllerFactory(this,
186                                "_controllerFactory");
187
188                _attachText("_iconDescription", "<svg>\n" + "<rect x=\"0\" y=\"0\" "
189                                + "width=\"85\" height=\"30\" " + "style=\"fill:white\"/>\n"
190                                + "<text x=\"9\" y=\"22\""
191                                + "style=\"font-size:16; fill:blue; font-family:SansSerif\">"
192                                + "Shapefile</text>\n" + "</svg>\n");
193
194        }
195
196        /**
197         * Callback for changes in attribute values.
198         */
199        public void attributeChanged(ptolemy.kernel.util.Attribute attribute)
200                        throws ptolemy.kernel.util.IllegalActionException {
201
202                if (attribute.getName().equals("process")) {
203                        if (_process != null) {
204                                String proc = ((StringParameter) attribute).getExpression();
205                                if (!proc.equals("")) {
206                                        _procType = ((Integer) processMap.get(proc)).intValue();
207
208                                        if (proc.equals(_VIEWMDSTR)
209                                                        || proc.equals(_DOWNLOADDATASTR)
210                                                        || proc.equals(_FORWARDIDSTR)) {
211
212                                                // Reset wsdlUrl and methodName
213                                                wsdlUrl.setExpression("");
214                                                methodName.setExpression("");
215
216                                                // delete all other service ports
217                                                _deletePorts();
218
219                                                if (proc.equals(_FORWARDIDSTR)) {
220                                                        // expose output port
221                                                        _hideOutput.setToken(BooleanToken.FALSE);
222                                                        _forwardGEONId.moveToFirst();
223                                                } else {
224                                                        // hide output port
225                                                        _hideOutput.setToken(BooleanToken.TRUE);
226                                                        _forwardGEONId.moveToLast();
227                                                }
228                                                // hide clientErrorPort
229                                                _hideErrorPort.setToken(BooleanToken.TRUE);
230                                        }
231
232                                        else if (proc.equals(_VIEWDATASTR)) {
233
234                                                // hide clientErrorPort and expose output port
235                                                _hideErrorPort.setToken(BooleanToken.FALSE);
236                                                // _hideOutput.setToken(BooleanToken.TRUE);
237
238                                                // Point wsdlUrl and methodName to the mapping service
239                                                // URL.
240                                                // This should call the web service actor's
241                                                // attributeChanged method!!!
242                                                // wsdlUrl.setExpression("??"); // TODO: ADD URL +
243                                                // modify config file
244                                                // methodName.setExpression("??");
245                                        }
246                                }
247                        }
248                } else
249                        super.attributeChanged(attribute);
250        }
251
252        /**
253         * Get the identifier of this record.
254         * 
255         * @return the String that uniquely identifies the record
256         */
257        public String getRecordId() {
258                String value = null;
259                try {
260                        StringAttribute attribute = (StringAttribute) this
261                                        .getAttribute(RECORDID);
262                        value = attribute.getExpression();
263                } catch (Exception e) {
264                        System.err.println("getRecordId - RECORDID attr is null.");
265                }
266                return value;
267        }
268
269        /**
270         * Get the endpoint of this record. The endpoint indicates where the service
271         * generating the record can be accessed.
272         * 
273         * @return endpoint the URL of the service that contains the record
274         */
275        public String getEndpoint() {
276                String value = null;
277                try {
278                        StringAttribute attribute = (StringAttribute) this
279                                        .getAttribute(ENDPOINT);
280                        value = attribute.getExpression();
281                } catch (Exception e) {
282                        System.err.println("getEndpoint - ENDPOINT attr is null.");
283                }
284                return value;
285        }
286
287        /**
288         * Get the namespace of this record.
289         * 
290         * @return namespace the URL of the service that contains the record
291         */
292        public String getNamespace() {
293                String value = null;
294                try {
295                        StringAttribute attribute = (StringAttribute) this
296                                        .getAttribute(NAMESPACE);
297                        value = attribute.getExpression();
298                } catch (Exception e) {
299                        System.err.println("getNamespace - NAMESPACE attr is null.");
300                }
301                return value;
302        }
303
304        /**
305         * Get a URL pointer to the ADN documentation for this data source.
306         * 
307         * @return URL the URL of the HTML file containing the documentation
308         */
309        public URL getDocumentation() {
310                try {
311                        URL htmlDoc = ADNMetadataSpecification
312                                        .getDocumentation(getRecordId());
313                        return htmlDoc;
314                } catch (Exception ex) {
315                        return null;
316                }
317        }
318
319        public void fire() throws IllegalActionException {
320                switch (_procType) {
321                case _VIEWMD:
322                        viewMD();
323                        break;
324                case _DOWNLOADDATA:
325                        downloadData();
326                        break;
327                case _VIEWDATA:
328                        super.fire();
329                        break;
330                case _FORWARDID:
331                        _forwardGEONId.broadcast(new StringToken(getRecordId()));
332                        break;
333                default:
334                        throw new IllegalActionException(this,
335                                        "Unrecognized process type: " + _procType);
336
337                }
338        }
339
340        /**
341         * postfire the actor. Return false if the command is not invoking the web
342         * service client and there is no trigger.
343         */
344        public boolean postfire() throws IllegalActionException {
345                if (_procType != _VIEWDATA && startTrigger.getWidth() == 0) {
346                        return false;
347                }
348                return super.postfire();
349        }
350
351        /** Deletes all the ports of this actor. */
352        protected void _deletePorts() throws IllegalActionException {
353                List inPortList = this.inputPortList();
354                Iterator ports = inPortList.iterator();
355                while (ports.hasNext()) {
356                        IOPort p = (IOPort) ports.next();
357                        if (p.isInput()) {
358                                try {
359                                        if (!(p.getName().equals("startTrigger"))) {
360                                                p.setContainer(null);
361                                        }
362                                } catch (NameDuplicationException e) {
363                                        throw new IllegalActionException(this, e,
364                                                "Could not delete the input port: " + p.getName());
365                                }
366                        }
367                }
368
369                List outPortList = this.outputPortList();
370                Iterator oports = outPortList.iterator();
371                while (oports.hasNext()) {
372                        IOPort outp = (IOPort) oports.next();
373                        if (outp.isOutput()) {
374                                try {
375                                        if (!(outp.getName().equals("clientExecErrors"))
376                                                        && !(outp.getName().equals("forwardGEONId"))) {
377                                                outp.setContainer(null);
378                                        }
379                                } catch (NameDuplicationException e) {
380                                        throw new IllegalActionException(this, e,
381                                                "Could not delete the output port:" + outp.getName());
382                                }
383                        }
384                }
385        } // end of deletePorts
386
387        /**
388         * download shapefile from the GEON portal to the client machine.
389         */
390        private void downloadData() {
391                // add implementation here..
392        }
393
394        /**
395         * View ADN metadata (could be also exposed by getMetadata in the actor's
396         * context menu).
397         */
398        private void viewMD() {
399                // add implementation here..
400        }
401
402        // ------------------------------------------------------------------------
403        // -- DataCacheListener
404        // ------------------------------------------------------------------------
405
406        public void complete(DataCacheObject aItem) {
407                log.debug("complete: " + this);
408
409                aItem.removeListener(this);
410
411                /*
412                 * if (aItem.isReady()) { // }
413                 */}
414
415}