001/**
002 *  '$RCSfile$'
003 *  '$Author: crawl $'
004 *  '$Date: 2012-07-25 17:41:30 +0000 (Wed, 25 Jul 2012) $'
005 *  '$Revision: 30276 $'
006 *
007 *  For Details:
008 *  http://www.kepler-project.org
009 *
010 *  Copyright (c) 2012 The Regents of the
011 *  University of California. All rights reserved. Permission is hereby granted,
012 *  without written agreement and without license or royalty fees, to use, copy,
013 *  modify, and distribute this software and its documentation for any purpose,
014 *  provided that the above copyright notice and the following two paragraphs
015 *  appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF
016 *  CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
017 *  OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
018 *  DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
019 *  POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY
020 *  DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
022 *  SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
023 *  CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
024 *  ENHANCEMENTS, OR MODIFICATIONS.
025 */
026package org.kepler.loader.util;
027
028import java.io.File;
029import java.io.IOException;
030import java.lang.reflect.Modifier;
031import java.net.URL;
032import java.sql.Connection;
033import java.sql.ResultSet;
034import java.sql.SQLException;
035import java.sql.Statement;
036import java.util.HashSet;
037import java.util.LinkedList;
038import java.util.List;
039import java.util.Set;
040
041import org.kepler.Kepler;
042import org.kepler.build.modules.Module;
043import org.kepler.build.modules.ModuleTree;
044import org.kepler.kar.KarDoclet;
045import org.kepler.objectmanager.library.LibraryManager;
046import org.kepler.util.sql.DatabaseFactory;
047import org.kepler.util.sql.HSQL;
048
049import ptolemy.actor.Actor;
050import ptolemy.actor.Director;
051import ptolemy.actor.gui.ConfigurationApplication;
052import ptolemy.data.expr.Parameter;
053import ptolemy.util.MessageHandler;
054
055/** A class to that finds source files whose classes are not in the actor tree.
056 * 
057 *  TODO:
058 *    separate deprecated classes
059 *    separate super classes
060 *    include some subclasses of Attribute
061 *    warn if xml has missing or invalid semantic types
062 *    warn if xml has no semantic types in onto:2
063 *    
064 *  @author Daniel Crawl
065 *  @version $Id: FindMissingActors.java 30276 2012-07-25 17:41:30Z crawl $
066 */
067public class FindMissingActors {
068
069        /** Find files whose classes are not in the actor tree.
070         * 
071         *  @param args a list of module names. if empty, all modules in
072         *  current suite are searched.
073         */
074        public static void main(String[] args) {
075                
076        // call the module initializers
077        try {
078            Kepler.initialize();
079        } catch (Exception e) {
080            MessageHandler.error("ERROR initializing modules.", e);
081            System.exit(1);
082        }
083
084        // start the kepler cache
085        
086        Kepler.setOntologyIndexFile();
087
088        _initializeCache();
089        
090        final ModuleTree tree = ModuleTree.instance();
091        List<Module> modules;
092        if(args.length == 0 || (args.length == 1 && args[0].equals("undefined"))) {
093            modules = tree.getModuleList();
094        } else {
095            modules = new LinkedList<Module>();
096            for(String name : args) {
097                final Module module = tree.getModule(name);
098                if(module == null) {
099                    System.out.println("Module " + name + " is not in current suite.");
100                } else {
101                    modules.add(module);
102                }
103            }
104        }
105        
106        for(Module module : modules) {
107            
108            final String moduleName = module.getName();
109            System.out.println("Find missing entries for module " + moduleName);
110
111            // print which files do not have entries
112            try {                                
113                _printFilesMissingEntries(module);
114                
115            } catch(Exception e) {
116                MessageHandler.error("Error finding missing entries.", e);
117            }
118            
119        }
120        
121        // shutdown the cache and exit
122       _shutdownCache(true);
123
124        }
125        
126        
127        /** Get a list of source files in a module that are not in the actor cache. */
128        private static void _printFilesMissingEntries(Module module) throws Exception {
129            
130            
131            List<String> fileNames = module.getSourceFileNames();
132            File srcDir = module.getSrc();
133            
134            if(_actorCacheClasses.isEmpty()) {
135                
136                Connection conn = null;
137                Statement st = null;
138                ResultSet result = null;
139                try {
140                    conn = DatabaseFactory.getDBConnection();
141                    st = conn.createStatement();
142                result = st.executeQuery("select classname from cachecontenttable ");
143                
144                while(result.next()) {
145                    _actorCacheClasses.add(result.getString(1));
146                }
147                } finally {
148                    try {
149                        if(result != null) {
150                            result.close();
151                        }
152                        if(st != null) {
153                            st.close();
154                        }
155                        if(conn != null) {
156                            conn.close();
157                        }
158                    } catch(SQLException e) {
159                        MessageHandler.error("ERROR closing cache database.", e);
160                    }
161                }
162            }
163            
164            List<String> missing = new LinkedList<String>();
165            List<String> deprecated = new LinkedList<String>();
166            
167            for(String relativeName : fileNames) {
168                
169                String className = relativeName.replace(File.separatorChar, '.');
170                className = className.substring(0, className.indexOf(".java"));
171                //System.out.println("class is " + className);
172                
173                String fileName = new File(srcDir, relativeName).getAbsolutePath();          
174                
175                if(!_actorCacheClasses.contains(className)) {
176                    
177                    // make sure class is an actor, director or parameter
178                    //System.out.println("checking " + className);
179                    Class<?> clazz = null;
180                    
181                    try {
182                        clazz = Class.forName(className);
183                    } catch(Throwable t) {
184                        // ignore
185                        continue;
186                    }
187                    
188                    // see if the class is an Actor, Director, or Parameter
189                    // is not abstract, or an interface
190                    if((Actor.class.isAssignableFrom(clazz) ||
191                            Director.class.isAssignableFrom(clazz) ||
192                            Parameter.class.isAssignableFrom(clazz)) &&
193                            !clazz.isInterface() && 
194                            !Modifier.isAbstract(clazz.getModifiers())) {
195             
196                        // see if it's deprecated
197                        // XXX this always returns false since KarDoclet was not
198                        // run for this class.
199                        if(KarDoclet.isClassDeprecated(className)) {
200                            deprecated.add(fileName);
201                        } else {
202                            missing.add(fileName);                      
203                        }
204                    }
205                }
206            }
207            
208            if(!missing.isEmpty()) {
209            System.out.println("Source files not in library:");
210            for(String name : missing) {
211                System.out.println(name);
212            }
213            }
214            
215            if(!deprecated.isEmpty()) {
216            System.out.println("Deprecated source files not in library:");
217            for(String name : deprecated) {
218                System.out.println(name);
219            }
220            }
221        }
222
223        private static void _initializeCache() {
224                                
225                // load the configuration since it is required to load the
226                // KAR entries handlers, which in turn is required to build
227                // the actor library
228                
229            // NOTE: we must use a configuration with the GUI, otherwise
230            // MoML filters are used to remove GUI actors.
231                String spec = "ptolemy/configs/kepler/ConfigGUIAndCache.xml";
232                URL url = null;
233                try {
234                        url = ConfigurationApplication.specToURL(spec);
235                } catch (IOException e) {
236                        MessageHandler.error("ERROR configuration URL.", e);
237                        System.exit(1);
238                }
239                
240                try {
241                        ConfigurationApplication.readConfiguration(url);
242                } catch (Exception e) {
243                        MessageHandler.error("ERROR reading configuration.", e);
244                        System.exit(1);
245                }               
246                
247                // build the actor library in case it does not exist
248                LibraryManager.getInstance().buildLibrary();
249        }
250        
251        
252        private static void _shutdownCache(boolean exit) {
253                // call the module deinitializers
254                Kepler.shutdown();
255                HSQL.shutdownServers();
256                
257                if(exit) {
258                    // we have to call System.exit() because ???
259                    System.exit(0);
260                }
261        }
262
263        private static Set<String> _actorCacheClasses = new HashSet<String>();
264}