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 java.io.File;
24 import java.io.IOException;
25 import java.net.MalformedURLException;
26 import java.net.URL;
27 import java.net.URLClassLoader;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.Comparator;
31 import java.util.Enumeration;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Map.Entry;
37 import java.util.Set;
38 import java.util.TreeSet;
39
40 import org.apache.commons.digester3.Digester;
41 import org.apache.commons.digester3.annotations.FromAnnotationsRuleModule;
42 import org.apache.commons.digester3.annotations.rules.BeanPropertySetter;
43 import org.apache.commons.digester3.annotations.rules.CallMethod;
44 import org.apache.commons.digester3.annotations.rules.CallParam;
45 import org.apache.commons.digester3.annotations.rules.ObjectCreate;
46 import org.apache.commons.digester3.annotations.rules.SetNext;
47 import org.apache.commons.digester3.annotations.rules.SetProperty;
48 import org.apache.commons.digester3.binder.DigesterLoader;
49 import org.apache.commons.lang3.builder.ToStringBuilder;
50 import org.apache.tools.ant.DirectoryScanner;
51 import org.efaps.admin.datamodel.Type;
52 import org.efaps.admin.program.esjp.EFapsClassLoader;
53 import org.efaps.admin.runlevel.RunLevel;
54 import org.efaps.ci.CIAdminCommon;
55 import org.efaps.db.Context;
56 import org.efaps.db.Insert;
57 import org.efaps.db.InstanceQuery;
58 import org.efaps.db.QueryBuilder;
59 import org.efaps.update.FileType;
60 import org.efaps.update.Install;
61 import org.efaps.update.Profile;
62 import org.efaps.update.schema.program.esjp.ESJPCompiler;
63 import org.efaps.update.schema.program.staticsource.AbstractStaticSourceCompiler;
64 import org.efaps.update.util.InstallationException;
65 import org.efaps.util.EFapsException;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
68
69
70
71
72
73 @ObjectCreate(pattern = "install")
74 public final class Application
75 {
76
77
78
79
80 private static final Logger LOG = LoggerFactory.getLogger(Application.class);
81
82
83
84
85 private static final Map<String, String> DEFAULT_TYPE_MAPPING = new HashMap<String, String>();
86 static {
87 Application.DEFAULT_TYPE_MAPPING.put("bpmn2", FileType.BPM.getType());
88 Application.DEFAULT_TYPE_MAPPING.put("css", FileType.CSS.getType());
89 Application.DEFAULT_TYPE_MAPPING.put("java", FileType.JAVA.getType());
90 Application.DEFAULT_TYPE_MAPPING.put("js", FileType.JS.getType());
91 Application.DEFAULT_TYPE_MAPPING.put("jrxml", FileType.JRXML.getType());
92 Application.DEFAULT_TYPE_MAPPING.put("wiki", FileType.WIKI.getType());
93 Application.DEFAULT_TYPE_MAPPING.put("xml", FileType.XML.getType());
94 Application.DEFAULT_TYPE_MAPPING.put("xsl", FileType.XSL.getType());
95 }
96
97
98
99
100
101
102 private static final Set<String> DEFAULT_INCLUDES = new HashSet<String>();
103 static {
104 Application.DEFAULT_INCLUDES.add("**/*.bpmn2");
105 Application.DEFAULT_INCLUDES.add("**/*.css");
106 Application.DEFAULT_INCLUDES.add("**/*.java");
107 Application.DEFAULT_INCLUDES.add("**/*.js");
108 Application.DEFAULT_INCLUDES.add("**/*.jrxml");
109 Application.DEFAULT_INCLUDES.add("**/*.wiki");
110 Application.DEFAULT_INCLUDES.add("**/*.xml");
111 Application.DEFAULT_INCLUDES.add("**/*.xsl");
112 }
113
114
115
116
117
118
119 private static final Set<String> DEFAULT_EXCLUDES = new HashSet<String>();
120 static {
121 Application.DEFAULT_EXCLUDES.add("**/versions.xml");
122 Application.DEFAULT_EXCLUDES.add("**/package-info.java");
123 Application.DEFAULT_EXCLUDES.add("**/.svn/**");
124 }
125
126
127
128
129
130
131 @BeanPropertySetter(pattern = "install/application")
132 private String application = null;
133
134
135
136
137
138
139
140 private final Set<ApplicationVersion> versions = new TreeSet<ApplicationVersion>();
141
142
143
144
145
146
147 private final Install install = new Install();
148
149
150
151
152
153
154 private final List<Long> notStoredVersions = new ArrayList<Long>();
155
156
157
158
159 private Long maxVersion;
160
161
162
163
164
165
166
167 private List<String> classpathElements;
168
169
170
171
172 private final List<Dependency> dependencies = new ArrayList<Dependency>();
173
174
175
176
177
178
179
180
181 private URL rootUrl;
182
183
184
185
186 @SetProperty(pattern = "install/rootPackage", attributeName = "name")
187 private String rootPackageName;
188
189
190
191
192 private Map<String, String> tmpElements = new HashMap<String, String>();
193
194
195
196
197
198
199
200
201 private Application(final URL _rootUrl,
202 final List<String> _classpathElements)
203 {
204 this.rootUrl = _rootUrl;
205 this.classpathElements = _classpathElements;
206 }
207
208
209
210
211 public Application()
212 {
213 }
214
215
216
217
218
219
220
221
222
223
224
225
226 public static Application getApplication(final URL _versionUrl,
227 final URL _rootUrl,
228 final List<String> _classpathElements)
229 throws InstallationException
230 {
231 Application appl = null;
232 try {
233 final DigesterLoader loader = DigesterLoader.newLoader(new FromAnnotationsRuleModule()
234 {
235 @Override
236 protected void configureRules()
237 {
238 bindRulesFrom(Application.class);
239 }
240 });
241 final Digester digester = loader.newDigester();
242 appl = (Application) digester.parse(_versionUrl);
243 appl.rootUrl = _rootUrl;
244 appl.classpathElements = _classpathElements;
245 for (final Entry<String, String> entry : appl.tmpElements.entrySet()) {
246 appl.addURL(new URL(_rootUrl, entry.getKey()), entry.getValue());
247 }
248 appl.tmpElements = null;
249 Collections.sort(appl.dependencies, new Comparator<Dependency>()
250 {
251
252 @Override
253 public int compare(final Dependency _dependency0,
254 final Dependency _dependency1)
255 {
256 return _dependency0.getOrder().compareTo(_dependency1.getOrder());
257 }
258 });
259 for (final ApplicationVersion applVers : appl.getVersions()) {
260 applVers.setApplication(appl);
261 appl.setMaxVersion(applVers.getNumber());
262 }
263
264 } catch (final IOException e) {
265 if (e.getCause() instanceof InstallationException) {
266 throw (InstallationException) e.getCause();
267 } else {
268 throw new InstallationException("Could not open / read version file '" + _versionUrl + "'");
269 }
270
271 } catch (final Exception e) {
272
273 throw new InstallationException("Error while parsing file '" + _versionUrl + "'", e);
274 }
275 return appl;
276 }
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295 public static Application getApplicationFromSource(final File _versionFile,
296 final List<String> _classpathElements,
297 final File _eFapsDir,
298 final File _outputDir,
299 final List<String> _includes,
300 final List<String> _excludes,
301 final Map<String, String> _file2typeMapping)
302 throws InstallationException
303 {
304 final Map<String, String> file2typeMapping = _file2typeMapping == null
305 ? Application.DEFAULT_TYPE_MAPPING
306 : _file2typeMapping;
307 final Application appl;
308 try {
309 appl = Application.getApplication(_versionFile.toURI().toURL(),
310 _eFapsDir.toURI().toURL(),
311 _classpathElements);
312
313 for (final String fileName : Application.getFiles(_eFapsDir, _includes, _excludes)) {
314 final String type = file2typeMapping.get(fileName.substring(fileName.lastIndexOf(".") + 1));
315 appl.addURL(new File(_eFapsDir, fileName).toURI().toURL(), type);
316 }
317 if (_outputDir.exists()) {
318 for (final String fileName : Application.getFiles(_outputDir, _includes, _excludes)) {
319 final String type = file2typeMapping.get(fileName.substring(fileName.lastIndexOf(".") + 1));
320 appl.addURL(new File(_outputDir, fileName).toURI().toURL(), type);
321 }
322 }
323 } catch (final IOException e) {
324 throw new InstallationException("Could not open / read version file " + "'" + _versionFile + "'", e);
325
326 } catch (final Exception e) {
327
328 throw new InstallationException("Read version file '" + _versionFile + "' failed", e);
329 }
330 return appl;
331 }
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347 protected static String[] getFiles(final File _eFapsDir,
348 final List<String> _includes,
349 final List<String> _excludes)
350 {
351 final DirectoryScanner ds = new DirectoryScanner();
352 final String[] included = _includes == null
353 ? Application.DEFAULT_INCLUDES.toArray(new String[Application.DEFAULT_INCLUDES.size()])
354 : _includes.toArray(new String[_includes.size()]);
355 final String[] excluded = _excludes == null
356 ? Application.DEFAULT_EXCLUDES.toArray(new String[Application.DEFAULT_EXCLUDES.size()])
357 : _excludes.toArray(new String[_excludes.size()]);
358 ds.setIncludes(included);
359 ds.setExcludes(excluded);
360 ds.setBasedir(_eFapsDir.toString());
361 ds.setCaseSensitive(true);
362 ds.scan();
363
364 return ds.getIncludedFiles();
365 }
366
367
368
369
370
371
372
373
374
375
376 public static Application getApplicationFromClassPath(final String _application,
377 final List<String> _classpath)
378 throws InstallationException
379 {
380 return Application.getApplicationsFromClassPath(_application, _classpath).get(_application);
381 }
382
383
384
385
386
387
388
389
390
391
392
393 public static Map<String, Application> getApplicationsFromClassPath(final String _application,
394 final List<String> _classpath)
395 throws InstallationException
396 {
397 final Map<String, Application> appls = new HashMap<String, Application>();
398 try {
399 final ClassLoader parent = Application.class.getClassLoader();
400 final List<URL> urls = new ArrayList<>();
401 for (final String pathElement : _classpath) {
402 urls.add(new File(pathElement).toURI().toURL());
403 }
404 final URLClassLoader cl = URLClassLoader.newInstance(urls.toArray(new URL[urls.size()]), parent);
405
406 final Enumeration<URL> urlEnum = cl.getResources("META-INF/efaps/install.xml");
407 while (urlEnum.hasMoreElements()) {
408
409 final URL url = urlEnum.nextElement();
410 final Application appl = Application.getApplication(url, new URL(url, "../../../"), _classpath);
411 appls.put(appl.getApplication(), appl);
412 }
413 } catch (final IOException e) {
414 throw new InstallationException("Could not access the install.xml file "
415 + "(in path META-INF/efaps/ path of each eFaps install jar).", e);
416 }
417 return appls;
418 }
419
420
421
422
423
424
425
426
427
428
429 public static Application getApplicationFromJarFile(final File _jarFile,
430 final List<String> _classpath)
431 throws InstallationException
432 {
433 try {
434 final URL url = new URL("jar", null, 0, _jarFile.toURI().toURL().toString() + "!/");
435 final URL url2 = new URL(url, "/META-INF/efaps/install.xml");
436 return Application.getApplication(url2, new URL(url2, "../../../"), _classpath);
437 } catch (final IOException e) {
438 throw new InstallationException("URL could not be parsed", e);
439 }
440 }
441
442
443
444
445
446
447
448
449
450
451
452
453 public static void compileAll(final String _userName,
454 final List<String> _classpath,
455 final boolean _addRuntimeClassPath)
456 throws InstallationException
457 {
458 new Application((URL) null, _classpath).compileAll(_userName, _addRuntimeClassPath);
459 }
460
461
462
463
464
465
466
467
468
469
470 public void compileAll(final String _userName,
471 final boolean _addRuntimeClassPath)
472 throws InstallationException
473 {
474 if (Application.LOG.isInfoEnabled()) {
475 Application.LOG.info("..Compiling");
476 }
477
478 reloadCache();
479
480 try {
481 Context.begin(_userName);
482 try {
483 new ESJPCompiler(getClassPathElements()).compile(null, _addRuntimeClassPath);
484 } catch (final InstallationException e) {
485 Application.LOG.error(" error during compilation of ESJP.");
486 }
487 AbstractStaticSourceCompiler.compileAll(this.classpathElements);
488 Context.commit();
489 } catch (final EFapsException e) {
490 throw new InstallationException("Compile failed", e);
491 }
492 }
493
494
495
496
497
498
499
500
501
502
503 public void install(final String _userName,
504 final String _password,
505 final Set<Profile> _profiles)
506 throws InstallationException
507 {
508 this.install(_userName, _password, _profiles, null);
509 }
510
511
512
513
514
515
516
517
518
519
520
521 public void install(final String _userName,
522 final String _password,
523 final Set<Profile> _profiles,
524 final Boolean _compile)
525 throws InstallationException
526 {
527 this.install(_userName, _password, _profiles, _compile, true);
528 }
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543 protected void install(final String _userName,
544 final String _password,
545 final Set<Profile> _profiles,
546 final Boolean _compile,
547 final boolean _withDependency)
548 throws InstallationException
549 {
550
551
552 if (_withDependency) {
553 for (final Dependency dependency : this.dependencies) {
554 dependency.resolve();
555 final Application appl = Application.getApplicationFromJarFile(
556 dependency.getJarFile(), this.classpathElements);
557 appl.install(_userName, _password, dependency.getProfiles(), _compile, false);
558 }
559 }
560
561
562 reloadCache();
563
564
565 final Map<String, Integer> latestVersions;
566 try {
567 Context.begin();
568 EFapsClassLoader.getOfflineInstance(getClass().getClassLoader());
569 latestVersions = this.install.getLatestVersions();
570 Context.rollback();
571 } catch (final EFapsException e) {
572 throw new InstallationException("Could not get information about installed versions", e);
573 }
574 final Integer latestVersion = latestVersions.get(this.application);
575
576 Application.LOG.info("Install application '" + this.application + "'");
577
578 for (final ApplicationVersion version : this.versions) {
579 Application.LOG.info("Check version '{}'", version.getNumber());
580 if (_compile != null) {
581 version.setCompile(_compile);
582 }
583 if (latestVersion != null && version.getNumber() < latestVersion) {
584 if (Application.LOG.isInfoEnabled()) {
585 Application.LOG.info("Version " + version.getNumber() + " already installed");
586 }
587 } else {
588 if (Application.LOG.isInfoEnabled()) {
589 Application.LOG.info("Starting installation of version " + version.getNumber());
590 final String desc = version.getDescription();
591 if (!"".equals(desc)) {
592 Application.LOG.info(desc);
593 }
594 }
595 try {
596 version.install(this.install, getLastVersion().getNumber(), _profiles, _userName, _password);
597
598 } catch (final Exception e) {
599
600 throw new InstallationException("Installation failed", e);
601 }
602 storeVersion(_userName, version.getNumber());
603
604 if (Application.LOG.isInfoEnabled()) {
605 Application.LOG.info("Finished installation of version " + version.getNumber());
606 }
607 }
608 }
609
610
611 reloadCache();
612 }
613
614
615
616
617
618
619
620
621
622 public void updateLastVersion(final String _userName,
623 final String _password,
624 final Set<Profile> _profiles)
625 throws Exception
626 {
627
628 reloadCache();
629
630
631 Context.begin();
632 EFapsClassLoader.getOfflineInstance(getClass().getClassLoader());
633 final Map<String, Integer> latestVersions = this.install.getLatestVersions();
634 Context.rollback();
635 final long latestVersion = latestVersions.get(this.application);
636
637 final ApplicationVersion version = getLastVersion();
638 if (version.getNumber() == latestVersion) {
639 Application.LOG.info("Update version '{}' of application '{}' ", version.getNumber(), this.application);
640
641 version.install(this.install, version.getNumber(), _profiles, _userName, _password);
642
643 Application.LOG.info("Finished update of version '{}'", version.getNumber());
644 } else {
645 Application.LOG.error("Version {}' of application '{}' not installed and could not updated!",
646 version.getNumber(), this.application);
647 }
648 }
649
650
651
652
653
654
655
656
657
658
659
660
661 protected void storeVersion(final String _userName,
662 final Long _version)
663 throws InstallationException
664 {
665 try {
666 Context.begin(_userName);
667 final Type versionType = CIAdminCommon.Version.getType();
668 if (versionType != null) {
669
670 for (final Long version : this.notStoredVersions) {
671 final Insert insert = new Insert(versionType);
672 insert.add(CIAdminCommon.Version.Name, this.application);
673 insert.add(CIAdminCommon.Version.Revision, version);
674 insert.execute();
675 }
676 this.notStoredVersions.clear();
677
678 final QueryBuilder queryBldr = new QueryBuilder(CIAdminCommon.Version);
679 queryBldr.addWhereAttrEqValue(CIAdminCommon.Version.Name, this.application);
680 queryBldr.addWhereAttrEqValue(CIAdminCommon.Version.Revision, _version);
681 final InstanceQuery query = queryBldr.getQuery();
682 query.execute();
683 if (!query.next()) {
684
685 final Insert insert = new Insert(CIAdminCommon.Version);
686 insert.add(CIAdminCommon.Version.Name, this.application);
687 insert.add(CIAdminCommon.Version.Revision, _version);
688 insert.execute();
689 }
690 } else {
691
692 this.notStoredVersions.add(_version);
693 }
694 Context.commit();
695 } catch (final EFapsException e) {
696 throw new InstallationException("Update of the version information failed", e);
697 }
698 }
699
700
701
702
703
704 @SetNext
705 public void addDependency(final Dependency _dependency)
706 {
707 this.dependencies.add(_dependency);
708 }
709
710
711
712
713
714
715 protected void reloadCache()
716 throws InstallationException
717 {
718 try {
719 Context.begin();
720 if (RunLevel.isInitialisable()) {
721 RunLevel.init("shell");
722 RunLevel.execute();
723 }
724 Context.rollback();
725 } catch (final EFapsException e) {
726 throw new InstallationException("Reload cache failed", e);
727 }
728 }
729
730
731
732
733
734
735
736 @SetNext
737 public void addVersion(final ApplicationVersion _version)
738 {
739 this.versions.add(_version);
740 }
741
742
743
744
745
746
747 public ApplicationVersion getLastVersion()
748 {
749 return (ApplicationVersion) this.versions.toArray()[this.versions.size() - 1];
750 }
751
752
753
754
755
756
757
758 public void setApplication(final String _application)
759 {
760 this.application = _application;
761 }
762
763
764
765
766
767
768
769
770
771 public void addURL(final URL _url,
772 final String _type)
773 {
774 this.install.addFile(_url, _type);
775 }
776
777
778
779
780
781
782
783
784
785
786
787 @CallMethod(pattern = "install/files/file")
788 public void addClassPathFile(
789 @CallParam(pattern = "install/files/file", attributeName = "name") final String _classPathFile,
790 @CallParam(pattern = "install/files/file", attributeName = "type") final String _type)
791 throws MalformedURLException
792 {
793 this.tmpElements.put(_classPathFile, _type);
794 }
795
796
797
798
799
800
801 public Install getInstall()
802 {
803 return this.install;
804 }
805
806
807
808
809
810
811 public List<Dependency> getDependencies()
812 {
813 return this.dependencies;
814 }
815
816
817
818
819
820
821
822 public String getApplication()
823 {
824 return this.application;
825 }
826
827
828
829
830
831
832
833 public List<String> getClassPathElements()
834 {
835 return this.classpathElements;
836 }
837
838
839
840
841
842
843
844 public URL getRootUrl()
845 {
846 return this.rootUrl;
847 }
848
849
850
851
852
853
854
855 public Set<ApplicationVersion> getVersions()
856 {
857 return this.versions;
858 }
859
860
861
862
863
864
865 public void setMaxVersion(final Long _maxVersion)
866 {
867 this.maxVersion = _maxVersion;
868 }
869
870
871
872
873
874
875 public Long getMaxVersion()
876 {
877 return this.maxVersion;
878 }
879
880
881
882
883
884
885
886 public void setRootPackageName(final String _rootPackageName)
887 {
888 this.rootPackageName = _rootPackageName;
889 }
890
891
892
893
894
895
896 public String getRootPackageName()
897 {
898 return this.rootPackageName;
899 }
900
901
902
903
904
905
906 @Override
907 public String toString()
908 {
909 return new ToStringBuilder(this)
910 .append("application", this.application)
911 .append("dependencies", this.dependencies)
912 .append("versions", this.versions)
913 .append("install", this.install)
914 .toString();
915 }
916 }