1 16 package scriptella.tools.launcher; 17 18 import scriptella.configuration.ConfigurationEl; 19 import scriptella.configuration.ConfigurationFactory; 20 import scriptella.execution.EtlExecutor; 21 import scriptella.execution.EtlExecutorException; 22 import scriptella.execution.ExecutionStatistics; 23 import scriptella.execution.JmxEtlManager; 24 import scriptella.interactive.ConsoleProgressIndicator; 25 import scriptella.interactive.LoggingConfigurer; 26 import scriptella.interactive.ProgressIndicator; 27 import scriptella.tools.template.TemplateManager; 28 import scriptella.util.BugReport; 29 import scriptella.util.CollectionUtils; 30 import scriptella.util.IOUtils; 31 import scriptella.util.StringUtils; 32 33 import java.io.File ; 34 import java.io.FileNotFoundException ; 35 import java.io.PrintStream ; 36 import java.net.MalformedURLException ; 37 import java.text.MessageFormat ; 38 import java.util.ArrayList ; 39 import java.util.Date ; 40 import java.util.List ; 41 import java.util.Map ; 42 import java.util.logging.ConsoleHandler ; 43 import java.util.logging.Formatter ; 44 import java.util.logging.Level ; 45 import java.util.logging.LogRecord ; 46 import java.util.logging.Logger ; 47 48 49 55 public class EtlLauncher { 56 private static final Logger LOG = Logger.getLogger(EtlLauncher.class.getName()); 57 private static final PrintStream out = System.out; 58 private static final PrintStream err = System.err; 59 60 63 public enum ErrorCode { 64 OK(0), FAILED(1), FILE_NOT_FOUND(2), UNRECOGNIZED_OPTION(3); 65 66 ErrorCode(int code) { 67 errorCode = code; 68 } 69 70 private int errorCode; 71 72 public int getErrorCode() { 73 return errorCode; 74 } 75 } 76 77 public static final Formatter STD_FORMATTER = new Formatter () { 78 private final MessageFormat f = new MessageFormat ("{0,date} {0,time} <{1}> {2}"); 79 private final Object args[] = new Object [3]; private final StringBuffer sb = new StringBuffer (); 81 private final Date d = new Date (); 82 83 public synchronized String format(final LogRecord record) { 84 d.setTime(record.getMillis()); 85 args[0] = d; 86 args[1] = record.getLevel().getLocalizedName(); 87 args[2] = record.getMessage(); 88 89 f.format(args, sb, null); 90 final Throwable err = record.getThrown(); 91 sb.append('\n'); 92 if (err != null) { 93 sb.append(err.getMessage()); 94 sb.append('\n'); 95 } 96 final String s = sb.toString(); 97 sb.setLength(0); 98 return s; 99 } 100 }; 101 102 private EtlExecutor exec = new EtlExecutor(); 103 private ConfigurationFactory factory = new ConfigurationFactory(); 104 private ProgressIndicator indicator; 105 private Map <String ,?> properties; 106 public static final String DEFAULT_FILE_NAME = "etl.xml"; 107 108 public EtlLauncher() { 109 exec.setJmxEnabled(true); } 111 112 118 ErrorCode launch(String [] args) { 119 ConsoleHandler h = new ConsoleHandler (); 120 121 h.setFormatter(STD_FORMATTER); 122 h.setLevel(Level.INFO); 123 boolean failed = false; 124 List <File > files = new ArrayList <File >(); 125 ConsoleProgressIndicator indicator = new ConsoleProgressIndicator("Execution Progress"); 126 127 try { 128 for (String arg : args) { 129 if (arg.startsWith("-h")) { 130 printUsage(); 131 return ErrorCode.OK; 132 } 133 if (arg.startsWith("-d")) { 134 h.setLevel(Level.FINE); 135 continue; 136 } 137 if (arg.startsWith("-q")) { 138 h.setLevel(Level.WARNING); 139 continue; 140 } 141 if (arg.startsWith("-v")) { 142 printVersion(); 143 return ErrorCode.OK; 144 } 145 if (arg.startsWith("-t")) { 146 template(); 147 return ErrorCode.OK; 148 } 149 if (arg.startsWith("-")) { 150 err.println("Unrecognized option "+arg); 151 return ErrorCode.UNRECOGNIZED_OPTION; 152 } 153 if (!arg.startsWith("-")) { 154 files.add(resolveFile(null, arg)); 155 } 156 } 157 158 159 if (files.isEmpty()) { files.add(resolveFile(null, null)); 161 } 162 } catch (FileNotFoundException e) { 163 err.println(e.getMessage()); 164 return ErrorCode.FILE_NOT_FOUND; 165 } 166 167 if (indicator != null) { 168 setProgressIndicator(indicator); 169 } 170 171 LoggingConfigurer.configure(h); 172 if (properties == null) { 173 setProperties(CollectionUtils.asMap(System.getProperties())); 174 } 175 for (File file : files) { 176 try { 177 execute(file); 178 } catch (Exception e) { 179 failed = true; 180 LOG.log(Level.SEVERE, 181 "Script " + file + " execution failed.", e); 182 if (BugReport.isPossibleBug(e)) { 183 LOG.log(Level.SEVERE, new BugReport(e).toString()); 184 } else if (h.getLevel().intValue() < Level.INFO.intValue()) { 185 err.println("---------------Debug Stack Trace-----------------"); 187 Throwable t = e.getCause() == null ? e : e.getCause(); 188 t.printStackTrace(); 189 } 190 } 191 } 192 LoggingConfigurer.remove(h); 193 194 return failed?ErrorCode.FAILED:ErrorCode.OK; 195 } 196 197 protected void printVersion() { 198 Package p = getClass().getPackage(); 199 if (p != null && p.getSpecificationTitle() != null && p.getImplementationVersion() != null) { 200 out.println(p.getSpecificationTitle() + " Version " + p.getImplementationVersion()); 201 } else { 202 out.println("Scriptella version information unavailable"); 203 } 204 } 205 206 protected void printUsage() { 207 out.println("scriptella [-options] [<file 1> ... <file N>]"); 208 out.println("Options:"); 209 out.println(" -help, -h display help "); 210 out.println(" -debug, -d print debugging information"); 211 out.println(" -quiet, -q be extra quiet"); 212 out.println(" -version, -v print version"); 213 out.println(" -template, -t creates an etl.xml template file in the current directory"); 214 } 215 216 protected void template() { 217 try { 218 new TemplateManager().create(); 219 } catch (Exception e) { 220 err.println(e.getMessage()); 221 } 222 } 223 224 229 public void setProperties(final Map <String ,?> props) { 230 properties=props; 231 } 232 233 public void setProgressIndicator(final ProgressIndicator indicator) { 234 this.indicator = indicator; 235 } 236 237 public void execute(final File file) 238 throws EtlExecutorException { 239 try { 240 factory.setResourceURL(IOUtils.toUrl(file)); 241 } catch (MalformedURLException e) { 242 throw new IllegalArgumentException ("Wrong file path " + 243 file.getPath(), e); 244 } 245 246 factory.setExternalProperties(properties); 247 final ConfigurationEl c = factory.createConfiguration(); 248 249 exec.setConfiguration(c); 250 ExecutionStatistics st = exec.execute(indicator); 251 if (LOG.isLoggable(Level.INFO)) { 252 LOG.info("Execution statistics:\n" + st.toString()); 253 LOG.info("Successfully executed ETL file " + file); 254 } 255 } 256 257 267 public File resolveFile(File dir, String name) throws FileNotFoundException { 268 File f; 269 if (StringUtils.isEmpty(name)) { 270 f = new File (dir, DEFAULT_FILE_NAME); 271 } else { 272 f = new File (dir, name); 273 if (!isFile(f) && name.indexOf('.') < 0) { f = new File (dir, name + '.' + DEFAULT_FILE_NAME); 275 } 276 } 277 if (!isFile(f)) { 278 throw new FileNotFoundException ("ETL file " + f + " was not found."); 279 } 280 281 return f.getAbsoluteFile(); 282 } 283 284 287 protected boolean isFile(File file) { 288 return file.isFile(); 289 } 290 291 public static void main(final String args[]) { 292 EtlLauncher launcher=new EtlLauncher(); 293 System.exit(launcher.launch(args).getErrorCode()); 294 } 295 296 299 private static class EtlShutdownHook extends Thread { 300 private static final EtlShutdownHook INSTANCE = new EtlShutdownHook(); 301 private EtlShutdownHook() { 302 setName("ETL Cancellation Thread"); 303 } 304 305 public void run() { 306 if (!JmxEtlManager.findEtlMBeans().isEmpty()) { 308 System.out.println("Cancelling ETL tasks and rolling back changes..."); 309 } 310 int i = JmxEtlManager.cancelAll(); 312 if (i>1) { 313 System.out.println(i+" ETL tasks cancelled"); 314 } else if (i==1) { 315 System.out.println("ETL cancelled"); 316 } 317 } 318 } 319 320 static { 321 try { 324 Runtime.getRuntime().addShutdownHook(EtlShutdownHook.INSTANCE); 325 } catch (Exception e) { 326 LOG.log(Level.WARNING, "Unable to add shutdown hook. ETL will not be rolled back on abnormal termination.", e); 327 } 328 } 329 330 331 } 332 | Popular Tags |