source: gs2-extensions/tipple-bridge/trunk/src/src/main/java/sqlCli.java@ 34903

Last change on this file since 34903 was 34903, checked in by davidb, 3 years ago

Rolled back to r34900

File size: 9.9 KB
Line 
1import com.mysql.cj.exceptions.MysqlErrorNumbers;
2import picocli.CommandLine;
3import picocli.CommandLine.Command;
4import picocli.CommandLine.Option;
5import picocli.CommandLine.Parameters;
6
7import java.sql.*;
8import java.util.HashMap;
9import com.google.gson.Gson;
10import java.io.FileWriter;
11import java.util.concurrent.Callable;
12
13/*
14TODO:
15
16 */
17
18//-u su41Tipple -p --port 3306 --dbname koicarp_test
19//@/home/su41/configFileTest
20
21/*
22The mixinStandardHelpOptions = true adds in --help and --version options
23 */
24@Command (name="sqlCli", description = "Arguments for database connection", mixinStandardHelpOptions = true)
25public class sqlCli implements Callable<Integer> {
26
27 //our cli arguments
28 @Option(names = {"-u", "--user"}, description = "The user name",
29 required = true)
30 String userName;
31
32 //interactive allows the user to omit the argument value and instead enter it as a prompt
33 /*
34 NOTE: if you are running an interactive option on an IDE, most likely the IDE will be using
35 the javaw.exe library which tries to mimic the terminal.
36 The point is that interactive option would usually make whatever you enter hidden (it doesn't
37 echo back) but on the IDE it will echo back.
38 */
39 @Option(names = {"-p", "--password"}, description = "User's password", interactive = true,
40 required = true)
41 String password;
42
43 @Option(names = {"--port"}, description="Port number", defaultValue="3306")
44 int port;
45
46 @Option(names = {"--dbname"}, description="Name of the database", defaultValue="koicarp_test")
47 String dbName;
48
49 //project id - it should be required right?
50 //if they omit, the query would come up empty.
51 @Option(names = {"--projectID"}, description = "ID number of the project")
52 String projectID;
53
54 @Option(names = {"--host"}, description = "Type of host e.g. localhost ",
55 required = true, defaultValue = "localhost")
56 String host;
57
58 /*
59 this parameter can be read in at any point on the options line.
60 but that's only because it's the only parameter at the moment.
61 If we add more parameters, will have to start indexing
62 https://picocli.info/quick-guide.html#_options_and_parameters
63 */
64 @Parameters(description = "Name of the output JSON file. E.g. yourFileName.json")
65 String jsonOutputFile;
66
67 public Integer call(){
68 //if it doesn't end with ...
69 if(!jsonOutputFile.endsWith(".json")){
70 System.out.println("Invalid file format.");
71 System.out.println("The file to save the output to must be a .json file.");
72 //exit code other than 0 means it's not fine.
73 return 1;
74 }
75 //else we're good to go.
76 // databaseConnect(userName, password, port, dbName, projectID, jsonOutputFile, host);
77 int status = databaseConnect(userName, password, port, dbName, projectID, jsonOutputFile, host);
78 return status;
79 }
80
81 public static void main(String... args) {
82 int exitCode = new CommandLine(new sqlCli()).execute(args);
83 System.exit(exitCode);
84 }
85
86
87 private static int databaseConnect(String user, String pass, int port, String dbName,
88 String projectID, String fileName, String host){
89 Connection conn;
90 Statement stmt;
91 //return status for code to send back to commandLine.execute
92 int returnStatus = 0;
93 // String dbUrl = "jdbc:mysql://localhost:" + port +"/"+ dbName;
94
95 //TODO: are we changing / putting the type of database into a variable too?
96 String dbUrl = "jdbc:mysql://" + host + ":" + port +"/"+ dbName;
97
98 //originally in the try ()
99 // FileWriter file = new FileWriter("tippleData.json")
100 System.out.println("Saving output to:");
101 System.out.println(" " + fileName);
102
103 try (FileWriter file = new FileWriter(fileName)){
104 //register the jdbc driver
105 Class.forName("com.mysql.cj.jdbc.Driver");
106 //opening the connection
107 System.out.println("Connecting to database:");
108 System.out.println(" " + dbUrl);
109
110 conn = DriverManager.getConnection(dbUrl, user, pass);
111
112 //create and execute query
113 stmt = conn.createStatement();
114 //remember to put in the projectId parameter instead of hardcoding it
115
116 /*
117 if we get up to the point where we allow boundary setting, i.e user specifies
118 between x and y number of records
119 could use an if statement to check
120 if the paramter exists or not, if it does then run a statement with those x and y
121 if not, then run a different statement without them
122 */
123
124 String sql = "SELECT name, id, typeId, created from td_ContentItem where projectId="+projectID;
125/*
126 String sql = "select td_Document.id, td_Document.content " +
127 "from td_Document, td_ContentItem, td_ContentItem_Document " +
128 "where td_ContentItem.projectId=" + projectID + " and td_ContentItem.id =
129 td_ContentItem_Document.ContentItemId " +
130 "and td_ContentItem_Document.documentId = td_Document.id;";
131*/
132 ResultSet myResult = stmt.executeQuery(sql);
133 ResultSetMetaData resultMetaData = myResult.getMetaData();
134
135 int dbColumn = resultMetaData.getColumnCount();
136 System.out.println(" Number of columns in table retrieved: " + dbColumn);
137
138 //create gson object and have the file write the opening bracket for valid json
139 Gson myGSon = new Gson();
140 file.write("[");
141
142 while(myResult.next()){
143 //string/object as key/value pair
144 HashMap<String, Object> dbRow = new HashMap<String, Object>(dbColumn);
145
146 for(int i = 1; i <= dbColumn; i++){
147 /*
148 doing checking this way could mean we have to have a case
149 for every data type,
150 if a data type changes in the database that's probably fine, but
151 if a new data type is sent in, we'll have update the statements
152 */
153 /*
154 Without this kind of check though, the output would throw a pretty nasty
155 warning about illegal reflective access. Though it would still print the
156 date out fine. The warning:
157
158 WARNING: An illegal reflective access operation has occurred
159 WARNING: Illegal reflective access by com.google.gson.internal.bind.ReflectiveTypeAdapterFactory (file:/home/su41/.gradle/caches/modules-2/files-2.1/com.google.code.gson/gson/2.7/751f548c85fa49f330cecbb1875893f971b33c4e/gson-2.7.jar) to field java.time.LocalDateTime.date
160 WARNING: Please consider reporting this to the maintainers of com.google.gson.internal.bind.ReflectiveTypeAdapterFactory
161 WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
162 WARNING: All illegal access operations will be denied in a future release
163 */
164 if(resultMetaData.getColumnTypeName(i).equals("DATETIME")){
165 dbRow.put(resultMetaData.getColumnName(i), myResult.getDate(i));
166 }
167 else{
168 dbRow.put(resultMetaData.getColumnName(i), myResult.getObject(i));
169 }
170 }
171 String dbRowAsJson = myGSon.toJson(dbRow);
172
173 //printing statements for checking output
174 // System.out.println("As normal: " + dbRow);
175 // System.out.println("====");
176 //System.out.println("As JSON: " + anObject);
177
178 //saving to json file
179
180 file.write(dbRowAsJson);
181
182 //Adding commas between each row that we write to our file, as we need it to be valid json
183 if(!myResult.isLast()){
184 file.write(",");
185 }
186 }
187 //write the closing bracket, and flush the writer
188 file.write("]");
189 file.flush();
190 file.close();
191 //System.out.println(myList);
192 System.out.println("Closing connection...");
193 myResult.close();
194 stmt.close();
195 conn.close();
196 System.out.println("Connection closed");
197 }
198 catch(SQLException sqlError){
199 // looking at the sql error code is good for debugging.
200 // can ref: https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-error-sqlstates.html
201 // to see what they're for
202
203 // System.out.println("MySQL error code: " + sqlError.getErrorCode());
204
205
206 //prints out the error message from sql, then check to see which error code
207 // came back and what the code matches.
208 // if it's access denied, usually something to do with username, password or db name
209 System.out.println(sqlError.getMessage());
210
211 if(sqlError.getErrorCode() == MysqlErrorNumbers.ER_ACCESS_DENIED_ERROR){
212 System.out.println("Error with database credentials. Double check your: ");
213 System.out.println(" -'Username'");
214 System.out.println(" -'Password' ");
215 }
216
217 if(sqlError.getErrorCode() == MysqlErrorNumbers.ER_DBACCESS_DENIED_ERROR){
218 System.out.println("Error with database credentials. Double check your: ");
219 System.out.println(" -'Database name' ");
220 }
221 returnStatus = 1;
222
223 }
224 catch(Exception e){
225 //catch for class.name
226 e.printStackTrace();
227 //print out wrong username or password instead of the stack trace?
228 System.out.println("encountered error");
229 returnStatus = 2;
230 }
231 return returnStatus;
232 }
233}
Note: See TracBrowser for help on using the repository browser.