1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.sourceforge.addam;
20
21
22 import java.io.*;
23 import java.lang.reflect.Method;
24 import java.net.URL;
25 import java.net.URLClassLoader;
26 import java.sql.Connection;
27 import java.sql.Driver;
28 import java.sql.SQLException;
29 import java.util.*;
30
31 import net.sourceforge.addam.ddlrun.custom.IDSCompletedScriptRetriever;
32 import net.sourceforge.addam.ddlrun.custom.IDSRunLogger;
33 import net.sourceforge.addam.ddlrun.custom.IDSStartFolderRetriever;
34 import net.sourceforge.addam.ddlrun.grammars.ScriptGrammar;
35 import net.sourceforge.addam.ddlrun.grammars.ScriptGrammarManager;
36 import net.sourceforge.addam.ddlrun.runners.DeploymentRunner;
37 import net.sourceforge.addam.ddlrun.runners.DeploymentRunnerFactory;
38 import net.sourceforge.addam.ddlrun.utils.ClassLoaderReaderFactory;
39 import net.sourceforge.addam.ddlrun.utils.ResourceReaderFactory;
40 import net.sourceforge.addam.ddlrun.utils.RunLogger;
41
42 /**
43 * this class is intended to be bundled as the main for a jar file that includes
44 * the scripts necessary to run the upgrade
45 */
46 public class Main {
47
48 private static final String separator = "/";
49
50
51 private static final Package PKG = Main.class.getPackage();
52 private static final String VERSION = PKG.getSpecificationTitle() + " " + PKG.getSpecificationVersion() + " (" + PKG.getImplementationVersion() + ")";
53 private static final String URLPREFIX = "jar:file:/";
54 private static final String JAR_FILE_NAME = getJarFileName();
55 private static final String JAR_FILE_DIR = getJarFileDir();
56
57 private Main() {
58 }
59
60 public static void main(String args[]) {
61
62 String configFileName = JAR_FILE_NAME.replace(".jar",".conf");
63
64 if (args.length < 1 || args.length > 2) {
65 usage(configFileName);
66 return;
67 }
68
69 if (args.length == 2) {
70 configFileName = args[1];
71 }
72
73 Map<String,String> conf;
74 try {
75 conf = loadConfig(configFileName);
76 } catch (IOException e) {
77 System.err.println("unable to load file " + configFileName);
78 e.printStackTrace();
79 return;
80 }
81
82 String url = getConf(conf,"url");
83 String username = getConf(conf,"username");
84 String password = getConf(conf,"password");
85 String driverjar = getConf(conf,"driverjar");
86 String driverName = getConf(conf,"driver");
87 ScriptGrammar grammar;
88 Driver driver;
89
90 try {
91 ClassPathHacker.addFile(driverjar);
92 Class driverClass = Class.forName(driverName);
93 driver = (Driver) driverClass.newInstance();
94 } catch (ClassNotFoundException e) {
95 throw new RuntimeException("unknown driver class " + driverName + "\n" +
96 "make sure to place the driver .jar file in the same directory as the script jar file");
97 } catch (IllegalAccessException e) {
98 throw new RuntimeException("can't instantiate driver " + driverName, e);
99 } catch (InstantiationException e) {
100 throw new RuntimeException("can't instantiate driver " + driverName, e);
101 } catch (IOException e) {
102 throw new RuntimeException("can't instantiate driver " + driverName, e);
103 }
104
105 String type;
106 if ("-install".equals(args[0])) {
107 type = "install";
108 } else if ("-upgrade".equals(args[0])) {
109 type = "upgrade";
110 } else if ("-version".equals(args[0])) {
111 System.out.println(VERSION);
112 return;
113 } else {
114 usage(configFileName);
115 return;
116 }
117
118
119 String script = type + ".drv";
120 DeploymentRunner runner;
121 Connection connection = null;
122 try {
123 System.out.println("connecting to " + url);
124 Properties props = new Properties();
125 props.put("user", username);
126 props.put("password", password);
127 connection = driver.connect(url, props);
128
129 grammar = new ScriptGrammarManager().getGrammar(connection);
130 if (grammar == null) {
131 throw new RuntimeException("unsupported database vendor");
132 }
133 String resourcePath = "database" + separator + type + separator + grammar.name();
134 ResourceReaderFactory factory = new ClassLoaderReaderFactory(resourcePath);
135
136 if ("install".equals(type)) {
137 runner = DeploymentRunnerFactory.getInstance().getInstallRunner(factory,
138 connection,
139 grammar);
140 } else if ("upgrade".equals(type)) {
141 runner = DeploymentRunnerFactory.getInstance().getUpgradeRunner(factory,
142 connection,
143 grammar,
144 new IDSStartFolderRetriever(connection),
145 new IDSCompletedScriptRetriever(connection));
146 runner.addRunLogger(new IDSRunLogger(connection, VERSION));
147 } else {
148 throw new RuntimeException("action must be install or upgrade");
149 }
150 runner.addRunLogger(new RunLogger() {
151 int count = 0;
152 public void logRunScript(String script, long time) throws Exception {
153 System.out.println("executed " + script + " (" + time + "ms)");
154 }
155
156 public void logRunComplete(String group, long time) throws Exception {
157 System.out.println("completed execution of available scripts in " + group + " (" + time + "ms)");
158 }
159
160 public void logRunFailure(String group, String script, Exception e) throws Exception {
161 System.out.println(group + separator + script + " failed!");
162 }
163 });
164 runner.run(script);
165 } catch (Exception e) {
166 System.err.println(e.getMessage());
167 e.printStackTrace(System.err);
168 System.exit(1);
169 } finally {
170 try {
171 connection.close();
172 } catch (SQLException e) {
173 e.printStackTrace();
174 }
175 }
176 }
177
178 private static String getConf(Map<String,String> map, String key) {
179 String value = map.get(key);
180 if (value == null || value.length()==0) {
181 System.err.println("missing config entry for " + key);
182 System.exit(-1);
183 }
184 return value;
185 }
186
187 private static Map<String,String> loadConfig(String configFileName) throws IOException {
188 Properties props = new Properties();
189 File file = new File(configFileName);
190 if (!file.exists()) {
191 file = new File(JAR_FILE_DIR,configFileName);
192 }
193 FileInputStream fis = new FileInputStream(file);
194 props.load(fis);
195
196 Map<String,String> config = new HashMap<String,String>();
197 for (Map.Entry entry : props.entrySet()) {
198 config.put(entry.getKey().toString(),entry.getValue().toString());
199 }
200
201 String password = props.getProperty("password");
202 if (password != null && password.length()>0) {
203 props.setProperty("password","");
204 System.out.println("password stripped from " + configFileName + " for security purposes");
205 FileOutputStream fos = new FileOutputStream(file);
206 props.store(fos,"updated " + new Date() + " by " + JAR_FILE_NAME);
207 }
208 return config;
209 }
210
211 private static void usage(String configFileName) {
212 System.err.printf("usage " + JAR_FILE_NAME + " -version | -install | -upgrade [config file]\n");
213 System.err.println();
214 System.err.println("if config file is not specified, \"" + configFileName + "\" will be used");
215 System.err.println("config file must contain elements from the following example:");
216 System.err.println(" url = jdbc:oracle:thin:@host:1521:sid");
217 System.err.println(" driver = oracle.jdbc.driver.OracleDriver");
218 System.err.println(" driverjar = ojdbc14.jar");
219 System.err.println(" username = " + System.getProperty("user.name"));
220 System.err.println(" password = <password>");
221 }
222
223 private static String getJarFileName() {
224 String jarURL = ClassLoader.getSystemResource("net/sourceforge/addam/Main.class").toString();
225 int i = jarURL.indexOf('!');
226 if (i > 0) jarURL = jarURL.substring(0, i);
227 i = jarURL.lastIndexOf('/');
228 if (i > 0 && jarURL.length() > 1) jarURL = jarURL.substring(i + 1);
229 return jarURL;
230 }
231
232 private static String getJarFileDir() {
233 String jarURL = ClassLoader.getSystemResource("net/sourceforge/addam/Main.class").toString();
234 int i = jarURL.indexOf('!');
235 if (i > 0) jarURL = jarURL.substring(0, i);
236 if (jarURL.startsWith(URLPREFIX) && jarURL.length() > URLPREFIX.length()) {
237 jarURL = jarURL.substring(URLPREFIX.length());
238 }
239 i = jarURL.lastIndexOf('/');
240 if (i > 0) jarURL = jarURL.substring(0,i);
241
242 return jarURL;
243 }
244
245 public static class ClassPathHacker {
246
247 public static void addFile(String fileName) throws IOException {
248 File file = new File(fileName);
249
250 if (!file.exists() && !file.isAbsolute()) {
251 file = new File(JAR_FILE_DIR,fileName);
252 }
253
254 if (!file.exists()) {
255 throw new FileNotFoundException(fileName);
256 }
257
258 URLClassLoader classloader = (URLClassLoader)ClassLoader.getSystemClassLoader();
259 try {
260 Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
261 method.setAccessible(true);
262 method.invoke(classloader, file.toURL());
263 } catch (Throwable t) {
264 t.printStackTrace();
265 throw new IOException("Error, could not add URL to system classloader");
266 }
267 }
268 }
269 }