Some progress toward implementing store(Analysis).
[cfb.git] / prod / net / jaekl / cfb / CFB.java
1 package net.jaekl.cfb;
2
3 // Comparative FindBugs
4 // 
5 // Tool to compare successive runs of FindBugs, 
6 // flagging the change from one run to the next.
7 // 
8 // Copyright (C) 2015 Christian Jaekl
9
10 import java.io.File;
11 import java.io.IOException;
12 import java.io.PrintWriter;
13 import java.sql.Connection;
14 import java.sql.SQLException;
15 import java.text.MessageFormat;
16 import java.util.Locale;
17 import java.util.Locale.Category;
18
19 import net.jaekl.cfb.analyze.Analysis;
20 import net.jaekl.cfb.analyze.Analyzer;
21 import net.jaekl.cfb.analyze.MessageMap;
22 import net.jaekl.cfb.db.CfbSchema;
23 import net.jaekl.cfb.db.TypeMismatchException;
24 import net.jaekl.cfb.db.driver.DbDriver;
25 import net.jaekl.cfb.db.driver.PostgresqlDriver;
26 import net.jaekl.cfb.store.DbStore;
27 import net.jaekl.qd.xml.XmlParseException;
28
29 import org.apache.commons.cli.CommandLine;
30 import org.apache.commons.cli.GnuParser;
31 import org.apache.commons.cli.HelpFormatter;
32 import org.apache.commons.cli.Options;
33 import org.apache.commons.cli.ParseException;
34 import org.xml.sax.SAXException;
35
36 public class CFB {
37         DbDriver m_driver;
38         CfbSchema m_schema;
39         CfbBundle m_bundle;     
40         Locale m_locale;
41         
42         // Command-line parameters
43         String m_dbName; // db name
44         File m_fbp;             // FindBugsProject file
45         File m_fbDir;   // Directory where FindBugs is installed
46         String m_host;  // db host
47         int m_port;             // db port
48         String m_user;  // db user
49         String m_pass;  // db password
50         String m_buildNum; // build number (version)
51         boolean m_removeSchema; // purge DB schema
52         
53         CFB(Locale locale) {
54                 m_driver = new PostgresqlDriver();
55                 m_schema = new CfbSchema(m_driver);
56                 m_locale = locale;
57                 m_bundle = CfbBundle.getInst(m_locale);
58                 
59                 m_dbName = "CFB";
60                 m_fbp    = null;
61                 m_fbDir  = null;
62                 m_host = "localhost";
63                 m_port = 5432;
64                 m_pass = "";
65                 m_user = "user";
66                 m_buildNum = null;
67                 m_removeSchema = false;
68         }
69         
70         Options createOptions() {
71                 Options opt = new Options();
72                 
73                 opt.addOption("d", "dbname", true, "DB name");
74                 opt.addOption("f", "fbp",    true, "FindBugsProject file");
75                 opt.addOption("h", "host",   true, "DB hostname");
76                 opt.addOption("n", "number", true, "Build number (version)");
77                 opt.addOption("p", "pass",   true, "DB password");
78                 opt.addOption("r", "remove", false, "Remove database schema (drop all data)");
79                 opt.addOption("t", "port",   true, "DB port");
80                 opt.addOption("u", "user",   true, "DB username");
81                 
82                 return opt;
83         }
84         
85         boolean parseArgs(PrintWriter pw, String[] args) {
86                 Options opt = createOptions();
87                 
88                 try {
89                         CommandLine line = new GnuParser().parse(opt, args);
90                         if (line.hasOption("d")) {
91                                 m_dbName = line.getOptionValue("d");
92                         }
93                         if (line.hasOption("f")) {
94                                 m_fbp = new File(line.getOptionValue("f"));
95                         }
96                         if (line.hasOption("h")) {
97                                 m_host = line.getOptionValue("h");
98                         }
99                         if (line.hasOption("n")) {
100                                 m_buildNum = line.getOptionValue("n");
101                         }
102                         if (line.hasOption("p")) {
103                                 m_pass = line.getOptionValue("p");
104                         }
105                         m_removeSchema = line.hasOption("r");
106                         if (line.hasOption("t")) {
107                                 m_port = Integer.parseInt(line.getOptionValue("t"));
108                         }
109                         if (line.hasOption("u")) {
110                                 m_user = line.getOptionValue("u");
111                         }
112                 } 
113                 catch (ParseException exc) {
114                         usage(pw, opt);
115                         return false;
116                 }
117                 
118                 return true;
119         }
120         
121         void usage(PrintWriter pw, Options opt) {
122                 HelpFormatter help = new HelpFormatter();
123                 help.printHelp(pw, 80, getClass().getName(), "", opt, 0, 0, "", true);
124         }
125         
126         String trans(String key) {
127                 return m_bundle.get(key);
128         }
129         
130         String getenv(String varName) {
131                 // This is a separate function so that we can override it at unit test time
132                 return System.getenv(varName);
133         }
134         
135         String getProperty(String propName) {
136                 // This is a separate function so that we can override it at unit test time
137                 return System.getProperty(propName);
138         }
139         
140         File getFindBugsDir() {
141                 return (null != m_fbDir) ? m_fbDir : new File(".");
142         }
143         
144         void initArgs() {
145                 String findBugsDir = getenv("FINDBUGS_HOME");
146                 if (null != findBugsDir) {
147                         m_fbDir = new File(findBugsDir);
148                 }
149                 findBugsDir = getProperty("findbugs.home");
150                 if (null != findBugsDir) {
151                         m_fbDir = new File(findBugsDir);
152                 }
153         } 
154         
155         void doMain(PrintWriter pw, String[] args) throws SQLException, IOException, XmlParseException, SAXException, TypeMismatchException {
156                 initArgs();     // read environment and system properties
157                 if ( ! parseArgs(pw, args) ) {
158                         return;
159                 }
160
161                 File findBugsDir = getFindBugsDir();
162                 File workDir = new File(".");
163                 MessageMap messageMap = new MessageMap();
164                 messageMap.load(findBugsDir, Locale.getDefault(Category.DISPLAY));
165                 
166                 try (Connection con = m_driver.connect(m_host, m_port, m_dbName, m_user, m_pass)) {
167                         m_schema.setMessageMap(messageMap);
168                         
169                         if (m_removeSchema) {
170                                 m_schema.purge(con);
171                                 return;
172                         }
173                         m_schema.ensureDbInitialized(con);
174                         messageMap.loadIds(con, m_driver);
175                 }
176                 catch (SQLException exc) {
177                         reportUnableToConnect(pw, exc);
178                         return;
179                 }
180                 
181                 Analyzer analyzer = new Analyzer(messageMap);
182                 Analysis analysis = analyzer.analyze(pw, workDir, m_fbp, m_buildNum);
183                 if (null == analysis) {
184                         pw.println(trans(CfbBundle.ANALYSIS_FAILED));
185                         return;
186                 }
187                 
188                 try (Connection con = m_driver.connect(m_host, m_port, m_dbName, m_user, m_pass)) {
189                         DbStore store = new DbStore(con, m_driver, messageMap.getColl());
190                         
191                         store.put(analysis);
192                 }
193                 catch (SQLException exc) {
194                         reportUnableToConnect(pw, exc);
195                         return;
196                 }
197         }
198
199         private void reportUnableToConnect(PrintWriter pw, SQLException exc) {
200                 String cannotConnectFormat = trans(CfbBundle.CANNOT_CONNECT);
201                 String cannotConnect = MessageFormat.format(cannotConnectFormat, m_host, ""+m_port, m_dbName, m_user);
202                 exc.printStackTrace(pw);
203                 pw.println(cannotConnect);
204         }
205         
206         public static void main(String[] args) {
207                 CFB cfb = new CFB(Locale.getDefault());
208                 
209                 try (PrintWriter pw = new PrintWriter(System.out)){
210                         cfb.doMain(pw, args);
211                         pw.flush();
212                 } catch (SQLException | IOException | XmlParseException | SAXException | TypeMismatchException exc) {
213                         exc.printStackTrace();
214                 }
215         }
216
217 }