001/*
002 * Copyright (c) 2013 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2017-08-24 05:17:26 +0000 (Thu, 24 Aug 2017) $' 
007 * '$Revision: 34620 $'
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.loader.util;
030
031import java.io.File;
032import java.io.FileInputStream;
033import java.io.InputStream;
034import java.util.Map;
035
036import org.apache.commons.io.FileUtils;
037import org.kepler.Kepler;
038import org.kepler.build.util.Version;
039import org.kepler.kar.KAREntry;
040import org.kepler.kar.KARFile;
041import org.kepler.kar.handlers.ActorMetadataKAREntryHandler;
042import org.kepler.objectmanager.ActorMetadata;
043import org.kepler.util.sql.HSQL;
044
045import ptolemy.kernel.CompositeEntity;
046import ptolemy.kernel.util.NamedObj;
047import ptolemy.moml.MoMLParser;
048import ptolemy.moml.filter.BackwardCompatibility;
049import ptolemy.util.MessageHandler;
050
051/** A utility class to load workflows. This is used by 
052 *  org.kepler.build.RunTestWorkflows to test loading demo workflows.
053 * 
054 *  @author Daniel Crawl
055 *  @version $Id: ParseWorkflow.java 34620 2017-08-24 05:17:26Z crawl $
056 */
057public class ParseWorkflow {
058
059    /** Load workflows and exit.
060     *  @param args A list of workflow files to load.
061     */
062    public static void main(String[] args) {
063        
064        System.setProperty("java.awt.headless", "true");
065        MoMLParser.setMoMLFilters(BackwardCompatibility.allFilters());
066        MessageHandler.setMessageHandler(new MessageHandler());
067        try {
068                // initialize Kepler to load the kepler-specific backward-compatible
069                // moml filters
070                Kepler.initialize();
071                Kepler.setJavaPropertiesAndCopyModuleDirectories();
072                } catch (Exception e) {
073                        MessageHandler.error("Error initializing Kepler.", e);
074                }
075
076        try {
077            ParseWorkflow parse = new ParseWorkflow();
078            parse.parseWorkflows(args);
079        } catch(Throwable t) {
080            System.err.println("Error: " + t.getMessage());
081            t.printStackTrace();
082        }
083        
084        Kepler.shutdown();
085        HSQL.shutdownServers();
086    }
087
088    /** Parse an actor's XML definition. */
089    public static NamedObj parseActor(File file) throws Exception {
090        
091        if(!file.exists()) {
092                throw new Exception("Actor file does not exist: " + file.getAbsolutePath());
093        }
094        
095        FileInputStream stream = null;
096        try {
097                stream = new FileInputStream(file);
098                ActorMetadata metadata = new ActorMetadata(stream);
099                NamedObj metadataNamedObj = metadata.getActorAsNamedObj(null);
100                String metadataString = metadataNamedObj.exportMoMLPlain();
101                
102                MoMLParser parser = new MoMLParser();
103                parser.resetAll();
104                CompositeEntity container = new CompositeEntity();
105                parser.setContext(container);
106                parser.parse(metadataString);
107                return container.getEntity(metadata.getName());
108                
109        } finally {
110                if(stream != null) {
111                        stream.close();
112                }
113        }
114        
115    }
116        
117    /** Load workflows. */
118    public void parseWorkflows(String[] args) throws Exception {
119        for(int i = 0; i < args.length; i++) {
120                boolean isActor = false;
121                if(args[i].equals("-a")) {
122                        isActor = true;
123                        i++;
124                }
125                String path = args[i];
126            File file = new File(path);
127            if(isActor) {
128                parseActor(file);
129            } else {
130                parseWorkflow(file);
131            }
132        }
133    }
134    
135    /** Parse a workflow MoML XML or KAR file.
136     *  @return the constructed NamedObj 
137     */
138    public static NamedObj parseWorkflow(File file) throws Exception {
139        
140        if(!file.exists()) {
141            throw new Exception("File does not exist " + file.getAbsolutePath());
142        }
143
144        if(file.getName().endsWith(".xml")) {
145            return _parseXML(file);
146        } else if(file.getName().endsWith(".kar")) {
147            return parseKAR(file, false);
148        } else {
149            throw new Exception("Unknown type of workflow: " + file.getAbsolutePath());
150        }
151    }
152        
153    /** Parse a workflow KAR file.
154     *  @return the constructed NamedObj 
155     */
156    public static NamedObj parseKAR(File file, boolean ignoreDependencies) throws Exception {
157        
158        // FIXME most of this method is duplicated from the
159        // KeplerConfigurationApplication constructor.
160        
161        try(KARFile karFile = new KARFile(file)) {
162        
163            if(!karFile.isOpenable() && !ignoreDependencies) {
164                
165                // check dependencies.
166                Map<String, Version> missingDeps = karFile.getMissingDependencies();
167                if(!missingDeps.isEmpty()) {
168                    
169                    // print out the missing dependencies
170                    System.out.println("ERROR: Missing module dependencies:");
171                    for(Map.Entry<String, Version> entry : missingDeps.entrySet()) {
172                        System.out.println("   " + entry.getKey());
173                    }
174                }
175            } else {
176             
177                // For each Actor in the KAR open the MOML
178                for (KAREntry entry : karFile.karEntries()) {
179    
180                    if (!ActorMetadataKAREntryHandler.handlesClass(entry.getType())) {
181                        //WARNING - using null TableauFrame here
182                        karFile.open(entry, null);
183                    } else {    
184                        // extract MOML to temp file
185                        File tmpFile = null;
186                        try {
187                            tmpFile = File.createTempFile("moml", ".xml");
188                            try(InputStream inputStream = karFile.getInputStream(entry);) {
189                                FileUtils.copyInputStreamToFile(inputStream, tmpFile);
190                            }
191                            return _parseXML(tmpFile);
192                        } finally {
193                            // delete file when done.
194                            if(tmpFile != null && !tmpFile.delete()) {
195                                System.err.println("Could not delete " + tmpFile.getAbsolutePath());
196                            }
197                        }
198                    }
199                }       
200            }
201        }
202        return null;
203    }
204    
205    /** Parse a MoML string. */
206    public static NamedObj parseMoML(String momlStr) throws Exception {
207        // MoMLParser is not thread-safe
208        synchronized(_lock) {
209            return new MoMLParser().parse(momlStr);
210        }
211    }
212    
213    /** Parse a workflow MoML file. */
214    private static NamedObj _parseXML(File file) throws Exception {
215        // MoMLParser is not thread-safe        
216        synchronized(_lock) {
217            return new MoMLParser().parse(null, file.toURI().toURL());
218        }
219    }
220    
221    private final static Object _lock = new Object();
222    
223}