KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > scriptella > tools > launcher > EtlLauncher


1 /*
2  * Copyright 2006-2007 The Scriptella Project Team.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

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 JavaDoc;
34 import java.io.FileNotFoundException JavaDoc;
35 import java.io.PrintStream JavaDoc;
36 import java.net.MalformedURLException JavaDoc;
37 import java.text.MessageFormat JavaDoc;
38 import java.util.ArrayList JavaDoc;
39 import java.util.Date JavaDoc;
40 import java.util.List JavaDoc;
41 import java.util.Map JavaDoc;
42 import java.util.logging.ConsoleHandler JavaDoc;
43 import java.util.logging.Formatter JavaDoc;
44 import java.util.logging.Level JavaDoc;
45 import java.util.logging.LogRecord JavaDoc;
46 import java.util.logging.Logger JavaDoc;
47
48
49 /**
50  * Command line launcher.
51  *
52  * @author Fyodor Kupolov
53  * @version 1.0
54  */

55 public class EtlLauncher {
56     private static final Logger JavaDoc LOG = Logger.getLogger(EtlLauncher.class.getName());
57     private static final PrintStream JavaDoc out = System.out;
58     private static final PrintStream JavaDoc err = System.err;
59
60     /**
61      * Error codes returned by the launcher.
62      */

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 JavaDoc STD_FORMATTER = new Formatter JavaDoc() {
78         private final MessageFormat JavaDoc f = new MessageFormat JavaDoc("{0,date} {0,time} <{1}> {2}");
79         private final Object JavaDoc args[] = new Object JavaDoc[3]; //arguments for formatter
80
private final StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
81         private final Date JavaDoc d = new Date JavaDoc();
82
83         public synchronized String JavaDoc format(final LogRecord JavaDoc 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 JavaDoc err = record.getThrown();
91             sb.append('\n');
92             if (err != null) {
93                 sb.append(err.getMessage());
94                 sb.append('\n');
95             }
96             final String JavaDoc 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 JavaDoc<String JavaDoc,?> properties;
106     public static final String JavaDoc DEFAULT_FILE_NAME = "etl.xml";
107
108     public EtlLauncher() {
109         exec.setJmxEnabled(true); //JMX monitoring is always enabled when launcher is used
110
}
111
112     /**
113      * Launches ETL script using command line arguments.
114      * @param args command line arguments.
115      * @return exit error code.
116      * @see System#exit(int)
117      */

118     ErrorCode launch(String JavaDoc[] args) {
119         ConsoleHandler JavaDoc h = new ConsoleHandler JavaDoc();
120
121         h.setFormatter(STD_FORMATTER);
122         h.setLevel(Level.INFO);
123         boolean failed = false;
124         List JavaDoc<File JavaDoc> files = new ArrayList JavaDoc<File JavaDoc>();
125         ConsoleProgressIndicator indicator = new ConsoleProgressIndicator("Execution Progress");
126
127         try {
128             for (String JavaDoc 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()) { //adding default name if no files specified
160
files.add(resolveFile(null, null));
161             }
162         } catch (FileNotFoundException JavaDoc 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 JavaDoc file : files) {
176             try {
177                 execute(file);
178             } catch (Exception JavaDoc 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                     //Print stack trace of exception in debug mode
186
err.println("---------------Debug Stack Trace-----------------");
187                     Throwable JavaDoc 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 JavaDoc 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 JavaDoc e) {
220             err.println(e.getMessage());
221         }
222     }
223
224     /**
225      * Sets additional properties available for ETL.
226      * <p>By default {@link System#getProperties()} is used.
227      * @param props properties map.
228      */

229     public void setProperties(final Map JavaDoc<String JavaDoc,?> 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 JavaDoc file)
238             throws EtlExecutorException {
239         try {
240             factory.setResourceURL(IOUtils.toUrl(file));
241         } catch (MalformedURLException JavaDoc e) {
242             throw new IllegalArgumentException JavaDoc("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     /**
258      * Resolves ETL file using the following rule:
259      * if specified file exists - it is returned, otherwise if file has no extension
260      * <code>name</code>+&quot;.etl.xml&quot; file is checked for presence and returned.
261      *
262      * @param dir parent directory, may be null.
263      * @param name file name, may be null in this case default name is used.
264      * @return resolved ETL file.
265      * @throws FileNotFoundException if ETL file cannot be found.
266      */

267     public File JavaDoc resolveFile(File JavaDoc dir, String JavaDoc name) throws FileNotFoundException JavaDoc {
268         File JavaDoc f;
269         if (StringUtils.isEmpty(name)) {
270             f = new File JavaDoc(dir, DEFAULT_FILE_NAME);
271         } else {
272             f = new File JavaDoc(dir, name);
273             if (!isFile(f) && name.indexOf('.') < 0) { //not a file and no extension
274
f = new File JavaDoc(dir, name + '.' + DEFAULT_FILE_NAME);
275             }
276         }
277         if (!isFile(f)) {
278             throw new FileNotFoundException JavaDoc("ETL file " + f + " was not found.");
279         }
280
281         return f.getAbsoluteFile();
282     }
283
284     /**
285      * Overridable for testing.
286      */

287     protected boolean isFile(File JavaDoc file) {
288         return file.isFile();
289     }
290
291     public static void main(final String JavaDoc args[]) {
292         EtlLauncher launcher=new EtlLauncher();
293         System.exit(launcher.launch(args).getErrorCode());
294     }
295
296     /**
297      * Shutdown hook for ETL cancellation.
298      */

299     private static class EtlShutdownHook extends Thread JavaDoc {
300         private static final EtlShutdownHook INSTANCE = new EtlShutdownHook();
301         private EtlShutdownHook() {
302             setName("ETL Cancellation Thread");
303         }
304
305         public void run() {
306             //if any mbean present - inform user about cancellation
307
if (!JmxEtlManager.findEtlMBeans().isEmpty()) {
308                 System.out.println("Cancelling ETL tasks and rolling back changes...");
309             }
310             //Cancel all ETL task, the findEtlMBeans result may be stale
311
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         //Register a system shutdown hook which cancels all
322
//in-progress ETL tasks on VM exit.
323
try {
324             Runtime.getRuntime().addShutdownHook(EtlShutdownHook.INSTANCE);
325         } catch (Exception JavaDoc 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