1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.efaps.db;
22
23 import java.sql.SQLException;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.Hashtable;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Map.Entry;
32 import java.util.Set;
33
34 import org.apache.commons.collections4.iterators.ReverseListIterator;
35 import org.apache.commons.lang3.builder.ToStringBuilder;
36 import org.efaps.admin.access.AccessCache;
37 import org.efaps.admin.access.AccessTypeEnums;
38 import org.efaps.admin.datamodel.Attribute;
39 import org.efaps.admin.datamodel.AttributeType;
40 import org.efaps.admin.datamodel.Dimension.UoM;
41 import org.efaps.admin.datamodel.SQLTable;
42 import org.efaps.admin.datamodel.Type;
43 import org.efaps.admin.event.EventDefinition;
44 import org.efaps.admin.event.EventType;
45 import org.efaps.admin.event.Parameter;
46 import org.efaps.admin.event.Parameter.ParameterValues;
47 import org.efaps.admin.event.Return;
48 import org.efaps.admin.event.Return.ReturnValues;
49 import org.efaps.ci.CIAttribute;
50 import org.efaps.db.transaction.ConnectionResource;
51 import org.efaps.db.wrapper.SQLUpdate;
52 import org.efaps.util.EFapsException;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56
57
58
59
60 public class Update
61 {
62
63
64
65 private static final Status STATUSOK = new Status();
66
67
68
69
70 private static final Logger LOG = LoggerFactory.getLogger(Update.class);
71
72
73
74
75 private Instance instance = null;
76
77
78
79
80 private final Map<SQLTable, List<Value>> table2values = new Hashtable<SQLTable, List<Value>>();
81
82
83
84
85 private final Map<Attribute, Value> attr2values = new HashMap<Attribute, Value>();
86
87
88
89
90 private final Map<Attribute, Value> trigRelevantAttr2values = new HashMap<Attribute, Value>();
91
92
93
94
95
96
97 public Update(final Type _type,
98 final String _id)
99 throws EFapsException
100 {
101 this(Instance.get(_type, _id));
102 }
103
104
105
106
107
108
109 public Update(final Type _type,
110 final long _id)
111 throws EFapsException
112 {
113 this(Instance.get(_type, _id));
114 }
115
116
117
118
119
120
121 public Update(final String _type,
122 final String _id)
123 throws EFapsException
124 {
125 this(Type.get(_type), _id);
126 }
127
128
129
130
131
132 public Update(final String _oid)
133 throws EFapsException
134 {
135 this(Instance.get(_oid));
136 }
137
138
139
140
141
142 public Update(final Instance _instance)
143 throws EFapsException
144 {
145 setInstance(_instance);
146 addAlwaysUpdateAttributes();
147 if (!Update.STATUSOK.getStati().isEmpty()) {
148 Update.STATUSOK.getStati().clear();
149 }
150 }
151
152
153
154
155
156 protected void addAlwaysUpdateAttributes()
157 throws EFapsException
158 {
159 final Iterator<?> iter = getInstance().getType().getAttributes().entrySet().iterator();
160 while (iter.hasNext()) {
161 final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) iter.next();
162 final Attribute attr = (Attribute) entry.getValue();
163 final AttributeType attrType = attr.getAttributeType();
164 if (attrType.isAlwaysUpdate()) {
165 addInternal(attr, false, (Object[]) null);
166 }
167 }
168 }
169
170
171
172
173
174
175
176 public void close()
177 throws EFapsException
178 {
179 }
180
181
182
183
184
185
186
187
188
189
190 protected boolean executeEvents(final EventType _eventtype)
191 throws EFapsException
192 {
193 boolean ret = false;
194 final List<EventDefinition> triggers = getInstance().getType().getEvents(_eventtype);
195 if (triggers != null) {
196 final Parameter parameter = new Parameter();
197 parameter.put(ParameterValues.NEW_VALUES, getNewValuesMap());
198 parameter.put(ParameterValues.INSTANCE, getInstance());
199 for (final EventDefinition evenDef : triggers) {
200 evenDef.execute(parameter);
201 }
202 ret = true;
203 }
204 return ret;
205 }
206
207
208
209
210 protected final Map<Attribute, Object[]> getNewValuesMap()
211 {
212
213 final Map<Attribute, Object[]> ret = new HashMap<Attribute, Object[]>();
214 for (final Entry<Attribute, Value> entry : this.trigRelevantAttr2values.entrySet()) {
215 ret.put(entry.getKey(), entry.getValue().getValues());
216 }
217 return ret;
218 }
219
220
221
222
223
224
225
226 public Status add(final String _attr,
227 final Object... _values)
228 throws EFapsException
229 {
230 final Attribute attr = getInstance().getType().getAttribute(_attr);
231 if (attr == null) {
232 throw new EFapsException(getClass(), "add.UnknownAttributeName", _attr);
233 }
234 return add(attr, _values);
235 }
236
237
238
239
240
241
242
243 public Status add(final Attribute _attr,
244 final Object... _values)
245 throws EFapsException
246 {
247 return addInternal(_attr, true, _values);
248 }
249
250
251
252
253
254
255
256 public Status add(final CIAttribute _attr,
257 final Object... _values)
258 throws EFapsException
259 {
260 final Attribute attr = getInstance().getType().getAttribute(_attr.name);
261 if (attr == null) {
262 throw new EFapsException(getClass(), "add.UnknownAttributeName", _attr);
263 }
264 return add(attr, _values);
265 }
266
267
268
269
270
271
272
273
274 protected Status addInternal(final Attribute _attr,
275 final boolean _triggerRelevant,
276 final Object... _value)
277 throws EFapsException
278 {
279 Status ret = Update.STATUSOK;
280 if (_attr.hasEvents(EventType.VALIDATE)) {
281 final List<Return> returns = _attr.executeEvents(EventType.VALIDATE, ParameterValues.NEW_VALUES, _value);
282 for (final Return retu : returns) {
283 if (retu.get(ReturnValues.TRUE) == null) {
284 ret = new Status(retu.get(ReturnValues.VALUES), _attr, _value);
285 break;
286 }
287 }
288 }
289 final Value value = getValue(_attr, _value);
290 validate(getInstance(), value);
291 List<Value> values = this.table2values.get(_attr.getTable());
292 if (values == null) {
293 values = new ArrayList<Value>();
294 this.table2values.put(_attr.getTable(), values);
295 }
296 values.add(value);
297
298 this.attr2values.put(_attr, value);
299
300 if (_triggerRelevant) {
301 this.trigRelevantAttr2values.put(_attr, value);
302 }
303 return ret;
304 }
305
306
307
308
309
310
311 protected void validate(final Instance _instance,
312 final Value _value)
313 throws EFapsException
314 {
315 _value.getAttribute().getAttributeType().getDbAttrType()
316 .valiate4Update(_value.getAttribute(), getInstance(), _value.getValues());
317 }
318
319
320
321
322
323
324 protected Value getValue(final Attribute _attr,
325 final Object[] _value)
326 {
327 final List<Object> values = new ArrayList<Object>();
328 if (_value != null) {
329 for (final Object obj : _value) {
330 final Object object;
331 if (obj instanceof Instance) {
332 object = ((Instance) obj).getId();
333 } else if (obj instanceof org.efaps.admin.datamodel.Status) {
334 object = ((org.efaps.admin.datamodel.Status) obj).getId();
335 } else if (obj instanceof UoM) {
336 object = ((UoM) obj).getId();
337 } else {
338 object = obj;
339 }
340 values.add(object);
341 }
342 }
343 return new Value(_attr, _value == null ? null : values.toArray());
344 }
345
346
347
348
349
350
351 protected Map<SQLTable, List<Value>> getTable2values()
352 {
353 return this.table2values;
354 }
355
356
357
358
359
360 public void execute()
361 throws EFapsException
362 {
363 final Set<Attribute> attributes = new HashSet<Attribute>();
364 for (final Attribute attr : this.attr2values.keySet()) {
365 final AttributeType attrType = attr.getAttributeType();
366 if (!attrType.isAlwaysUpdate()) {
367 attributes.add(attr);
368 }
369 }
370 AccessCache.registerUpdate(getInstance());
371 final boolean hasAccess = getType().hasAccess(getInstance(), AccessTypeEnums.MODIFY.getAccessType(),
372 attributes);
373
374 if (!hasAccess) {
375 throw new EFapsException(getClass(), "execute.NoAccess", Context.getThreadContext().getPerson());
376 }
377 executeWithoutAccessCheck();
378 }
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395 public void executeWithoutAccessCheck()
396 throws EFapsException
397 {
398 if (Update.STATUSOK.getStati().isEmpty()) {
399
400 executeEvents(EventType.UPDATE_PRE);
401
402 if (!executeEvents(EventType.UPDATE_OVERRIDE)) {
403 executeWithoutTrigger();
404 }
405
406 executeEvents(EventType.UPDATE_POST);
407 } else {
408 throw new EFapsException(getClass(), "executeWithout.StatusInvalid", Update.STATUSOK.getStati());
409 }
410 }
411
412
413
414
415
416
417
418 public void executeWithoutTrigger()
419 throws EFapsException
420 {
421 if (Update.STATUSOK.getStati().isEmpty()) {
422 final Context context = Context.getThreadContext();
423 ConnectionResource con = null;
424 try {
425 con = context.getConnectionResource();
426 for (final Entry<SQLTable, List<Value>> entry : this.table2values.entrySet()) {
427 final SQLUpdate update = Context.getDbType().newUpdate(entry.getKey().getSqlTable(),
428 entry.getKey().getSqlColId(),
429 this.instance.getId());
430
431
432 final ReverseListIterator<Value> iterator = new ReverseListIterator<Value>(entry.getValue());
433
434 final Set<String> added = new HashSet<String>();
435 while (iterator.hasNext()) {
436 final Value value = iterator.next();
437 final String colKey = value.getAttribute().getSqlColNames().toString();
438 if (!added.contains(colKey)) {
439 value.getAttribute().prepareDBUpdate(update, value.getValues());
440 added.add(colKey);
441 }
442
443 }
444 update.execute(con.getConnection());
445 }
446 con.commit();
447 } catch (final SQLException e) {
448 Update.LOG.error("Update of '" + this.instance + "' not possible", e);
449 throw new EFapsException(getClass(), "executeWithoutTrigger.SQLException", e, this.instance);
450 } finally {
451 if ((con != null) && con.isOpened()) {
452 con.abort();
453 }
454 }
455 } else {
456 throw new EFapsException(getClass(), "executeWithout.StatusInvalid", Update.STATUSOK.getStati());
457 }
458 }
459
460
461
462
463
464
465
466 protected Type getType()
467 {
468 return getInstance().getType();
469 }
470
471
472
473
474
475
476
477
478
479 public long getId()
480 {
481 return getInstance().getId();
482 }
483
484
485
486
487
488
489
490
491 public Instance getInstance()
492 {
493 return this.instance;
494 }
495
496
497
498
499
500
501
502
503 protected void setInstance(final Instance _instance)
504 {
505 this.instance = _instance;
506 }
507
508
509
510
511 public static class Status
512 {
513
514
515
516
517
518
519
520 private final List<Update.Status> stati = new ArrayList<Update.Status>();
521
522
523
524
525
526
527 private final Object returnValue;
528
529
530
531
532
533
534
535 private final Object value;
536
537
538
539
540
541 private final Attribute attribute;
542
543
544
545
546
547
548
549
550
551 public Status(final Object _returnvalue,
552 final Attribute _attribute,
553 final Object _value)
554 {
555 this.returnValue = _returnvalue;
556 this.value = _value;
557 this.attribute = _attribute;
558 Update.STATUSOK.getStati().add(this);
559 }
560
561
562
563
564 public Status()
565 {
566 this.returnValue = null;
567 this.value = null;
568 this.attribute = null;
569 }
570
571
572
573
574
575
576 public boolean isOk()
577 {
578 boolean ret = false;
579 if (equals(Update.STATUSOK)) {
580 ret = true;
581 }
582 return ret;
583 }
584
585
586
587
588
589
590
591
592 public Object getReturnValue()
593 {
594 return this.returnValue;
595 }
596
597
598
599
600
601
602
603 public Object getValue()
604 {
605 return this.value;
606 }
607
608
609
610
611
612
613
614
615 public Attribute getAttribute()
616 {
617 return this.attribute;
618 }
619
620
621
622
623
624
625
626 public List<Update.Status> getStati()
627 {
628 return this.stati;
629 }
630
631
632
633
634
635 @Override
636 public String toString()
637 {
638 return new ToStringBuilder(this).append("AttributeName", getAttribute().getName())
639 .append(" Value", getValue()).append(" ReturnValue:", getReturnValue()).toString();
640 }
641 }
642
643
644
645
646 protected static final class Value
647 {
648
649
650
651 private final Attribute attribute;
652
653
654
655
656 private final Object[] values;
657
658
659
660
661
662 private Value(final Attribute _attribute,
663 final Object... _values)
664 {
665 this.attribute = _attribute;
666 this.values = _values;
667 }
668
669
670
671
672 public Attribute getAttribute()
673 {
674 return this.attribute;
675 }
676
677
678
679
680 public Object[] getValues()
681 {
682 return this.values;
683 }
684
685 @Override
686 public String toString()
687 {
688 return ToStringBuilder.reflectionToString(this);
689 }
690 }
691 }