1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.efaps.admin.datamodel;
22
23 import java.sql.PreparedStatement;
24 import java.sql.ResultSet;
25 import java.sql.SQLException;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Map.Entry;
31 import java.util.StringTokenizer;
32 import java.util.TreeMap;
33 import java.util.UUID;
34
35 import org.apache.commons.lang3.builder.ToStringBuilder;
36 import org.efaps.admin.event.EventDefinition;
37 import org.efaps.admin.event.EventType;
38 import org.efaps.admin.event.Parameter.ParameterValues;
39 import org.efaps.admin.event.Return;
40 import org.efaps.admin.event.Return.ReturnValues;
41 import org.efaps.ci.CIAdminDataModel;
42 import org.efaps.ci.CIAdminUser;
43 import org.efaps.db.Context;
44 import org.efaps.db.databases.information.ColumnInformation;
45 import org.efaps.db.transaction.ConnectionResource;
46 import org.efaps.db.wrapper.SQLInsert;
47 import org.efaps.db.wrapper.SQLPart;
48 import org.efaps.db.wrapper.SQLSelect;
49 import org.efaps.db.wrapper.SQLUpdate;
50 import org.efaps.util.EFapsException;
51 import org.efaps.util.cache.CacheLogListener;
52 import org.efaps.util.cache.CacheReloadException;
53 import org.efaps.util.cache.InfinispanCache;
54 import org.infinispan.Cache;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58
59
60
61
62
63
64
65
66 public class Attribute
67 extends AbstractDataModelObject
68 {
69
70
71
72 public enum AttributeTypeDef
73 {
74
75 ATTRTYPE_LINK("440f472f-7be2-41d3-baec-4a2f0e4e5b31"),
76
77 ATTRTYPE_LINK_WITH_RANGES("9d6b2e3e-68ce-4509-a5f0-eae42323a696"),
78
79 ATTRTYPE_GROUP_LINK("a48538dd-5d9b-468f-a84f-bf42791eed66"),
80
81 ATTRTYPE_PERSON_LINK("7b8f98de-1967-44e0-b174-027349868a61"),
82
83 ATTRTYPE_CREATOR_LINK("76122fe9-8fde-4dd4-a229-e48af0fb4083"),
84
85 ATTRTYPE_MODIFIER_LINK("447a7c87-8395-48c4-b2ed-d4e96d46332c"),
86
87 ATTRTYPE_MULTILINEARRAY("adb13c3d-9506-4da2-8d75-b54c76779c6c"),
88
89 ATTRTYPE_STATUS("0161bcdb-45e9-4839-a709-3a1c56f8a76a"),
90
91 ATTRTYPE_ENUM("b7c6a324-5dec-425f-b778-fa8fabf80202"),
92
93 ATTRTYPE_BITENUM("a9b1abde-d58d-4aea-8cdc-f2870111f1cd"),
94
95 ATTRTYPE_JAXB("58817bd8-db76-4b40-8acd-18112fe96170");
96
97
98
99
100 private final UUID uuid;
101
102
103
104
105
106
107 private AttributeTypeDef(final String _uuid)
108 {
109 this.uuid = UUID.fromString(_uuid);
110 }
111
112
113
114
115 public UUID getUuid()
116 {
117 return this.uuid;
118 }
119 }
120
121
122
123
124 private static final long serialVersionUID = 1L;
125
126
127
128
129 private static final Logger LOG = LoggerFactory.getLogger(Attribute.class);
130
131
132
133
134 private static final String SQL_TYPE = new SQLSelect()
135 .column("ID")
136 .column("NAME")
137 .column("TYPEID")
138 .column("DMTABLE")
139 .column("DMATTRIBUTETYPE")
140 .column("DMTYPELINK")
141 .column("PARENTSET")
142 .column("SQLCOLUMN")
143 .column("DEFAULTVAL")
144 .column("DIMENSION")
145 .column("CLASSNAME")
146 .from("V_ADMINATTRIBUTE", 0)
147 .addPart(SQLPart.WHERE).addColumnPart(0, "DMTYPE").addPart(SQLPart.EQUAL).addValuePart("?")
148 .toString();
149
150
151
152
153 private static final String SQL_ATTR = new SQLSelect()
154 .column("DMTYPE")
155 .from("V_ADMINATTRIBUTE", 0)
156 .addPart(SQLPart.WHERE).addColumnPart(0, "ID").addPart(SQLPart.EQUAL).addValuePart("?").toString();
157
158
159
160
161 private static String NAMECACHE = Attribute.class.getName() + ".Name";
162
163
164
165
166 private static String IDCACHE = Attribute.class.getName() + ".ID";
167
168
169
170
171
172
173 private final SQLTable sqlTable;
174
175
176
177
178
179
180
181 private Long link = null;
182
183
184
185
186
187
188
189 private final Long parent;
190
191
192
193
194
195
196
197 private final ArrayList<String> sqlColNames = new ArrayList<String>();
198
199
200
201
202
203
204 private final AttributeType attributeType;
205
206
207
208
209
210
211 private final String defaultValue;
212
213
214
215
216
217
218
219 private final boolean required;
220
221
222
223
224 private AttributeSet parentSet;
225
226
227
228
229
230 private final int size;
231
232
233
234
235 private final int scale;
236
237
238
239
240 private final String dimensionUUID;
241
242
243
244
245
246 private Map<String, Attribute> dependencies;
247
248
249
250
251 private String key;
252
253
254
255
256
257
258
259 private String className;
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278 protected Attribute(final long _id,
279 final long _parentId,
280 final String _name,
281 final String _sqlColNames,
282 final SQLTable _sqlTable,
283 final AttributeType _attributeType,
284 final String _defaultValue,
285 final String _dimensionUUID)
286
287 throws EFapsException
288 {
289 super(_id, null, _name);
290 this.sqlTable = _sqlTable;
291 this.parent = _parentId;
292 this.attributeType = _attributeType;
293 this.defaultValue = (_defaultValue != null) ? _defaultValue.trim() : null;
294 this.dimensionUUID = (_dimensionUUID != null) ? _dimensionUUID.trim() : null;
295
296 boolean req = false;
297 int sizeTemp = 0;
298 int scaleTemp = 0;
299 final StringTokenizer tok = new StringTokenizer(_sqlColNames.trim(), ",");
300 while (tok.hasMoreTokens()) {
301 final String colName = tok.nextToken().trim();
302 getSqlColNames().add(colName);
303 final ColumnInformation columInfo = this.sqlTable.getTableInformation().getColInfo(colName);
304 if (columInfo == null) {
305 throw new EFapsException(Attribute.class, "Attribute", _id, _name, _sqlTable, colName);
306 }
307 req |= !columInfo.isNullable();
308 sizeTemp = columInfo.getSize();
309 scaleTemp = columInfo.getScale();
310 }
311 this.size = sizeTemp;
312 this.scale = scaleTemp;
313 this.required = req;
314 }
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335 private Attribute(final long _id,
336 final long _parentId,
337 final String _name,
338 final SQLTable _sqlTable,
339 final AttributeType _attributeType,
340 final String _defaultValue,
341 final String _dimensionUUID,
342 final boolean _required,
343 final int _size,
344 final int _scale)
345 {
346
347 super(_id, null, _name);
348 this.parent = _parentId;
349 this.sqlTable = _sqlTable;
350 this.attributeType = _attributeType;
351 this.defaultValue = (_defaultValue != null) ? _defaultValue.trim() : null;
352 this.required = _required;
353 this.size = _size;
354 this.scale = _scale;
355 this.dimensionUUID = _dimensionUUID;
356 }
357
358
359
360
361
362
363
364 public boolean hasLink()
365 {
366 return this.link != null;
367 }
368
369
370
371
372
373
374 protected Attribute copy(final long _parentId)
375 {
376 final Attribute ret = new Attribute(getId(), _parentId, getName(), this.sqlTable, this.attributeType,
377 this.defaultValue, this.dimensionUUID, this.required, this.size, this.scale);
378 ret.getSqlColNames().addAll(getSqlColNames());
379 ret.setLink(this.link);
380 ret.setClassName(getClassName());
381 ret.getProperties().putAll(getProperties());
382 return ret;
383 }
384
385
386
387
388 @Override
389 public void addEvent(final EventType _eventtype,
390 final EventDefinition _eventdef)
391 throws CacheReloadException
392 {
393 super.addEvent(_eventtype, _eventdef);
394 for (final Type child : getParent().getChildTypes()) {
395 final Attribute childAttr = child.getAttribute(getName());
396 if (childAttr != null) {
397 childAttr.addEvent(_eventtype, _eventdef);
398 }
399 }
400 }
401
402
403
404
405
406
407
408 public SQLTable getTable()
409 {
410 return this.sqlTable;
411 }
412
413
414
415
416
417
418
419
420 protected void setLink(final Long _link)
421 {
422 this.link = _link;
423 }
424
425
426
427
428
429
430
431 public Type getLink()
432 throws CacheReloadException
433 {
434 return Type.get(this.link);
435 }
436
437
438
439
440
441
442
443 public Map<String, Attribute> getDependencies()
444 throws CacheReloadException
445 {
446 if (this.dependencies == null) {
447 this.dependencies = new TreeMap<String, Attribute>();
448
449
450 if (getProperties().containsKey("CurrencyAttribute4Rate")) {
451 this.dependencies.put("CurrencyAttribute4Rate",
452 getParent().getAttribute(getProperties().get("CurrencyAttribute4Rate")));
453 this.dependencies.put("TargetCurrencyAttribute4Rate",
454 getParent().getAttribute(getProperties().get("TargetCurrencyAttribute4Rate")));
455 }
456 }
457 return this.dependencies;
458 }
459
460
461
462
463
464
465
466 public Type getParent()
467 throws CacheReloadException
468 {
469 return Type.get(this.parent);
470 }
471
472
473
474
475 public Long getParentId()
476 {
477 return this.parent;
478 }
479
480
481
482
483
484
485
486 public AttributeSet getParentSet()
487 {
488 return this.parentSet;
489 }
490
491
492
493
494
495
496 private void setParentSet(final AttributeSet _parentSet)
497 {
498 this.parentSet = _parentSet;
499 }
500
501
502
503
504
505
506
507 public ArrayList<String> getSqlColNames()
508 {
509 return this.sqlColNames;
510 }
511
512
513
514
515
516
517
518 public AttributeType getAttributeType()
519 {
520 return this.attributeType;
521 }
522
523
524
525
526
527
528
529 public String getDefaultValue()
530 {
531 return this.defaultValue;
532 }
533
534
535
536
537
538
539
540 public boolean isRequired()
541 {
542 return this.required;
543 }
544
545
546
547
548
549
550 public int getSize()
551 {
552 return this.size;
553 }
554
555
556
557
558
559
560 public int getScale()
561 {
562 return this.scale;
563 }
564
565
566
567
568
569
570 public Dimension getDimension()
571
572 {
573 Dimension ret = null;
574 try {
575 ret = Dimension.get(UUID.fromString(this.dimensionUUID));
576 } catch (final CacheReloadException e) {
577
578 e.printStackTrace();
579 }
580 return ret;
581 }
582
583
584
585
586
587
588 public boolean hasUoM()
589 {
590 return this.dimensionUUID != null;
591 }
592
593
594
595
596
597
598
599
600
601 public void prepareDBInsert(final SQLInsert _insert,
602 final Object... _values)
603 throws SQLException
604 {
605 Object[] tmp = _values;
606 try {
607 final List<Return> returns = executeEvents(EventType.UPDATE_VALUE, ParameterValues.CLASS, this,
608 ParameterValues.OTHERS, _values);
609 for (final Return aRet : returns) {
610 if (aRet.contains(ReturnValues.VALUES)) {
611 tmp = (Object[]) aRet.get(ReturnValues.VALUES);
612 }
613 }
614 } catch (final EFapsException e) {
615 throw new SQLException(e);
616 }
617 this.attributeType.getDbAttrType().prepareInsert(_insert, this, tmp);
618 }
619
620
621
622
623
624
625
626
627
628 public void prepareDBUpdate(final SQLUpdate _update,
629 final Object... _values)
630 throws SQLException
631 {
632 Object[] tmp = _values;
633 try {
634 final List<Return> returns = executeEvents(EventType.UPDATE_VALUE, ParameterValues.CLASS, this,
635 ParameterValues.OTHERS, _values);
636 for (final Return aRet : returns) {
637 if (aRet.contains(ReturnValues.VALUES)) {
638 tmp = (Object[]) aRet.get(ReturnValues.VALUES);
639 }
640 }
641 } catch (final EFapsException e) {
642 throw new SQLException(e);
643 }
644 this.attributeType.getDbAttrType().prepareUpdate(_update, this, tmp);
645 }
646
647
648
649
650
651
652
653
654 public Object readDBValue(final List<Object> _objectList)
655 throws EFapsException
656 {
657 Object ret = this.attributeType.getDbAttrType().readValue(this, _objectList);
658 final List<Return> returns = executeEvents(EventType.READ_VALUE, ParameterValues.CLASS, this,
659 ParameterValues.OTHERS, ret);
660 for (final Return aRet : returns) {
661 if (aRet.contains(ReturnValues.VALUES)) {
662 ret = aRet.get(ReturnValues.VALUES);
663 }
664 }
665 return ret;
666 }
667
668
669
670
671 public String getLabelKey()
672 {
673 return getKey() + ".Label";
674 }
675
676
677
678
679 public String getKey()
680 {
681 if (this.key == null) {
682 try {
683 this.key = getParent().getName() + "/" + getName();
684 } catch (final CacheReloadException e) {
685 Attribute.LOG.error("Problems during reading of key for Attribute: {}", this);
686 }
687 }
688 return this.key;
689 }
690
691
692
693
694
695
696 public String getClassName()
697 {
698 return this.className;
699 }
700
701
702
703
704
705
706 protected void setClassName(final String _className)
707 {
708 this.className = _className;
709 }
710
711
712
713
714
715
716
717 public static void initialize(final Class<?> _class)
718 throws CacheReloadException
719 {
720 if (InfinispanCache.get().exists(Attribute.NAMECACHE)) {
721 InfinispanCache.get().<String, Attribute>getCache(Attribute.NAMECACHE).clear();
722 } else {
723 InfinispanCache.get().<String, Attribute>getCache(Attribute.NAMECACHE)
724 .addListener(new CacheLogListener(Attribute.LOG));
725 }
726
727 if (InfinispanCache.get().exists(Attribute.IDCACHE)) {
728 InfinispanCache.get().<Long, Attribute>getCache(Attribute.IDCACHE).clear();
729 } else {
730 InfinispanCache.get().<Long, Attribute>getCache(Attribute.IDCACHE)
731 .addListener(new CacheLogListener(Attribute.LOG));
732 }
733 }
734
735
736
737
738
739
740 public static void initialize()
741 throws CacheReloadException
742 {
743 Attribute.initialize(Attribute.class);
744 }
745
746
747
748
749
750
751
752
753
754
755 public static Attribute get(final long _id)
756 throws CacheReloadException
757 {
758 final Cache<Long, Attribute> cache = InfinispanCache.get().<Long, Attribute>getCache(Attribute.IDCACHE);
759 if (!cache.containsKey(_id)) {
760 Type.get(Attribute.getTypeID(_id));
761 }
762 return cache.get(_id);
763 }
764
765
766
767
768
769
770
771
772
773
774 public static Attribute get(final String _name)
775 throws CacheReloadException
776 {
777 final Cache<String, Attribute> cache = InfinispanCache.get().<String, Attribute>getCache(Attribute.NAMECACHE);
778 if (!cache.containsKey(_name)) {
779 final String[] nameParts = _name.split("/");
780 if (nameParts != null && nameParts.length == 2) {
781 Type.get(nameParts[0]);
782 }
783 }
784 return cache.get(_name);
785 }
786
787
788
789
790
791 private static void cacheAttribute(final Attribute _attr,
792 final Type _type)
793 {
794 final Cache<String, Attribute> nameCache = InfinispanCache.get().<String, Attribute>getIgnReCache(
795 Attribute.NAMECACHE);
796 if (_type != null) {
797 nameCache.putIfAbsent(_type.getName() + "/" + _attr.getName(), _attr);
798 } else {
799 nameCache.putIfAbsent(_attr.getKey(), _attr);
800 }
801
802 final Cache<Long, Attribute> idCache = InfinispanCache.get().<Long, Attribute>getIgnReCache(
803 Attribute.IDCACHE);
804 idCache.putIfAbsent(_attr.getId(), _attr);
805 }
806
807
808
809
810
811
812
813
814 @Override
815 public String toString()
816 {
817 return new ToStringBuilder(this).appendSuper(super.toString())
818 .append("attributetype", getAttributeType().toString())
819 .append("required", this.required).toString();
820 }
821
822 @Override
823 public boolean equals(final Object _obj)
824 {
825 boolean ret;
826 if (_obj instanceof Attribute) {
827 ret = ((Attribute) _obj).getId() == getId();
828 } else {
829 ret = super.equals(_obj);
830 }
831 return ret;
832 }
833
834 @Override
835 public int hashCode()
836 {
837 return Long.valueOf(getId()).intValue();
838 }
839
840
841
842
843
844
845 protected static long getTypeID(final long _attrId)
846 throws CacheReloadException
847 {
848 long ret = 0;
849 ConnectionResource con = null;
850 try {
851 con = Context.getThreadContext().getConnectionResource();
852 PreparedStatement stmt = null;
853 try {
854 stmt = con.getConnection().prepareStatement(Attribute.SQL_ATTR);
855 stmt.setObject(1, _attrId);
856 final ResultSet rs = stmt.executeQuery();
857 while (rs.next()) {
858 ret = rs.getLong(1);
859 }
860 rs.close();
861 } finally {
862 if (stmt != null) {
863 stmt.close();
864 }
865 }
866 con.commit();
867 } catch (final SQLException e) {
868 throw new CacheReloadException("Cannot read a type for an attribute.", e);
869 } catch (final EFapsException e) {
870 throw new CacheReloadException("Cannot read a type for an attribute.", e);
871 } finally {
872 if ((con != null) && con.isOpened()) {
873 try {
874 con.abort();
875 } catch (final EFapsException e) {
876 throw new CacheReloadException("Cannot read a type for an attribute.", e);
877 }
878 }
879 }
880 return ret;
881 }
882
883
884
885
886
887 protected static void add4Type(final Type _type)
888 throws EFapsException
889 {
890 ConnectionResource con = null;
891 try {
892 con = Context.getThreadContext().getConnectionResource();
893 PreparedStatement stmt = null;
894 final List<Object[]> values = new ArrayList<Object[]>();
895 try {
896 stmt = con.getConnection().prepareStatement(Attribute.SQL_TYPE);
897 stmt.setObject(1, _type.getId());
898 final ResultSet rs = stmt.executeQuery();
899 while (rs.next()) {
900 values.add(new Object[] {
901 rs.getLong(1),
902 rs.getString(2).trim(),
903 rs.getLong(3),
904 rs.getLong(4),
905 rs.getLong(5),
906 rs.getLong(6),
907 rs.getLong(7),
908 rs.getString(8),
909 rs.getString(9),
910 rs.getString(10),
911 rs.getString(11)
912 });
913 }
914 rs.close();
915 } finally {
916 if (stmt != null) {
917 stmt.close();
918 }
919 }
920 con.commit();
921
922 final Map<Long, AttributeSet> id2Set = new HashMap<Long, AttributeSet>();
923 final Map<Attribute, Long> attribute2setId = new HashMap<Attribute, Long>();
924 final List<Attribute> attributes = new ArrayList<Attribute>();
925 for (final Object[] row : values) {
926 final long id = (Long) row[0];
927 final String name = (String) row[1];
928 final long typeAttrId = (Long) row[2];
929 final long tableId = (Long) row[3];
930 final long attrTypeId = (Long) row[4];
931 final long typeLinkId = (Long) row[5];
932 final long parentSetId = (Long) row[6];
933 final String sqlCol = (String) row[7];
934 final String defaultval = (String) row[8];
935 final String dimensionUUID = (String) row[9];
936 final String className = (String) row[10];
937
938 Attribute.LOG.debug("read attribute '{}/{}' (id = {})", _type.getName(), name, id);
939
940 if (Type.check4Type(typeAttrId, CIAdminDataModel.AttributeSet.uuid)) {
941 final AttributeSet set = new AttributeSet(id, _type, name, AttributeType.get(attrTypeId),
942 sqlCol, tableId, typeLinkId, dimensionUUID);
943 id2Set.put(id, set);
944 } else {
945 final Attribute attr = new Attribute(id, _type.getId(), name, sqlCol, SQLTable.get(tableId),
946 AttributeType.get(attrTypeId), defaultval,
947 dimensionUUID);
948
949 final UUID uuid = attr.getAttributeType().getUUID();
950 if (uuid.equals(Attribute.AttributeTypeDef.ATTRTYPE_LINK.getUuid())
951 || uuid.equals(Attribute.AttributeTypeDef.ATTRTYPE_LINK_WITH_RANGES.getUuid())
952 || uuid.equals(Attribute.AttributeTypeDef.ATTRTYPE_STATUS.getUuid())) {
953 attr.setLink(typeLinkId);
954
955
956 } else if (uuid.equals(Attribute.AttributeTypeDef.ATTRTYPE_CREATOR_LINK.getUuid())
957 || uuid.equals(Attribute.AttributeTypeDef.ATTRTYPE_MODIFIER_LINK.getUuid())
958 || uuid.equals(Attribute.AttributeTypeDef.ATTRTYPE_PERSON_LINK.getUuid())) {
959 attr.setLink(Type.getId4UUID(CIAdminUser.Person.uuid));
960
961 } else if (uuid.equals(Attribute.AttributeTypeDef.ATTRTYPE_GROUP_LINK.getUuid())) {
962 attr.setLink(Type.getId4UUID(CIAdminUser.Group.uuid));
963
964 } else if (uuid.equals(Attribute.AttributeTypeDef.ATTRTYPE_ENUM.getUuid())
965 || uuid.equals(Attribute.AttributeTypeDef.ATTRTYPE_BITENUM.getUuid())
966 || uuid.equals(Attribute.AttributeTypeDef.ATTRTYPE_JAXB.getUuid())) {
967 if (className == null || (className != null && className.isEmpty())) {
968 Attribute.LOG.error("An Attribute of Type Enum, BitEnum, Jaxb must have a className: {}",
969 attr);
970 }
971 attr.setClassName(className.trim());
972 }
973 attr.readFromDB4Properties();
974
975 if (Type.check4Type(typeAttrId, CIAdminDataModel.AttributeSetAttribute.uuid)) {
976 attribute2setId.put(attr, parentSetId);
977 } else {
978 attributes.add(attr);
979 Attribute.cacheAttribute(attr, _type);
980 }
981 }
982 }
983
984 for (final Entry<Attribute, Long> entry : attribute2setId.entrySet()) {
985 final AttributeSet parentset = id2Set.get(entry.getValue());
986 final Attribute childAttr = entry.getKey();
987 parentset.addAttributes(false, childAttr);
988 childAttr.setParentSet(parentset);
989
990 Attribute.cacheAttribute(childAttr, parentset);
991 }
992 for (final AttributeSet set : id2Set.values()) {
993 Type.cacheType(set);
994 }
995
996 _type.addAttributes(false, attributes.toArray(new Attribute[attributes.size()]));
997 } catch (final SQLException e) {
998 throw new CacheReloadException("Cannot read attributes.", e);
999 } finally {
1000 if ((con != null) && con.isOpened()) {
1001 con.abort();
1002 }
1003 }
1004 }
1005 }