001/* A default implementation of Queryable.
002 * 
003 * Copyright (c) 2015 The Regents of the University of California.
004 * All rights reserved.
005 *
006 * '$Author: crawl $'
007 * '$Date: 2017-08-23 20:27:50 +0000 (Wed, 23 Aug 2017) $' 
008 * '$Revision: 34619 $'
009 * 
010 * Permission is hereby granted, without written agreement and without
011 * license or royalty fees, to use, copy, modify, and distribute this
012 * software and its documentation for any purpose, provided that the above
013 * copyright notice and the following two paragraphs appear in all copies
014 * of this software.
015 *
016 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
017 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
018 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
019 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
020 * SUCH DAMAGE.
021 *
022 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
023 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
024 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
025 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
026 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
027 * ENHANCEMENTS, OR MODIFICATIONS.
028 *
029 */
030package org.kepler.provenance;
031
032import java.io.IOException;
033import java.lang.ref.WeakReference;
034import java.util.Date;
035import java.util.HashMap;
036import java.util.LinkedList;
037import java.util.List;
038import java.util.Map;
039
040import org.kepler.objectmanager.lsid.KeplerLSID;
041import org.kepler.sms.NamedOntClass;
042import org.kepler.util.WorkflowRun;
043import org.kepler.util.WorkflowRun.type;
044
045import ptolemy.data.StringToken;
046import ptolemy.data.Token;
047import ptolemy.data.expr.ASTPtRootNode;
048import ptolemy.data.expr.ParseTreeEvaluator;
049import ptolemy.data.expr.PtParser;
050import ptolemy.kernel.util.NamedObj;
051import ptolemy.moml.MoMLParser;
052
053/** A default implementation of Queryable. Most methods do nothing
054 *  and return null.
055 * 
056 *  @author Daniel Crawl
057 *  @version $Id: DefaultQuery.java 34619 2017-08-23 20:27:50Z crawl $
058 */
059public abstract class DefaultQuery implements Queryable {
060
061    @Override
062    public void close() throws IOException {
063        try {
064            disconnect();
065        } catch (QueryException e) {
066            throw new IOException("Error closing query interface.", e);
067        }
068    }
069
070    @Override
071    public void disconnect() throws QueryException {
072        // TODO Auto-generated method stub
073
074    }
075
076    @Override
077    public List<String> getWorkflows() throws QueryException {
078        // TODO Auto-generated method stub
079        return null;
080    }
081
082    @Override
083    public String getWorkflowName(KeplerLSID lsid) throws QueryException {
084        // TODO Auto-generated method stub
085        return null;
086    }
087
088    @Override
089    public String getWorkflowNameForExecution(KeplerLSID lsid) throws QueryException {
090        // TODO
091        return null;
092    }
093
094    @Override
095    public List<Integer> getExecutions() throws QueryException {
096        // TODO Auto-generated method stub
097        return null;
098    }
099
100    @Override
101    public List<KeplerLSID> getExecutionLSIDs() throws QueryException {
102        // TODO Auto-generated method stub
103        return null;
104    }
105
106    @Override
107    public List<Integer> getExecutionsForWorkflow(String workflow)
108            throws QueryException {
109        // TODO Auto-generated method stub
110        return null;
111    }
112
113    @Override
114    public Integer getExecutionForExecutionLSID(KeplerLSID runLSID)
115            throws QueryException {
116        // TODO Auto-generated method stub
117        return null;
118    }
119
120    @Override
121    public KeplerLSID getExecutionLSIDForExecution(Integer execId)
122            throws QueryException {
123        // TODO Auto-generated method stub
124        return null;
125    }
126
127    @Override
128    public List<Integer> getExecutionsForAnnotation(String annotation)
129            throws QueryException {
130        // TODO Auto-generated method stub
131        return null;
132    }
133
134    @Override
135    public Date[] getTimestampsForExecution(int execId) throws QueryException {
136        // TODO Auto-generated method stub
137        return null;
138    }
139
140    @Override
141    public String getMoMLForExecution(int execId) throws QueryException {
142        // TODO Auto-generated method stub
143        return null;
144    }
145
146    @Override
147    public String getMoMLForExecution(KeplerLSID lsid) throws QueryException {
148        // TODO Auto-generated method stub
149        return null;
150    }
151
152    @Override
153    public List<String> getMoMLForExecutionLSIDs(List<KeplerLSID> lsids)
154            throws QueryException {
155        // TODO Auto-generated method stub
156        return null;
157    }
158
159    /** Get the workflow object for a execution id. */
160    @Override
161    public NamedObj getWorkflowForExecution(Integer execId) 
162        throws QueryException {
163
164        // sychronizing on the static _executionToWorkflowMap map prevents
165        // MoMLParsing from being performed concurrently. MoMLParser is not
166        // thread-safe, even using different instances.
167        synchronized(_executionToWorkflowMap) {
168            NamedObj workflow = null;
169            WeakReference<NamedObj> weakWorkflow = _executionToWorkflowMap.get(execId);
170            if(weakWorkflow != null) {
171                workflow = weakWorkflow.get();
172            }
173            
174            if(workflow == null) { 
175                //System.out.println("parsing for " + execId);
176                MoMLParser parser = new MoMLParser();
177                String momlStr = getMoMLForExecution(execId);                
178                try {
179                    workflow = parser.parse(momlStr);
180                } catch (Exception e) {
181                    throw new QueryException("Error parsing workflow MoML.", e);
182                }
183                _executionToWorkflowMap.put(execId, new WeakReference<NamedObj>(workflow));
184            }            
185            
186            // return a copy of the workflow since the caller may modify
187            // the workflow.
188            try {
189                return (NamedObj) workflow.clone();
190            } catch (CloneNotSupportedException e) {
191                throw new QueryException("Error cloning workflow.", e);
192            }
193        }        
194    }
195
196    @Override
197    public List<Integer> getExecutionsForTimespan(Date start, Date end)
198            throws QueryException {
199        // TODO Auto-generated method stub
200        return null;
201    }
202
203    @Override
204    public List<Integer> getExecutionsForWorkflowRuns(String workflowName,
205            String userName) throws QueryException {
206        // TODO Auto-generated method stub
207        return null;
208    }
209
210    @Override
211    public List<Integer> getExecutionsForWorkflowRunsAfter(String workflowName,
212            String userName, Date after) throws QueryException {
213        // TODO Auto-generated method stub
214        return null;
215    }
216
217    @Override
218    public List<Integer> getExecutionsForWorkflowRuns(String workflowName,
219            String userName, Date after, Date before, int execIdAfter,
220            int execIdBefore) throws QueryException {
221        // TODO Auto-generated method stub
222        return null;
223    }
224
225    @Override
226    public List<KeplerLSID> getExecutionLSIDsForWorkflowRuns(
227            String workflowName, String userName, Date after, Date before,
228            int execIdAfter, int execIdBefore) throws QueryException {
229        // TODO Auto-generated method stub
230        return null;
231    }
232
233    @Override
234    public List<Integer> getExecutionsForWorkflowRunsBefore(
235            String workflowName, String userName, Date before)
236            throws QueryException {
237        // TODO Auto-generated method stub
238        return null;
239    }
240
241    @Override
242    public Integer getLastExecutionForWorkflow(KeplerLSID lsid)
243            throws QueryException {
244        // TODO Auto-generated method stub
245        return null;
246    }
247
248    @Override
249    public Integer getLastExecutionForWorkflow(String workflow)
250            throws QueryException {
251        // TODO Auto-generated method stub
252        return null;
253    }
254
255    @Override
256    public KeplerLSID getLastExecutionLSIDForWorkflow(String workflow)
257            throws QueryException {
258        // TODO Auto-generated method stub
259        return null;
260    }
261
262    @Override
263    public KeplerLSID getLastExecutionLSIDForWorkflow(KeplerLSID lsid)
264            throws QueryException {
265        // TODO Auto-generated method stub
266        return null;
267    }
268
269    @Override
270    public String getErrorForExecution(KeplerLSID lsid) throws QueryException {
271        // TODO Auto-generated method stub
272        return null;
273    }
274
275    @Override
276    public boolean isErrorForExecution(KeplerLSID executionLSID)
277            throws QueryException {
278        // TODO Auto-generated method stub
279        return false;
280    }
281
282    /** Get an sequence of tokens for an execution.
283     *  @param execId the execution id
284     *  @param last if true, the sequence starts at the last token created
285     *  and goes backwards to the first; otherwise the sequence starts at
286     *  the first.
287     */
288    @Override
289    public List<Integer> getTokensForExecution(int execId, boolean last)
290        throws QueryException
291    {   
292        return getTokensForExecution(execId, null, last);
293    }
294
295    /** Get an sequence of tokens for an execution.
296     *  @param execId the execution id
297     *  @param portId the port id. If null, returns the ids of
298     *  tokens read in entire execution.
299     *  @param last if true, the sequence starts at the last token created
300     *  and goes backwards to the first; otherwise the sequence starts at
301     *  the first.
302     */
303    @Override
304    public List<Integer> getTokensForExecution(int execId, Integer portId,
305            boolean last) throws QueryException {
306        // TODO Auto-generated method stub
307        return null;
308    }
309
310    /** Get the firing id(s) of the actor(s) that read or wrote a token.
311     *  @param tokenId the token id
312     *  @param read If true, return the actor(s) firing id(s) that read
313     *  the token. Otherwise, return the actor firing that wrote the token.
314     */
315    @Override
316    public List<Integer> getActorFiringForToken(int tokenId, boolean read)
317            throws QueryException {
318        // TODO Auto-generated method stub
319        return null;
320    }
321
322    @Override
323    public List<Integer> getTokensForFiring(int fireId, boolean read)
324            throws QueryException {
325        // TODO Auto-generated method stub
326        return null;
327    }
328
329    /** Get the Token. */
330    @Override
331    public Token getToken(int tokenId) throws QueryException
332    {
333        Token token = null;
334        //get the type
335        String type = getTokenType(tokenId);
336        //get the value
337        String value = getTokenValue(tokenId);
338        
339        if(_stringTokenValuesHaveSurroundingQuotes()) {
340            // if the token is a StringToken, then the value is surrounded
341            // by double-quotes. the quotes should be removed from the value
342            // otherwise they are in the contents of the new StringToken, which
343            // is not identical to the one recorded to provenance.
344            if(type.equals(StringToken.class.getName()) && value.length() >= 2) {
345                value = value.substring(1, value.length() - 1);
346            }
347        }
348
349        if(type.equals(_stringTokenClassName)) {
350            
351            //put it together - requires token to have a string constructor
352            try 
353            {
354                Class<?> clazz = Class.forName(type);
355                token = (Token) clazz.getConstructor(String.class).newInstance(value);
356            } 
357            catch (Exception e) 
358            {
359                System.err.println("WARNING: Token could not be constructed for type: " +
360                        type + ": " + e.getMessage());
361                e.printStackTrace();
362            }
363
364            
365        } else {
366            try {
367                synchronized(_parserLock) {
368                    if (_parser == null) {
369                        _parser = new PtParser();
370                    }
371        
372                    if (_parseTreeEvaluator == null) {
373                        _parseTreeEvaluator = new ParseTreeEvaluator();
374                    }
375        
376                    ASTPtRootNode parseTree = _parser.generateParseTree(value);
377                    token = _parseTreeEvaluator.evaluateParseTree(parseTree);
378                }
379            } catch (Throwable e) {
380                System.err.println("Warning: Token value invalid: " + e.getMessage());
381            }
382        }
383        
384        return token;
385    }
386
387    
388    @Override
389    public String getTokenValue(int tokenId) throws QueryException {
390        // TODO Auto-generated method stub
391        return null;
392    }
393
394    @Override
395    public String getTokenType(int tokenId) throws QueryException {
396        // TODO Auto-generated method stub
397        return null;
398    }
399
400    /** Get the channel that a token was read or written on.
401     *  @param tokenId the token id
402     *  @param read if true, return the channel the token was read on.
403     *  otherwise, return the channel the token was written on.
404     *  @param fireId the actor firing id. can be null for writes, but
405     *  must be specified for reads.
406     *  @return the channel the token was read or written on.
407     */
408    @Override
409    public Integer getChannelForToken(int tokenId, boolean read, Integer fireId)
410        throws QueryException {
411        // TODO
412        return null;
413    }
414
415    @Override
416    public String getActorName(int fireId) throws QueryException {
417        // TODO Auto-generated method stub
418        return null;
419    }
420
421    @Override
422    public String getActorType(int fireId) throws QueryException {
423        // TODO Auto-generated method stub
424        return null;
425    }
426
427    @Override
428    public Integer getEntityId(String entityName, KeplerLSID lsid)
429            throws QueryException {
430        // TODO Auto-generated method stub
431        return null;
432    }
433
434    @Override
435    public Integer getEntityId(String entityName, String workflowName)
436            throws QueryException {
437        // TODO Auto-generated method stub
438        return null;
439    }
440
441    @Override
442    public String getEntityType(Integer entityId) throws QueryException {
443        // TODO Auto-generated method stub
444        return null;
445    }
446
447    @Override
448    public Integer getEntityWorkflowId(Integer entityId) throws QueryException {
449        // TODO Auto-generated method stub
450        return null;
451    }
452
453    @Override
454    public Map<String, String> getParameterNameValuesForFiring(int fireId)
455            throws QueryException {
456        // TODO Auto-generated method stub
457        return null;
458    }
459
460    @Override
461    public Map<String, String> getParameterNameValuesForExecution(int execId)
462            throws QueryException {
463        // TODO Auto-generated method stub
464        return null;
465    }
466
467    @Override
468    public String getParameterValueLatest(String parameter, KeplerLSID lsid)
469            throws QueryException {
470        // TODO Auto-generated method stub
471        return null;
472    }
473
474    @Override
475    public String getParameterValueAtTime(Date timestamp, String parameter,
476            KeplerLSID lsid) throws QueryException {
477        // TODO Auto-generated method stub
478        return null;
479    }
480
481    @Override
482    public List<Integer> getImmediateDependencies(int tokenId)
483            throws QueryException {
484        // TODO Auto-generated method stub
485        return null;
486    }
487
488    @Override
489    public List<byte[]> getAssociatedDataForExecution(int execId,
490            Map<String, String> metadataMap, boolean matchAny)
491            throws QueryException {
492        // TODO Auto-generated method stub
493        return null;
494    }
495
496    /** Get any associated keys-values for an execution. */
497    @Override
498    public Map<String,String> getAssociatedKeysValuesForExecution(int execId)
499        throws QueryException {
500        // TODO
501        return null;
502    }
503
504    @Override
505    public Map<KeplerLSID, WorkflowRun> getWorkflowRunsForExecutionLSIDs(
506            List<KeplerLSID> executions) throws QueryException {
507        // TODO Auto-generated method stub
508        return null;
509    }
510
511    /** Get workflow runs for a user. */
512    @Override
513    public List<WorkflowRun> getWorkflowRunsForUser(String user) throws QueryException {
514        return new LinkedList<WorkflowRun>();
515    }
516
517    @Override
518    public List<Integer> getExecutionIdsForTags(String tagsSearchString)
519            throws QueryException {
520        // TODO Auto-generated method stub
521        return null;
522    }
523
524    @Override
525    public List<String> getTagsForExecutionId(int execId) throws QueryException {
526        // TODO Auto-generated method stub
527        return null;
528    }
529
530    @Override
531    public String getTypeForTag(String conceptId) {
532        // TODO Auto-generated method stub
533        return null;
534    }
535
536    @Override
537    public Map<NamedOntClass, String> getTagClassesForExecutionId(int execId)
538            throws QueryException {
539        // TODO Auto-generated method stub
540        return null;
541    }
542
543    @Override
544    public Integer getExecutionForExecutionLSIDWithoutRevision(
545            String execLSIDWithoutRevision) throws QueryException {
546        // TODO Auto-generated method stub
547        return null;
548    }
549
550    @Override
551    public Integer getExecutionForOldestReferralExecutionLSIDWithoutRevision(
552            String stringWithoutRevision) throws QueryException {
553        // TODO Auto-generated method stub
554        return null;
555    }
556
557    @Override
558    public List<KeplerLSID> getExecutionsForType(type type)
559            throws QueryException {
560        // TODO Auto-generated method stub
561        return null;
562    }
563
564    @Override
565    public boolean isImportedExecution(KeplerLSID executionLSID)
566            throws QueryException {
567        // TODO Auto-generated method stub
568        return false;
569    }
570
571    @Override
572    public List<String> getPortsForActor(KeplerLSID workflow, String actor)
573            throws QueryException {
574        // TODO Auto-generated method stub
575        return null;
576    }
577
578    @Override
579    public String getUserForExecution(Integer execId) throws QueryException {
580        // TODO Auto-generated method stub
581        return null;
582    }
583
584    @Override
585    public String getUserForExecution(KeplerLSID execLSID) throws QueryException {
586        // TODO Auto-generated method stub
587        return null;        
588    }
589
590    @Override
591    public String getHostIdForExecution(Integer execId) throws QueryException {
592        // TODO Auto-generated method stub
593        return null;
594    }
595
596    @Override
597    public String getOutputRoleToken(int tokenId) throws QueryException {
598        // TODO Auto-generated method stub
599        return null;
600    }
601
602    @Override
603    public String getInputRoleForTokenAndFireId(int tokenId, int fireId)
604            throws QueryException {
605        // TODO Auto-generated method stub
606        return null;
607    }
608
609    @Override
610    public Map<String, String> getParameterNameValuesOfSpecificTypeForExecution(
611            int execId) throws QueryException {
612        // TODO Auto-generated method stub
613        return null;
614    }
615
616    @Override
617    public Date[] getTimestampsForActorFiring(int fireId) throws QueryException {
618        // TODO Auto-generated method stub
619        return null;
620    }
621
622    @Override
623    public List<Integer> getActorFiringIds(String actorName, Integer wfExecId)
624            throws QueryException {
625        // TODO Auto-generated method stub
626        return null;
627    }
628
629    @Override
630    public Map<String, String> getParameterAndPortParameterNameValuesForFiring(
631            int fireId) throws QueryException {
632        // TODO Auto-generated method stub
633        return null;
634    }
635
636    @Override
637    public List<Integer> getActorFirings(int wfExecId) throws QueryException {
638        // TODO Auto-generated method stub
639        return null;
640    }
641    
642    /** Get the total execution time for an actor.
643    *
644    *  @param workflow the workflow LSID. If null, must specify execution id.
645    *  @param execLSID the execution id. If null, use the last execution of the workflow.
646    *  @param actor the full actor name.
647    *  @return the total time execution time of the actor, in milliseconds.
648    */
649    @Override
650    public long getTotalExecutionTimeForActor(KeplerLSID workflow, KeplerLSID execLSID,
651        String actor) throws QueryException
652    {
653        Map<String,Long> map = getExecutionTimesForActor(workflow, execLSID, actor);
654        long sum = 0;
655        for(Long time : map.values())
656        {
657            sum += time;
658        }
659        return sum;
660    }
661    
662    /** Get the execution times for an actor.
663    *
664    * @param workflow the workflow LSID. If null, must specify execution id.
665    * @param execLSID the execution LSID. If null, the last execution of the workflow
666    * is used.
667    * @param actor the full actor name.
668    * @return a map of actor fire id to execution time pairs. if a firing does not
669    * have a valid start or stop time, the firing is not included in the result.
670    */
671    @Override
672    public Map<String,Long> getExecutionTimesForActor(KeplerLSID workflow,
673            KeplerLSID execLSID, String actor) throws QueryException {
674        // TODO Auto-generated method stub
675        return null;
676    }
677    
678    /** Get the number of bytes read or written by a port.
679    *
680    *  @param workflow the workflow LSID. If null, must specify execution id.
681    *  @param execId the execution id. If null, the last execution of the workflow
682    *  is used.
683    *  @param port the full port name.
684    *  @param read If true, get the bytes read. Otherwise, get the bytes written.
685    *  @return a map of port event id to bytes read/written.
686    */
687    @Override
688    public Map<Integer,Integer> getIOBytesForPort(KeplerLSID workflow, Integer execId,
689        String port, boolean read) throws QueryException {
690        // TODO Auto-generated method stub
691        return null;
692    }
693    
694    /** Get the total number of bytes read or or written by an actor over all its ports.
695     *  @param workflow the workflow LSID. If null, specify the execution id.
696     *  @param execId the execution id. If null, the last execution of the workflow
697     *  is used.
698     *  @param actor the full actor name.
699     *  @param read If true, get the bytes read. Otherwise, get the bytes written.
700     */
701    @Override
702    public Integer getTotalIOBytesForActor(KeplerLSID workflow, Integer execId, String actor,
703        boolean read) throws QueryException
704    {
705        Integer retval = 0;
706        
707        if(execId == null)
708        {
709            execId = _getLastExecutionId(workflow);
710        }
711        
712        List<String> portsList = getPortsForActor(workflow, actor);
713        
714        for(String port : portsList)
715        {
716            Map<Integer,Integer> map = getIOBytesForPort(workflow, execId, port, read);
717            for(Integer size : map.values())
718            {
719                retval += size;
720            }
721        }
722        
723        return retval;
724    }
725        
726    /*
727    @Override
728    public List<LinkIO> getLinksIO(KeplerLSID workflow, Integer execId) throws QueryException {
729        // TODO Auto-generated method stub
730        return null;
731    }
732    */
733
734    /** Get the timestamp(s) when a token was read. If a token was
735     *  never read, this can return null or an empty array.
736     */
737    @Override
738    public Date[] getTimestampsForTokenRead(Integer tokenId) throws QueryException {
739        return null;
740    }
741
742    /** Get the timestamp when a token was written. */
743    @Override
744    public Date getTimestampForTokenWrite(Integer tokenId) throws QueryException {
745        return null;
746    }
747
748    /** Get the last execution id for a workflow. If no execution id found,
749     *  throws exception.
750     */
751    protected Integer _getLastExecutionId(KeplerLSID workflow)
752        throws QueryException
753    {   
754        if(workflow == null)
755        {
756            throw new QueryException("Must specify either workflow LSID or execution id.");
757        }
758        
759        // get the last execution id for the workflow
760        Integer execId = getLastExecutionForWorkflow(workflow);
761
762        if(execId == null)
763        {
764            throw new QueryException("Could not find last execution for workflow.");
765        }
766        return execId;
767    }
768
769    /** Returns true if getTokenValue() for StringTokens has
770     *  surrounding double-quotes. i.e., the value was saved
771     *  using StringToken.toString() (which adds double-quotes)
772     *  instead of StringToken.stringValue().
773     */
774    abstract protected boolean _stringTokenValuesHaveSurroundingQuotes();
775    
776    /** A mapping of execution id to workflow objects. We use weak
777     *  references for the workflow objects so that they can be garbage
778     *  collected.
779     */
780    private static Map<Integer,WeakReference<NamedObj>> _executionToWorkflowMap =
781            new HashMap<Integer,WeakReference<NamedObj>>();
782
783    private static final Object _parserLock = new Object();
784    private ParseTreeEvaluator _parseTreeEvaluator = null;
785    private PtParser _parser = null;
786    private static final String _stringTokenClassName = StringToken.class.getName();
787
788}