Project

General

Profile

signature_builder.diff

Adrian Lungu, 11/23/2020 01:16 PM

Download (9.42 KB)

View differences:

src/com/goldencode/p2j/persist/TemporaryBuffer.java 2020-11-23 17:31:35 +0000
3374 3374
         
3375 3375
         if (!srcBuf.isTableDefinitelyEmpty())
3376 3376
         {
3377
            DmoMeta srcMeta = srcBuf.getDmoInfo();
3377 3378
            DmoMeta dstMeta = dstBuf.getDmoInfo();
3378 3379
            
3379 3380
            // skip validation when:
......
3382 3383
            // TODO: enhance this if we are not in append mode, the dst and src tables are different, and they 
3383 3384
            // have the same set of unique indexes (by the field position, not name) and the same set of
3384 3385
            // mandatory fields (by field position, not name)
3385
            boolean bulkInsert = !append &&
3386
               ((dstBuf.getDMOImplementationClass() == srcBuf.getDMOImplementationClass()) ||
3387
                (dstMeta.getUniqueConstraints().isEmpty() && dstMeta.getMandatoryFields().isEmpty()));
3386
            boolean bulkInsert = !append && srcMeta.getSignature().equals(dstMeta.getSignature());
3387
            
3388
            /*((dstBuf.getDMOImplementationClass() == srcBuf.getDMOImplementationClass()) ||
3389
                (dstMeta.getUniqueConstraints().isEmpty() && dstMeta.getMandatoryFields().isEmpty()));*/
3388 3390
            
3389 3391
            if (bulkInsert)
3390 3392
            {
src/com/goldencode/p2j/persist/orm/DmoMeta.java 2020-11-23 18:03:22 +0000
202 202
   /** The set of properties and their metadata, indexed by their in-memory positions. */
203 203
   private Pair<Property, PropertyMeta>[] properties = null;
204 204
   
205
   /** The set of properties and their metadata, indexed by their in-memory positions. */
206
   private String signature;
207
   
205 208
   /** The unique id of this DMO. */
206 209
   private final int id = idSeed.incrementAndGet();
207 210
   
......
311 314
         fields.put(property.name, property);
312 315
      }
313 316
      
317
      // build a String signature suitable for identifying if two DMOs are compatible in certain 
318
      // operations (for example copy-temp-table).
319
      signature = SignatureBuilder.buildSignature(getFields(false), getUniqueProperties());
320
      
314 321
      // the eventual relations cannot be created at this moment, they will be processed at a
315 322
      // later time, when the respective DMO interfaces will be loaded. 
316 323
   }
......
753 760
      return uniqueConstraints;
754 761
   }
755 762
   
763
   public Set<Property> getUniqueProperties()
764
   {
765
      Set<Property> uniqueProp = new HashSet<>();
766
      List<Set<String>> indexList = getUniqueConstraints();
767
      
768
      for (Set<String> index : indexList)
769
      {
770
         for (String field : index)
771
         {
772
            Property prop = fields.get(field);
773
            uniqueProp.add(prop);
774
         }
775
      }
776
      
777
      return uniqueProp;
778
   }
779
   
756 780
   /**
757 781
    * Get the {@code Property} that correspond to the k-th entry in {@code data} table of the class
758 782
    * implementing this DMO.
......
1085 1109
   }
1086 1110
   
1087 1111
   /**
1112
    * Get the structure-based signature for this DMO.
1113
    * 
1114
    * @return  The signature of this DMO.
1115
    */
1116
   public String getSignature()
1117
   {
1118
      return signature;
1119
   }
1120
   
1121
   /**
1088 1122
    * Obtain a short description of this object, usually for debugging.
1089 1123
    * 
1090 1124
    * @return  a short description of this object.
src/com/goldencode/p2j/persist/orm/SignatureBuilder.java 2020-11-23 18:01:48 +0000
1
package com.goldencode.p2j.persist.orm;
2

  
3
import java.util.*;
4
import java.util.logging.*;
5

  
6
import com.goldencode.p2j.util.*;
7

  
8
/**
9
 * Compute a string based signature for a DMO, which contains information regarding the 
10
 * type of each field, extents and eventually some restrictions like mandatory or unique.
11
 * In order to have the prefix-code property for each generated string, the following 
12
 * standards should be respected:
13
 * - The properties are represented in the order they are provided.
14
 * - A data type representation should be a single upper case character.
15
 * - In case the field has an extent, the length of the extent will follow the data type 
16
 * representation as a number (no matter the number of digits)
17
 * - At the end of the representation of one property, there will be a sequence of lower-case
18
 * characters showing which restrictions are imposed on this property (mandatory/unique). The
19
 * order of these is important.
20
 */
21
public class SignatureBuilder
22
{
23
   /** 
24
    * A map statically initialized with the classic JVM data type single-char representation.
25
    * This can also contain other mappings created at the runtime.
26
    */
27
   private static Map<Class<? extends BaseDataType>, Character> typeMapping;
28
   
29
   /** The character used for representing a mandatory property */
30
   private static char CHAR_MANDANTORY = 'm';
31

  
32
   /** The character used for representing a unique property */
33
   private static char CHAR_UNIQUE = 'u';
34
   
35
   /** Logger */
36
   private static final Logger LOG = LogHelper.getLogger(SignatureBuilder.class.getName());
37
   
38
   /** Static initialization of the type mapping */
39
   static 
40
   {
41
      typeMapping = new IdentityHashMap<>();
42

  
43
      typeMapping.put(character.class, 'C');
44
      typeMapping.put(decimal.class, 'F');
45
      typeMapping.put(integer.class, 'I');
46
      typeMapping.put(int64.class, 'J');
47
      typeMapping.put(logical.class, 'Z');
48
   }
49
   
50
   /**
51
    * This builds a string which structurally represents a DMO. The DMOs which are compatible,
52
    * from strcture's point of view, should have the same signature. This is useful for quickly
53
    * checking compatibility (example: copy-temp-table).
54
    * 
55
    * @param   it
56
    *          An iterator to the whole collection of properties for the processed DMO.
57
    * @param   uniqueProperties
58
    *          A set of properties which are unique. These should be flagged in the signature.
59
    * @return  A string representing the signature for a DMO having the specified properties..
60
    */
61
   static String buildSignature(Iterator<Property> it, Set<Property> uniqueProperties)
62
   {
63
      StringBuilder sb = new StringBuilder();
64
      
65
      TypeIdentifierProvider findSuitableCandidate = (type) -> 
66
      {
67
         Set<Character> values = new HashSet<Character>(typeMapping.values());
68
         for (char raw : type.getName().toCharArray())
69
         {
70
            char candidate = Character.toUpperCase(raw);
71
            if (!values.contains(candidate))
72
            {
73
               typeMapping.put(type, candidate);
74
               return candidate;
75
            }
76
         }
77
         return null;
78
      };
79
      
80
      TypeIdentifierProvider findAnyCandidate = (type) -> 
81
      {
82
         Set<Character> values = new HashSet<Character>(typeMapping.values());
83
         for (char candidate = 'A'; candidate <= 'Z'; candidate++)
84
         {
85
            if (!values.contains(candidate))
86
            {
87
               typeMapping.put(type, candidate);
88
               return candidate;
89
            }
90
         }
91
         return null;
92
      };
93
      
94
      while (it.hasNext())
95
      {
96
         Property prop = it.next();
97
         Class<? extends BaseDataType> type = (Class<? extends BaseDataType>) prop._fwdType;
98
         Character ch = typeMapping.get(type);
99
         if (ch == null)
100
         {
101
            // for this kind of situations, find a suitable representation for this type
102
            ch = findSuitableCandidate.provide(type);
103
         }
104
         if (ch == null)
105
         {
106
            // can't find a suitable representation, assign a random character
107
            ch = findAnyCandidate.provide(type);
108
         }
109
         if (ch == null)
110
         {
111
            if (LOG.isLoggable(Level.WARNING))
112
            {
113
               LOG.log(Level.WARNING, "Couldn't find a character representation for " + type.getName());
114
            }
115
            return null;
116
         }
117
         
118
         sb.append(ch);
119
         
120
         int extent = prop.extent;
121
         if (extent > 0)
122
         {
123
            sb.append(extent);
124
         }
125
         
126
         processFieldRestrictions(prop, uniqueProperties.contains(prop), sb);
127
      }
128
      
129
      return sb.toString();
130
   }
131
   
132
   /**
133
    * Helper which sets restrictions like mandatory or unique to a specified field.
134
    * 
135
    * @param   prop
136
    *          The property for which the restriction analysis is done.
137
    * @param   unique
138
    *          A flag which indicates that the property should be unique.
139
    * @param   sb
140
    *          The string builder which should be completed with the found restrictions.
141
    */
142
   private static void processFieldRestrictions(Property prop, 
143
                                                boolean unique,
144
                                                StringBuilder sb)
145
   {
146
      if (prop.mandatory)
147
      {
148
         sb.append(CHAR_MANDANTORY);
149
      }
150
      
151
      if (unique)
152
      {
153
         sb.append(CHAR_UNIQUE);
154
      }
155
   }
156
   
157
   /**
158
    * Helper for anonymous functions used in identifying a suitable character for a specified data type. 
159
    */
160
   interface TypeIdentifierProvider 
161
   {
162
      Character provide(Class<? extends BaseDataType> type);
163
   }
164
}