1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.efaps.update.version;
22
23 import groovy.lang.Binding;
24 import groovy.lang.GroovyShell;
25 import groovy.lang.Script;
26
27 import java.io.IOException;
28 import java.io.InputStreamReader;
29 import java.io.Reader;
30 import java.io.StringReader;
31 import java.net.MalformedURLException;
32 import java.net.URL;
33 import java.util.ArrayList;
34 import java.util.HashSet;
35 import java.util.List;
36 import java.util.Set;
37
38 import org.apache.commons.digester3.annotations.rules.CallMethod;
39 import org.apache.commons.digester3.annotations.rules.CallParam;
40 import org.apache.commons.digester3.annotations.rules.ObjectCreate;
41 import org.apache.commons.digester3.annotations.rules.SetProperty;
42 import org.apache.commons.lang3.builder.ToStringBuilder;
43 import org.efaps.admin.program.esjp.EFapsClassLoader;
44 import org.efaps.db.Context;
45 import org.efaps.update.Install;
46 import org.efaps.update.Profile;
47 import org.efaps.update.UpdateLifecycle;
48 import org.efaps.update.util.InstallationException;
49 import org.efaps.util.EFapsException;
50 import org.mozilla.javascript.ImporterTopLevel;
51 import org.mozilla.javascript.Scriptable;
52 import org.mozilla.javascript.ScriptableObject;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56
57
58
59
60
61
62
63 @ObjectCreate(pattern = "install/version")
64 public class ApplicationVersion
65 implements Comparable<ApplicationVersion>
66 {
67
68
69
70 private static final Logger LOG = LoggerFactory.getLogger(ApplicationVersion.class);
71
72
73
74
75
76
77
78 @SetProperty(pattern = "install/version", attributeName = "number")
79 private Long number = Long.valueOf(0);
80
81
82
83
84
85
86
87 @SetProperty(pattern = "install/version", attributeName = "compile")
88 private boolean compile = false;
89
90
91
92
93
94
95
96
97 @SetProperty(pattern = "install/version", attributeName = "login")
98 private boolean loginNeeded = true;
99
100
101
102
103
104
105
106
107 @SetProperty(pattern = "install/version", attributeName = "reloadCache")
108 private boolean reloadCacheNeeded = true;
109
110
111
112
113
114
115 private final List<AbstractScript> scripts = new ArrayList<AbstractScript>();
116
117
118
119
120
121
122
123 private final StringBuilder description = new StringBuilder();
124
125
126
127
128
129
130 private final Set<UpdateLifecycle> ignoredSteps = new HashSet<UpdateLifecycle>();
131
132
133
134
135 private Application application;
136
137
138
139
140
141
142
143
144
145
146
147
148
149 public void install(final Install _install,
150 final long _latestVersionNumber,
151 final Set<Profile> _profiles,
152 final String _userName,
153 final String _password)
154 throws InstallationException
155 {
156
157 if (this.reloadCacheNeeded) {
158 this.application.reloadCache();
159 }
160 try {
161
162 if (this.loginNeeded) {
163 Context.begin(_userName);
164 } else {
165 Context.begin();
166 }
167
168 _install.install(this.number, _latestVersionNumber, _profiles, this.ignoredSteps);
169
170
171 Context.commit();
172
173
174 for (final AbstractScript script : this.scripts) {
175 script.execute(_userName, _password);
176 }
177
178
179 if (this.compile) {
180 this.application.compileAll(_userName, true);
181 }
182 } catch (final EFapsException e) {
183 throw new InstallationException("error in Context", e);
184 }
185 }
186
187
188
189
190
191
192
193
194
195 @CallMethod(pattern = "install/version/script")
196 public void addScript(@CallParam(pattern = "install/version/script") final String _code,
197 @CallParam(pattern = "install/version/script", attributeName = "type") final String _type,
198 @CallParam(pattern = "install/version/script", attributeName = "name") final String _name,
199 @CallParam(pattern = "install/version/script", attributeName = "function")
200 final String _function)
201 {
202 AbstractScript script = null;
203 if ("rhino".equalsIgnoreCase(_type)) {
204 script = new RhinoScript(_code, _name, _function);
205 } else if ("groovy".equalsIgnoreCase(_type)) {
206 script = new GroovyScript(_code, _name, _function);
207 }
208 if (script != null) {
209 this.scripts.add(script);
210 }
211 }
212
213
214
215
216
217
218
219 @CallMethod(pattern = "install/version/description")
220 public void appendDescription(@CallParam(pattern = "install/version/description") final String _desc)
221 {
222 if (_desc != null) {
223 this.description.append(_desc.trim()).append("\n");
224 }
225 }
226
227
228
229
230 public void setApplication(final Application _appl)
231 {
232 this.application = _appl;
233 }
234
235
236
237
238
239
240
241
242 public String getDescription()
243 {
244 return this.description.toString().trim();
245 }
246
247
248
249
250
251
252
253 @CallMethod(pattern = "install/version/lifecyle/ignore")
254 public void addIgnoredStep(@CallParam(pattern = "install/version/lifecyle/ignore", attributeName = "step")
255 final String _step)
256 {
257 this.ignoredSteps.add(UpdateLifecycle.valueOf(_step.toUpperCase()));
258 }
259
260
261
262
263
264
265
266
267
268
269
270
271
272 public int compareTo(final ApplicationVersion _compareTo)
273 {
274 return new Long(this.number).compareTo(_compareTo.number);
275 }
276
277
278
279
280
281
282
283
284 public void setNumber(final Long _number)
285 {
286 this.number = _number;
287 }
288
289
290
291
292
293
294
295
296 public Long getNumber()
297 {
298 return this.number;
299 }
300
301
302
303
304
305
306
307 public void setCompile(final boolean _compile)
308 {
309 this.compile = _compile;
310 }
311
312
313
314
315
316
317
318
319 public void setLoginNeeded(final boolean _loginNeeded)
320 {
321 this.loginNeeded = _loginNeeded;
322 }
323
324
325
326
327
328
329
330
331
332 public void setReloadCacheNeeded(final boolean _reloadCacheNeeded)
333 {
334 this.reloadCacheNeeded = _reloadCacheNeeded;
335 }
336
337
338
339
340
341
342
343
344
345
346
347
348 protected URL getCompleteRootUrl()
349 throws InstallationException
350 {
351 try {
352 final URL url;
353 if (this.application.getRootPackageName() == null) {
354 url = this.application.getRootUrl();
355 } else {
356 url = new URL(this.application.getRootUrl(), this.application.getRootPackageName());
357 }
358 return url;
359 } catch (final MalformedURLException e) {
360 throw new InstallationException("Root url could not be prepared", e);
361 }
362 }
363
364
365
366
367
368
369 @Override
370 public String toString()
371 {
372 return new ToStringBuilder(this)
373 .append("number", this.number)
374 .toString();
375 }
376
377
378
379
380
381 private abstract class AbstractScript
382 {
383
384
385
386
387 private final String code;
388
389
390
391
392 private final String fileName;
393
394
395
396
397 private final String function;
398
399
400
401
402
403
404
405
406 private AbstractScript(final String _code,
407 final String _fileName,
408 final String _function)
409 {
410 this.code = (_code == null) || ("".equals(_code.trim())) ? null : _code.trim();
411 this.fileName = _fileName;
412 this.function = _function;
413 }
414
415
416
417
418
419
420
421
422 public abstract void execute(final String _userName,
423 final String _password)
424 throws InstallationException;
425
426
427
428
429
430
431 public String getCode()
432 {
433 return this.code;
434 }
435
436
437
438
439
440
441 public String getFileName()
442 {
443 return this.fileName;
444 }
445
446
447
448
449
450
451 public String getFunction()
452 {
453 return this.function;
454 }
455 }
456
457
458
459
460 private final class GroovyScript
461 extends ApplicationVersion.AbstractScript
462 {
463
464
465
466
467
468
469 private GroovyScript(final String _code,
470 final String _fileName,
471 final String _function)
472 {
473 super(_code, _fileName, _function);
474 }
475
476
477
478
479
480
481 @Override
482 public void execute(final String _userName,
483 final String _password)
484 throws InstallationException
485 {
486 boolean commit = false;
487 try {
488 try {
489 Context.begin(_userName);
490 } catch (final EFapsException e) {
491 throw new InstallationException("Context could not be started", e);
492 }
493 final ClassLoader parent = getClass().getClassLoader();
494 final EFapsClassLoader efapsClassLoader = EFapsClassLoader.getOfflineInstance(parent);
495
496 if (getCode() != null) {
497 final Binding binding = new Binding();
498 binding.setVariable("EFAPS_LOGGER", ApplicationVersion.LOG);
499 binding.setVariable("EFAPS_USERNAME", _userName);
500 binding.setVariable("EFAPS_PASSWORD", _userName);
501 binding.setVariable("EFAPS_ROOTURL", getCompleteRootUrl());
502
503 final GroovyShell shell = new GroovyShell(efapsClassLoader, binding);
504 final Script script = shell.parse(getCode());
505 script.run();
506 }
507 try {
508 Context.commit();
509 } catch (final EFapsException e) {
510 throw new InstallationException("Transaction could not be commited", e);
511 }
512 commit = true;
513 } finally {
514 if (!commit) {
515 try {
516 Context.rollback();
517 } catch (final EFapsException e) {
518 throw new InstallationException("Tranaction could not be aborted", e);
519 }
520 }
521 }
522 }
523 }
524
525
526
527
528 private final class RhinoScript
529 extends ApplicationVersion.AbstractScript
530 {
531
532
533
534
535
536
537
538 private RhinoScript(final String _code,
539 final String _fileName,
540 final String _function)
541 {
542 super(_code, _fileName, _function);
543 }
544
545
546
547
548 @Override
549 public void execute(final String _userName,
550 final String _password)
551 throws InstallationException
552 {
553 try {
554
555 final org.mozilla.javascript.Context javaScriptContext = org.mozilla.javascript.Context.enter();
556
557 final Scriptable scope = new ImporterTopLevel(javaScriptContext);
558
559
560 ScriptableObject.putProperty(scope, "javaScriptContext", javaScriptContext);
561
562
563 ScriptableObject.putProperty(scope, "javaScriptScope", scope);
564
565 ScriptableObject.putProperty(scope, "EFAPS_LOGGER",
566 org.mozilla.javascript.Context.javaToJS(ApplicationVersion.LOG, scope));
567 ScriptableObject.putProperty(scope, "EFAPS_USERNAME",
568 org.mozilla.javascript.Context.javaToJS(_userName, scope));
569 ScriptableObject.putProperty(scope, "EFAPS_PASSWORD",
570 org.mozilla.javascript.Context.javaToJS(_userName, scope));
571 ScriptableObject.putProperty(scope,
572 "EFAPS_ROOTURL",
573 org.mozilla.javascript.Context.javaToJS(getCompleteRootUrl(), scope));
574
575
576 if (getFileName() != null) {
577 if (ApplicationVersion.LOG.isInfoEnabled()) {
578 ApplicationVersion.LOG.info("Execute script file '" + getFileName() + "'");
579 }
580 final Reader in = new InputStreamReader(
581 new URL(getCompleteRootUrl(), getFileName()).openStream(), "UTF-8");
582 javaScriptContext.evaluateReader(scope, in, getFileName(), 1, null);
583 in.close();
584 }
585
586
587 if (getCode() != null) {
588 javaScriptContext.evaluateReader(scope, new StringReader(getCode()),
589 "Executing script code of version " + ApplicationVersion.this.number, 1, null);
590 }
591
592
593 if (getFunction() != null) {
594 if (ApplicationVersion.LOG.isInfoEnabled()) {
595 ApplicationVersion.LOG.info("Execute script function '" + getFunction() + "'");
596 }
597 javaScriptContext.evaluateReader(scope, new StringReader(getFunction()), getFunction(), 1, null);
598 }
599 } catch (final IOException e) {
600 throw new InstallationException("IOException in RhinoScript", e);
601 }
602 }
603 }
604 }