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;
22
23 import java.io.IOException;
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Method;
26 import java.net.URL;
27 import java.sql.SQLException;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.Comparator;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Properties;
36 import java.util.Set;
37
38 import org.apache.commons.jexl2.JexlContext;
39 import org.apache.commons.jexl2.MapContext;
40 import org.apache.commons.lang3.builder.ToStringBuilder;
41 import org.efaps.admin.EFapsSystemConfiguration;
42 import org.efaps.admin.KernelSettings;
43 import org.efaps.ci.CIAdminCommon;
44 import org.efaps.db.Context;
45 import org.efaps.db.MultiPrintQuery;
46 import org.efaps.db.QueryBuilder;
47 import org.efaps.update.util.InstallationException;
48 import org.efaps.util.EFapsException;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51 import org.xml.sax.SAXException;
52
53
54
55
56
57
58
59 public class Install
60 {
61
62
63
64 private static final Logger LOG = LoggerFactory.getLogger(Install.class);
65
66
67
68
69
70
71 private final List<InstallFile> files = new ArrayList<InstallFile>();
72
73
74
75
76
77
78
79 private boolean initialised = false;
80
81
82
83
84
85
86
87 private final Map<Class<? extends IUpdate>, List<IUpdate>> cache
88 = new HashMap<Class<? extends IUpdate>, List<IUpdate>>();
89
90
91
92
93 private final boolean evaluateProfiles;
94
95
96
97
98 public Install()
99 {
100 this(false);
101 }
102
103
104
105
106 public Install(final boolean _evaluateProfiles)
107 {
108 this.evaluateProfiles = _evaluateProfiles;
109 }
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 public void install(final Long _number,
130 final Long _latestNumber,
131 final Set<Profile> _profiles,
132 final Set<UpdateLifecycle> _ignoredSteps)
133 throws InstallationException
134 {
135 final boolean bigTrans = Context.getDbType().supportsBigTransactions();
136 final String user;
137 try {
138 user = Context.getThreadContext().getPerson() != null
139 ? Context.getThreadContext().getPerson().getName()
140 : null;
141 } catch (final EFapsException e) {
142 throw new InstallationException("No context in this thread defined!", e);
143 }
144
145
146 initialise();
147
148
149 final JexlContext jexlContext = new MapContext();
150 if (_number != null) {
151 jexlContext.set("version", _number);
152 }
153 if (_latestNumber != null) {
154 jexlContext.set("latest", _latestNumber);
155 }
156
157
158 for (final UpdateLifecycle step : getUpdateLifecycles()) {
159 if (!_ignoredSteps.contains(step)) {
160 if (Install.LOG.isInfoEnabled()) {
161 Install.LOG.info("..Running Lifecycle step " + step);
162 }
163 for (final Map.Entry<Class<? extends IUpdate>, List<IUpdate>> entry : this.cache.entrySet()) {
164 final List<IUpdate> updates = entry.getValue();
165 Collections.sort(updates, new Comparator<IUpdate>()
166 {
167 @Override
168 public int compare(final IUpdate _update0,
169 final IUpdate _update1)
170 {
171 return String.valueOf(_update0.getURL()).compareTo(String.valueOf(_update1.getURL()));
172 }
173 });
174 for (final IUpdate update : updates) {
175 try {
176 update.updateInDB(jexlContext, step,
177 evaluateProfiles(update.getFileApplication(), _profiles));
178 if (!bigTrans) {
179 Context.commit();
180 Context.begin(user);
181 }
182 } catch (final EFapsException e) {
183 throw new InstallationException("Transaction start failed", e);
184 }
185
186 }
187 }
188 } else if (Install.LOG.isInfoEnabled()) {
189 Install.LOG.info("..Skipped Lifecycle step " + step);
190 }
191 }
192 }
193
194
195
196
197
198 private List<UpdateLifecycle> getUpdateLifecycles()
199 {
200 final List<UpdateLifecycle> ret = new ArrayList<UpdateLifecycle>();
201 for (final UpdateLifecycle cycle : UpdateLifecycle.values()) {
202 ret.add(cycle);
203 }
204 Collections.sort(ret, new Comparator<UpdateLifecycle>() {
205
206 @Override
207 public int compare(final UpdateLifecycle _cycle1,
208 final UpdateLifecycle _cycle2)
209 {
210 return _cycle1.getOrder().compareTo(_cycle2.getOrder());
211 }
212 });
213
214 return ret;
215 }
216
217
218
219
220
221
222
223
224
225 public void updateLatest(final Set<Profile> _profiles)
226 throws InstallationException
227 {
228 final boolean bigTrans = Context.getDbType().supportsBigTransactions();
229 final String user;
230 try {
231 user = Context.getThreadContext().getPerson() != null
232 ? Context.getThreadContext().getPerson().getName()
233 : null;
234 } catch (final EFapsException e) {
235 throw new InstallationException("No context in this thread defined!", e);
236 }
237
238
239 initialise();
240
241
242 final Map<String, Integer> versions = getLatestVersions();
243
244
245 for (final UpdateLifecycle step : getUpdateLifecycles()) {
246 if (Install.LOG.isInfoEnabled()) {
247 Install.LOG.info("..Running Lifecycle step " + step);
248 }
249 for (final Map.Entry<Class<? extends IUpdate>, List<IUpdate>> entry : this.cache.entrySet()) {
250 for (final IUpdate update : entry.getValue()) {
251 final Integer latestVersion = versions.get(update.getFileApplication());
252
253 final JexlContext jexlContext = new MapContext();
254 if (latestVersion != null) {
255 jexlContext.set("version", latestVersion);
256 jexlContext.set("latest", latestVersion);
257 }
258 try {
259
260 update.updateInDB(jexlContext, step, evaluateProfiles(update.getFileApplication(), _profiles));
261 if (!bigTrans) {
262 Context.commit();
263 Context.begin(user);
264 }
265 } catch (final EFapsException e) {
266 throw new InstallationException("Transaction start failed", e);
267 }
268
269 }
270 }
271 }
272 }
273
274
275
276
277
278
279
280
281 public Map<String, Integer> getLatestVersions()
282 throws InstallationException
283 {
284 final Map<String, Integer> versions = new HashMap<String, Integer>();
285 try {
286 if (Context.getDbType().existsView(Context.getThreadContext().getConnection(), "V_ADMINTYPE")
287 && CIAdminCommon.Version.getType() != null) {
288 final QueryBuilder queryBldr = new QueryBuilder(CIAdminCommon.Version);
289 final MultiPrintQuery multi = queryBldr.getPrint();
290 multi.addAttribute(CIAdminCommon.Version.Name, CIAdminCommon.Version.Revision);
291 multi.executeWithoutAccessCheck();
292 while (multi.next()) {
293 final String name = multi.<String>getAttribute(CIAdminCommon.Version.Name);
294 final Integer revision = multi.<Integer>getAttribute(CIAdminCommon.Version.Revision);
295 if (!versions.containsKey(name) || versions.get(name) < revision) {
296 versions.put(name, revision);
297 }
298 }
299 }
300 } catch (final EFapsException e) {
301 throw new InstallationException("Latest version could not be found", e);
302 } catch (final SQLException e) {
303 throw new InstallationException("Latest version could not be found", e);
304 }
305 return versions;
306 }
307
308
309
310
311
312
313
314 protected void initialise()
315 throws InstallationException
316 {
317
318 if (!this.initialised) {
319 this.initialised = true;
320 this.cache.clear();
321 AppDependency.initialise();
322 for (final FileType fileType : FileType.values()) {
323
324 if (fileType == FileType.XML) {
325 for (final InstallFile file : this.files) {
326 if (file.getType() == fileType) {
327 final SaxHandler handler = new SaxHandler();
328 try {
329 final IUpdate elem = handler.parse(file.getUrl());
330 List<IUpdate> list = this.cache.get(elem.getClass());
331 if (list == null) {
332 list = new ArrayList<IUpdate>();
333 this.cache.put(elem.getClass(), list);
334 }
335 list.add(handler.getUpdate());
336 } catch (final SAXException e) {
337 throw new InstallationException("initialise()", e);
338 } catch (final IOException e) {
339 throw new InstallationException("initialise()", e);
340 }
341 }
342 }
343 } else {
344 for (final Class<? extends AbstractUpdate> updateClass : fileType.getClazzes()) {
345
346 final List<IUpdate> list = new ArrayList<IUpdate>();
347 this.cache.put(updateClass, list);
348
349 Method method = null;
350 try {
351 method = updateClass.getMethod("readFile", URL.class);
352 } catch (final SecurityException e) {
353 throw new InstallationException("initialise()", e);
354 } catch (final NoSuchMethodException e) {
355 throw new InstallationException("initialise()", e);
356 }
357 for (final InstallFile file : this.files) {
358 if (file.getType() == fileType) {
359 Object obj = null;
360 try {
361 obj = method.invoke(null, file.getUrl());
362 } catch (final IllegalArgumentException e) {
363 throw new InstallationException("initialise()", e);
364 } catch (final IllegalAccessException e) {
365 throw new InstallationException("initialise()", e);
366 } catch (final InvocationTargetException e) {
367 throw new InstallationException("initialise()", e);
368 }
369 if (obj != null) {
370 list.add((AbstractUpdate) obj);
371 }
372 }
373 }
374 }
375 }
376 }
377 }
378 }
379
380
381
382
383
384
385
386
387
388
389
390
391 public void addFile(final URL _url,
392 final String _type)
393 {
394 addFile(_url, FileType.getFileTypeByType(_type));
395 }
396
397
398
399
400
401
402
403
404 public void addFile(final URL _url,
405 final FileType _fileType)
406 {
407 this.files.add(new InstallFile(_url, _fileType));
408 this.initialised = false;
409 }
410
411
412
413
414
415
416 public List<InstallFile> getFiles()
417 {
418 return this.files;
419 }
420
421
422
423
424
425
426 protected boolean isEvaluateProfiles()
427 {
428 return this.evaluateProfiles;
429 }
430
431
432
433
434
435
436
437 private Set<Profile> evaluateProfiles(final String _application,
438 final Set<Profile> _profile)
439 throws EFapsException
440 {
441 final Set<Profile> ret;
442 if (_profile == null && _application != null) {
443 ret = new HashSet<Profile>();
444 final Properties props = EFapsSystemConfiguration.get().getAttributeValueAsProperties(
445 KernelSettings.PROFILES4UPDATE, true);
446 if (props.containsKey(_application)) {
447 final String[] profileNames = props.getProperty(_application).split(";");
448 for (final String name : profileNames) {
449 ret.add(Profile.getProfile(name));
450 }
451 }
452 if (ret.isEmpty()) {
453 ret.add(Profile.getDefaultProfile());
454 }
455 } else {
456 ret = _profile;
457 }
458 Install.LOG.debug("Applying profiles: {}", ret);
459 return ret;
460 }
461
462
463
464
465
466
467 @Override
468 public String toString()
469 {
470 return new ToStringBuilder(this)
471 .append("urls", this.files)
472 .toString();
473 }
474
475
476
477
478 public static class InstallFile
479 {
480
481
482
483 private final URL url;
484
485
486
487
488 private final FileType type;
489
490
491
492
493
494 public InstallFile(final URL _url,
495 final FileType _type)
496 {
497 this.url = _url;
498 this.type = _type;
499 }
500
501
502
503
504
505
506 public URL getUrl()
507 {
508 return this.url;
509 }
510
511
512
513
514
515
516 public FileType getType()
517 {
518 return this.type;
519 }
520
521 @Override
522 public String toString()
523 {
524 return ToStringBuilder.reflectionToString(this);
525 }
526 }
527 }