6129b-6816.patch
new/src/com/goldencode/cache/Cache.java 2023-01-05 10:49:48 +0000 | ||
---|---|---|
11 | 11 |
** ExpiryCache implementation class. Added for-each loop iteration methods keys(), values(), |
12 | 12 |
** and entries(), plus a size() method. |
13 | 13 |
** VVT 20210917 Javadoc fixed. |
14 |
** RAA 20221215 Added computeIfAbsent. |
|
14 | 15 |
*/ |
15 | 16 |
/* |
16 | 17 |
** This program is free software: you can redistribute it and/or modify |
... | ... | |
67 | 68 | |
68 | 69 |
package com.goldencode.cache; |
69 | 70 | |
71 |
import java.util.function.*; |
|
72 | ||
70 | 73 |
/** |
71 | 74 |
* A simple interface for a cache, with a map-like API. |
72 | 75 |
* |
... | ... | |
116 | 119 |
public V putIfAbsent(K key, V value); |
117 | 120 |
|
118 | 121 |
/** |
122 |
* Function which does the following things: |
|
123 |
* 1. First, it checks if the key is present in the cache. |
|
124 |
* If the key is present, and a non-null value is related to the key, then it returns that value. |
|
125 |
* If not (the key is not present or is present, but has a null value related), it moves on to step 2. |
|
126 |
* |
|
127 |
* 2. It attempts to compute the value using the given {@code mappingFunction}. |
|
128 |
* It also enters the calculated value into the map unless the calculated value is null. |
|
129 |
* |
|
130 |
* @param key |
|
131 |
* A hashable key. |
|
132 |
* @param mappingFunction |
|
133 |
* Function that takes one argument and produces a result. |
|
134 |
* That result, unless it is null, is then put in the cache. |
|
135 |
* |
|
136 |
* @return The value at the given key, either directly retrieved or calculated. |
|
137 |
*/ |
|
138 |
public V computeIfAbsent(K key, |
|
139 |
Function<? super K, ? extends V> mappingFunction); |
|
140 |
|
|
141 |
/** |
|
119 | 142 |
* Remove the entry associated with the given key from the cache. |
120 | 143 |
* |
121 | 144 |
* @param key |
new/src/com/goldencode/cache/ExpiryCache.java 2023-01-05 10:49:48 +0000 | ||
---|---|---|
18 | 18 |
** cache grows and subsequent attempts will be made to shrink it back down. Refactored the |
19 | 19 |
** implementation and added methods to give some for-each loop iteration capability. |
20 | 20 |
** OM 20210831 Replaced anonymous classes with equivalent lambdas. |
21 |
* RAA 20221215 Added computeIfAbsent. |
|
21 | 22 |
*/ |
22 | 23 | |
23 | 24 |
/* |
... | ... | |
312 | 313 |
} |
313 | 314 |
|
314 | 315 |
/** |
316 |
* Function which does the following things: |
|
317 |
* 1. First, it checks if the key is present in the cache. |
|
318 |
* If the key is present, and a non-null value is related to the key, then it returns that value. |
|
319 |
* If not (the key is not present or is present, but has a null value related), it moves on to step 2. |
|
320 |
* |
|
321 |
* 2. It attempts to compute the value using the given {@code mappingFunction}. |
|
322 |
* It also enters the calculated value into the map unless the calculated value is null. |
|
323 |
* When the cache is full, before adding another element, it pushes out the least desirable element(s). |
|
324 |
* |
|
325 |
* @param key |
|
326 |
* A hashable key. |
|
327 |
* @param mappingFunction |
|
328 |
* Function that takes one argument and produces a result. |
|
329 |
* That result, unless it is null, is then put in the cache. |
|
330 |
* |
|
331 |
* @return The value at the given key, either directly retrieved or calculated. |
|
332 |
*/ |
|
333 |
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) |
|
334 |
{ |
|
335 |
|
|
336 |
Objects.requireNonNull(mappingFunction); |
|
337 |
V v; |
|
338 |
if ((v = get(key)) == null) |
|
339 |
{ |
|
340 |
V newValue; |
|
341 |
if ((newValue = mappingFunction.apply(key)) != null) |
|
342 |
{ |
|
343 |
put(key, newValue); |
|
344 |
return newValue; |
|
345 |
} |
|
346 |
} |
|
347 | ||
348 |
return v; |
|
349 |
} |
|
350 |
|
|
351 |
/** |
|
315 | 352 |
* Remove the entry associated with the given key from the cache. |
316 | 353 |
* |
317 | 354 |
* @param key |
new/src/com/goldencode/p2j/persist/AdaptiveComponent.java 2023-01-05 11:05:42 +0000 | ||
---|---|---|
21 | 21 |
** CA 20221130 Refactored the WHERE clause translation (when the bound and definition buffers are not the |
22 | 22 |
** same), to be aware of the external buffers (i.e. added for CAN-FIND sub-select clauses). |
23 | 23 |
** The translate will be performed before the query is being executed. |
24 |
** RAA 20230105 Changed how a SortCriterion is generated. It now uses SortCriterionFactory |
|
25 |
** instead of just calling the constructor. |
|
24 | 26 |
*/ |
25 | 27 | |
26 | 28 |
/* |
... | ... | |
430 | 432 |
String alias = getBuffer().getDMOAlias(); |
431 | 433 |
for (SortCriterion criterion : sortCriteria) |
432 | 434 |
{ |
433 |
ret.add(criterion.getAlias().equals(alias) ? criterion : new SortCriterion(criterion, alias)); |
|
435 |
ret.add(criterion.getAlias().equals(alias) ? criterion : |
|
436 |
SortCriterionFactory.getInstance(criterion, alias)); |
|
434 | 437 |
} |
435 | 438 |
|
436 | 439 |
return ret; |
new/src/com/goldencode/p2j/persist/PreselectQuery.java 2023-01-05 11:07:12 +0000 | ||
---|---|---|
596 | 596 |
** are not the same), to be aware of the external buffers (i.e. added for CAN-FIND |
597 | 597 |
** sub-select clauses). The translate will be performed before the query is being |
598 | 598 |
** executed. |
599 |
** RAA 20230105 Changed how a SortCriterion is generated. It now uses SortCriterionFactory |
|
600 |
** instead of just calling the constructor. |
|
599 | 601 |
*/ |
600 | 602 | |
601 | 603 |
/* |
... | ... | |
4944 | 4946 |
} |
4945 | 4947 |
|
4946 | 4948 |
// create the SortCriterion instance and add it to the master list and to the appropriate sub-list |
4947 |
SortCriterion crit = new SortCriterion(buffer, part);
|
|
4949 |
SortCriterion crit = SortCriterionFactory.getInstance(buffer, part);
|
|
4948 | 4950 |
|
4949 | 4951 |
sortCriteria.add(crit); |
4950 | 4952 |
subSortCrit.add(crit); |
... | ... | |
5009 | 5011 |
|
5010 | 5012 |
try |
5011 | 5013 |
{ |
5012 |
workList.add(new SortCriterion(buffer, sb.toString()));
|
|
5014 |
workList.add(SortCriterionFactory.getInstance(buffer, sb.toString()));
|
|
5013 | 5015 |
} |
5014 | 5016 |
catch (PersistenceException exc) |
5015 | 5017 |
{ |
new/src/com/goldencode/p2j/persist/PresortQuery.java 2023-01-05 10:49:48 +0000 | ||
---|---|---|
92 | 92 |
** OM 20201007 Optimized SortCriterion by using DmoMeta data instead of map lookups. |
93 | 93 |
** CA 20210310 A dynamic predicate must set the default lock to NONE, instead of SHARE. |
94 | 94 |
** OM 20220701 Dropped overriding methods which were duplicating code from super class. |
95 |
** RAA 20221215 Changed how a SortCriterion is generated. It now uses SortCriterionFactory |
|
96 |
** instead of just calling the constructor. |
|
95 | 97 |
*/ |
96 | 98 | |
97 | 99 |
/* |
... | ... | |
961 | 963 |
while (iter.hasNext()) |
962 | 964 |
{ |
963 | 965 |
RecordBuffer buffer = iter.next().getBuffer(); |
964 |
SortCriterion crit = new SortCriterion(
|
|
966 |
SortCriterion crit = SortCriterionFactory.getInstance(
|
|
965 | 967 |
buffer, buffer.getDMOAlias() + "." + DatabaseManager.PRIMARY_KEY + " asc"); |
966 | 968 |
sortCriteria.add(crit); |
967 | 969 |
} |
new/src/com/goldencode/p2j/persist/SortCriterion.java 2023-01-05 11:09:26 +0000 | ||
---|---|---|
98 | 98 |
** AL2 20220706 Added isCompatible to filter out the sort clauses not belonging to the buffer. |
99 | 99 |
** OM 20220727 FieldId and PropertyId are different for denormalized extent fields. |
100 | 100 |
** OM 20221103 New class names for FQLPreprocessor, FQLExpression, FQLBundle, and FQLCache. |
101 |
** RAA 20221213 Added a cache for storing the result of toSortExpression() method. |
|
102 |
** RAA 20221215 Changed how a SortCriterion is generated. It now uses SortCriterionFactory |
|
103 |
** instead of just calling the constructor. |
|
101 | 104 |
*/ |
102 | 105 | |
103 | 106 |
/* |
... | ... | |
225 | 228 |
/** Lock for cache */ |
226 | 229 |
private static final Object cacheLock = new Object(); |
227 | 230 |
|
231 |
/** Cache for storing the result of {@code toSortExpression} method. */ |
|
232 |
private final Vector<String> toStringCache; |
|
233 |
|
|
228 | 234 |
/** <code>true</code> if sort is ascending, else it is descending */ |
229 | 235 |
private final boolean ascending; |
230 | 236 |
|
... | ... | |
253 | 259 |
private final String originalName; |
254 | 260 |
|
255 | 261 |
/** Sort property name, usually qualified */ |
256 |
private String name; |
|
262 |
private final String name;
|
|
257 | 263 |
|
258 | 264 |
/** Subscript value, if any */ |
259 |
private int subscript = -1;
|
|
265 |
private final int subscript;
|
|
260 | 266 |
|
261 | 267 |
/** SQL dialect which used this sort criterion; used for rtrim calls on character properties */ |
262 |
private Dialect dialect = null;
|
|
268 |
private final Dialect dialect;
|
|
263 | 269 |
|
264 | 270 |
/** |
265 | 271 |
* Constructor which parses original sort component text, deriving the property name, sort |
... | ... | |
347 | 353 |
// parse the test and extract alias, property and optional extent |
348 | 354 |
int spacePos = text.indexOf(' '); |
349 | 355 |
String rawName = ((spacePos != -1) ? text.substring(0, spacePos) : text).trim(); |
350 |
name = rawName;
|
|
356 |
String actualName = rawName;
|
|
351 | 357 |
originalName = internStrings ? rawName.intern() : rawName; |
352 | 358 |
int bracketPos = rawName.indexOf("["); |
353 | 359 |
int endPos = -1; |
360 |
int actualSubscript = -1; |
|
354 | 361 |
if (bracketPos >= 0) |
355 | 362 |
{ |
356 | 363 |
endPos = rawName.indexOf("]"); |
... | ... | |
360 | 367 |
} |
361 | 368 |
|
362 | 369 |
// extract base name |
363 |
name = rawName.substring(0, bracketPos);
|
|
370 |
actualName = rawName.substring(0, bracketPos);
|
|
364 | 371 |
} |
365 | 372 |
|
366 |
int dotPos = name.lastIndexOf(".");
|
|
373 |
int dotPos = actualName.lastIndexOf(".");
|
|
367 | 374 |
if (dotPos < 0) |
368 | 375 |
{ |
369 | 376 |
throw new PersistenceException("Sort property may not be unqualified: " + rawName); |
370 | 377 |
} |
371 | 378 |
|
372 |
String propName = name.substring(dotPos + 1);
|
|
373 |
String alias = name.substring(0, dotPos);
|
|
379 |
String propName = actualName.substring(dotPos + 1);
|
|
380 |
String alias = actualName.substring(0, dotPos);
|
|
374 | 381 |
DmoMeta dmoMeta = DmoMetadataManager.getDmoInfo(dmoClass); |
375 | 382 |
Property propMeta = dmoMeta.getFieldInfo(propName); |
376 | 383 |
this.propertyName = propMeta.name; // already interned, anyway |
... | ... | |
385 | 392 |
String sub = rawName.substring(bracketPos + 1, endPos); |
386 | 393 |
try |
387 | 394 |
{ |
388 |
subscript = Integer.parseInt(sub);
|
|
395 |
actualSubscript = Integer.parseInt(sub);
|
|
389 | 396 |
} |
390 | 397 |
catch (NumberFormatException exc) |
391 | 398 |
{ |
392 | 399 |
throw new PersistenceException("Unsupported subscript: " + sub); |
393 | 400 |
} |
394 | 401 |
|
395 |
name = alias + "." + propertyName;
|
|
402 |
actualName = alias + "." + propertyName;
|
|
396 | 403 |
} |
397 | 404 |
} |
398 | 405 |
|
399 | 406 |
if (internStrings) |
400 | 407 |
{ |
401 |
name = name.intern();
|
|
408 |
actualName = actualName.intern();
|
|
402 | 409 |
} |
403 | 410 |
|
404 | 411 |
// determine sort direction |
... | ... | |
448 | 455 |
ignoreCase = isCharacter && !caseSens; |
449 | 456 |
computedColumnPrefix = ccPrefix; |
450 | 457 |
} |
458 |
|
|
459 |
name = actualName; |
|
460 |
subscript = actualSubscript; |
|
461 |
toStringCache = new Vector<>(16); |
|
462 |
toStringCache.setSize(16); |
|
451 | 463 |
} |
452 | 464 |
|
453 | 465 |
/** |
... | ... | |
475 | 487 |
this.originalName = other.originalName; |
476 | 488 |
this.name = alias + "." + propertyName + |
477 | 489 |
(subscript < 0 ? "" : "[" + subscript + "]") + (ascending ? " asc" : " desc"); |
490 |
toStringCache = new Vector<>(16); |
|
491 |
toStringCache.setSize(16); |
|
478 | 492 |
} |
479 | 493 |
|
480 | 494 |
/** |
... | ... | |
565 | 579 |
continue; |
566 | 580 |
} |
567 | 581 |
|
568 |
next = new SortCriterion(dialect, sortComp.trim(), dmoInfo);
|
|
582 |
next = SortCriterionFactory.getInstance(dialect, sortComp.trim(), dmoInfo);
|
|
569 | 583 |
sortCriteria.add(next); |
570 | 584 |
sortNames.add(next.getUnqualifiedName()); |
571 | 585 |
} |
... | ... | |
582 | 596 |
if (makeUnique && !sortNames.contains(DatabaseManager.PRIMARY_KEY)) |
583 | 597 |
{ |
584 | 598 |
String sortComp = dmoAlias + "." + DatabaseManager.PRIMARY_KEY + " " + (pKeyAscend ? "asc" : "desc"); |
585 |
sortCriteria.add(new SortCriterion(dialect, sortComp, dmoInfo));
|
|
599 |
sortCriteria.add(SortCriterionFactory.getInstance(dialect, sortComp, dmoInfo));
|
|
586 | 600 |
} |
587 | 601 |
|
588 | 602 |
// eliminate superfluous sort components if sort criteria define a superset of a unique |
... | ... | |
930 | 944 |
// ASC: ASC + NULLS LAST (CASE WHEN [Order] IS NULL THEN 1 ELSE 0 END), [Order] ASC |
931 | 945 |
// DESC: DESC + NULLS FIRST (CASE WHEN [Order] IS NULL THEN 0 ELSE 1 END), [Order] DESC |
932 | 946 |
|
947 |
int cacheKey = 0; |
|
948 |
cacheKey += (invert ? 1 << 3 : 0); |
|
949 |
cacheKey += (useTableAlias ? 1 << 2 : 0); |
|
950 |
cacheKey += (uniqueAlias ? 1 << 1 : 0); |
|
951 |
cacheKey += (doSpecificProcessing ? 1 : 0); |
|
952 |
String cacheResult = null; |
|
953 |
cacheResult = toStringCache.get(cacheKey); |
|
954 |
|
|
955 |
if (cacheResult != null) |
|
956 |
{ |
|
957 |
return cacheResult; |
|
958 |
} |
|
959 |
|
|
933 | 960 |
boolean mssqlFix = dialect instanceof P2JSQLServer2008Dialect; |
934 | 961 |
StringBuilder buf = new StringBuilder(); |
935 | 962 |
StringBuilder sortExpr = mssqlFix ? new StringBuilder() : null; |
... | ... | |
983 | 1010 |
buf.append(ascending ? "asc" : "desc"); |
984 | 1011 |
} |
985 | 1012 |
|
986 |
return buf.toString(); |
|
1013 |
String result = buf.toString(); |
|
1014 |
toStringCache.setElementAt(result, cacheKey); |
|
1015 |
return result; |
|
987 | 1016 |
} |
988 | 1017 |
|
989 | 1018 |
/** |
new/src/com/goldencode/p2j/persist/SortCriterionFactory.java 2023-01-05 10:49:48 +0000 | ||
---|---|---|
1 |
/* |
|
2 |
** Module : SortCriterionFactory.java |
|
3 |
** Abstract : Factory for an object which encapsulates a single "order by" sort criterion |
|
4 |
** |
|
5 |
** Copyright (c) 2004-2022, Golden Code Development Corporation. |
|
6 |
** |
|
7 |
** -#- -I- --Date-- --JPRM-- -----------------------------------Description----------------------------------- |
|
8 |
** 001 RAA 20221214 Created initial version. |
|
9 |
*/ |
|
10 | ||
11 |
/* |
|
12 |
** This program is free software: you can redistribute it and/or modify |
|
13 |
** it under the terms of the GNU Affero General Public License as |
|
14 |
** published by the Free Software Foundation, either version 3 of the |
|
15 |
** License, or (at your option) any later version. |
|
16 |
** |
|
17 |
** This program is distributed in the hope that it will be useful, |
|
18 |
** but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
19 |
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
20 |
** GNU Affero General Public License for more details. |
|
21 |
** |
|
22 |
** You may find a copy of the GNU Affero GPL version 3 at the following |
|
23 |
** location: https://www.gnu.org/licenses/agpl-3.0.en.html |
|
24 |
** |
|
25 |
** Additional terms under GNU Affero GPL version 3 section 7: |
|
26 |
** |
|
27 |
** Under Section 7 of the GNU Affero GPL version 3, the following additional |
|
28 |
** terms apply to the works covered under the License. These additional terms |
|
29 |
** are non-permissive additional terms allowed under Section 7 of the GNU |
|
30 |
** Affero GPL version 3 and may not be removed by you. |
|
31 |
** |
|
32 |
** 0. Attribution Requirement. |
|
33 |
** |
|
34 |
** You must preserve all legal notices or author attributions in the covered |
|
35 |
** work or Appropriate Legal Notices displayed by works containing the covered |
|
36 |
** work. You may not remove from the covered work any author or developer |
|
37 |
** credit already included within the covered work. |
|
38 |
** |
|
39 |
** 1. No License To Use Trademarks. |
|
40 |
** |
|
41 |
** This license does not grant any license or rights to use the trademarks |
|
42 |
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks |
|
43 |
** of Golden Code Development Corporation. You are not authorized to use the |
|
44 |
** name Golden Code, FWD, or the names of any author or contributor, for |
|
45 |
** publicity purposes without written authorization. |
|
46 |
** |
|
47 |
** 2. No Misrepresentation of Affiliation. |
|
48 |
** |
|
49 |
** You may not represent yourself as Golden Code Development Corporation or FWD. |
|
50 |
** |
|
51 |
** You may not represent yourself for publicity purposes as associated with |
|
52 |
** Golden Code Development Corporation, FWD, or any author or contributor to |
|
53 |
** the covered work, without written authorization. |
|
54 |
** |
|
55 |
** 3. No Misrepresentation of Source or Origin. |
|
56 |
** |
|
57 |
** You may not represent the covered work as solely your work. All modified |
|
58 |
** versions of the covered work must be marked in a reasonable way to make it |
|
59 |
** clear that the modified work is not originating from Golden Code Development |
|
60 |
** Corporation or FWD. All modified versions must contain the notices of |
|
61 |
** attribution required in this license. |
|
62 |
*/ |
|
63 | ||
64 |
package com.goldencode.p2j.persist; |
|
65 | ||
66 |
import java.util.logging.*; |
|
67 | ||
68 |
import com.goldencode.cache.*; |
|
69 |
import com.goldencode.p2j.persist.dialect.*; |
|
70 |
import com.goldencode.p2j.persist.orm.*; |
|
71 |
import com.goldencode.p2j.util.*; |
|
72 | ||
73 |
/** |
|
74 |
* Factory design pattern for a {@link SortCriterion}. Its purpose is to quickly retrieve an already created |
|
75 |
* {@code SortCriterion}. If that does not happen, the instance is created and then stored in cache. |
|
76 |
*/ |
|
77 |
public final class SortCriterionFactory |
|
78 |
{ |
|
79 |
/** Logger for {@code SortCriterionFactory}. */ |
|
80 |
private static final Logger log = LogHelper.getLogger(SortCriterionFactory.class.getName()); |
|
81 |
|
|
82 |
/** Cache for quickly returning an already created {@code SortCriterion}. */ |
|
83 |
static final Cache<Key, SortCriterion> cache = new LRUCache<>(2048); |
|
84 |
|
|
85 |
/** |
|
86 |
* Function which simulates the behavior of the {@link SortCriterion} constructor with |
|
87 |
* {@link RecordBuffer} and {@code String} parameters. |
|
88 |
* |
|
89 |
* It is strongly advised to use this function because the instance has a chance to be retrieved |
|
90 |
* from cache, meaning that it would be faster than creating a new one. |
|
91 |
* |
|
92 |
* @param buffer |
|
93 |
* Record buffer. |
|
94 |
* @param text |
|
95 |
* Text representation of sort component, as provided by query. |
|
96 |
* |
|
97 |
* @return The instance of the requested {@code SortCriterion}. |
|
98 |
*/ |
|
99 |
static SortCriterion getInstance(RecordBuffer buffer, String text) |
|
100 |
throws PersistenceException |
|
101 |
{ |
|
102 |
return getInstance(buffer.getDialect(), text, buffer.getDmoInfo(), false); |
|
103 |
} |
|
104 |
|
|
105 |
/** |
|
106 |
* Function which simulates the behavior of the {@link SortCriterion} constructor with |
|
107 |
* {@link Dialect}, {@code String} and {@link DmoMeta} parameters. |
|
108 |
* |
|
109 |
* It is strongly advised to use this function because the instance has a chance to be retrieved |
|
110 |
* from cache, meaning that it would be faster than creating a new one. |
|
111 |
* |
|
112 |
* @param dialect |
|
113 |
* Database dialect. |
|
114 |
* @param text |
|
115 |
* Text representation of sort component, as provided by query. |
|
116 |
* @param dmoInfo |
|
117 |
* Metadata for the table. |
|
118 |
* |
|
119 |
* @return The instance of the requested {@code SortCriterion}. |
|
120 |
*/ |
|
121 |
static SortCriterion getInstance(Dialect dialect, String text, DmoMeta dmoInfo) |
|
122 |
throws PersistenceException |
|
123 |
{ |
|
124 |
return getInstance(dialect, text, dmoInfo, true); |
|
125 |
} |
|
126 |
|
|
127 |
/** |
|
128 |
* Function which simulates the behavior of the {@link SortCriterion} constructor with |
|
129 |
* {@link Dialect}, {@code String}, {@link DmoMeta} and {@code boolean} parameters. |
|
130 |
* |
|
131 |
* It is strongly advised to use this function because the instance has a chance to be retrieved |
|
132 |
* from cache, meaning that it would be faster than creating a new one. |
|
133 |
* |
|
134 |
* @param dialect |
|
135 |
* Database dialect. |
|
136 |
* @param text |
|
137 |
* Text representation of sort component, as provided by query. |
|
138 |
* @param dmoInfo |
|
139 |
* Metadata for the table. |
|
140 |
* @param internStrings |
|
141 |
* {@code true} to intern string fields, else {@code false}. |
|
142 |
* |
|
143 |
* @return The instance of the requested {@code SortCriterion}. |
|
144 |
*/ |
|
145 |
static SortCriterion getInstance(Dialect dialect, String text, |
|
146 |
DmoMeta dmoInfo, boolean internStrings) |
|
147 |
throws PersistenceException |
|
148 |
{ |
|
149 |
Key key = new Key(dialect, text, dmoInfo, internStrings); |
|
150 |
synchronized (cache) |
|
151 |
{ |
|
152 |
return cache.computeIfAbsent(key, k -> { |
|
153 |
try |
|
154 |
{ |
|
155 |
return new SortCriterion(dialect, text, dmoInfo, internStrings); |
|
156 |
} |
|
157 |
catch (PersistenceException e) |
|
158 |
{ |
|
159 |
if (log.isLoggable(Level.WARNING)) |
|
160 |
{ |
|
161 |
log.log(Level.WARNING, "Could not create a new SortCriterion", e); |
|
162 |
} |
|
163 |
} |
|
164 |
|
|
165 |
return null; |
|
166 |
}); |
|
167 |
} |
|
168 |
} |
|
169 |
|
|
170 |
/** |
|
171 |
* Function which simulates the behavior of the {@link SortCriterion} constructor with |
|
172 |
* {@code SortCriterion} and {@code String} parameters. |
|
173 |
* |
|
174 |
* There are two reasons as to why this method does not involve caching: |
|
175 |
* 1. It is rarely used. |
|
176 |
* 2. Adding another element to the cache key (alias) and storing multiple {@code SortCriterion} with |
|
177 |
* just different aliases might provide more negative than positive aspects. It would make the |
|
178 |
* common cases (>95%) more difficult to obtain and the ones that are rarer easier to find. |
|
179 |
* |
|
180 |
* @param other |
|
181 |
* The source {@code SortCriterion} to copy. |
|
182 |
* @param alias |
|
183 |
* The new alias to be used. |
|
184 |
* |
|
185 |
* @return The instance of the requested {@code SortCriterion}. |
|
186 |
*/ |
|
187 |
static SortCriterion getInstance(SortCriterion other, String alias) |
|
188 |
{ |
|
189 |
return new SortCriterion(other, alias); |
|
190 |
} |
|
191 |
|
|
192 |
/** |
|
193 |
* Key for cached {@code SortCriterion}s. |
|
194 |
*/ |
|
195 |
private static class Key |
|
196 |
{ |
|
197 |
/** Database dialect. */ |
|
198 |
private final Dialect dialect; |
|
199 |
|
|
200 |
/** Text representation of sort component, as provided by query. */ |
|
201 |
private final String text; |
|
202 |
|
|
203 |
/** Metadata for the table. */ |
|
204 |
private final DmoMeta dmoInfo; |
|
205 |
|
|
206 |
/** Database dialect. */ |
|
207 |
private final boolean internStrings; |
|
208 |
|
|
209 |
/** {@code true} to intern string fields, else {@code false}. */ |
|
210 |
private final int hashCode; |
|
211 |
|
|
212 |
/** |
|
213 |
* Constructor. |
|
214 |
* |
|
215 |
* @param dialect |
|
216 |
* Database dialect. |
|
217 |
* @param text |
|
218 |
* Text representation of sort component, as provided by query. |
|
219 |
* @param dmoInfo |
|
220 |
* Metadata for the table. |
|
221 |
* @param internStrings |
|
222 |
* {@code true} to intern string fields, else {@code false}. |
|
223 |
*/ |
|
224 |
Key(Dialect dialect, String text, DmoMeta dmoInfo, boolean internStrings) |
|
225 |
{ |
|
226 |
this.dialect = dialect; |
|
227 |
this.text = text; |
|
228 |
this.dmoInfo = dmoInfo; |
|
229 |
this.internStrings = internStrings; |
|
230 |
|
|
231 |
int result = 17; |
|
232 |
result = 37 * result + (dialect == null ? 0 : dialect.hashCode()); |
|
233 |
result = 37 * result + (text == null ? 0 : text.hashCode()); |
|
234 |
result = 37 * result + (dmoInfo == null ? 0 : dmoInfo.hashCode()); |
|
235 |
result = 37 * result + (internStrings == false ? 0 : 1); |
|
236 |
|
|
237 |
this.hashCode = result; |
|
238 |
} |
|
239 |
|
|
240 |
/** |
|
241 |
* Override of the default hash code algorithm. Consistent with {@link #equals(Object)}. |
|
242 |
* |
|
243 |
* @return Hash code. |
|
244 |
*/ |
|
245 |
@Override |
|
246 |
public int hashCode() |
|
247 |
{ |
|
248 |
return hashCode; |
|
249 |
} |
|
250 |
|
|
251 |
/** |
|
252 |
* Override of the default equivalence algorithm. Consistent with {@link #hashCode()}. |
|
253 |
* |
|
254 |
* return {@code true} if this object is equivalent to the given object, else {@code |
|
255 |
* false}. |
|
256 |
*/ |
|
257 |
@Override |
|
258 |
public boolean equals(Object o) |
|
259 |
{ |
|
260 |
if (!(o instanceof Key)) |
|
261 |
{ |
|
262 |
return false; |
|
263 |
} |
|
264 |
|
|
265 |
Key that = (Key) o; |
|
266 |
if (this.dialect != that.dialect) |
|
267 |
{ |
|
268 |
return false; |
|
269 |
} |
|
270 |
|
|
271 |
if ((this.text == null && that.text != null) || |
|
272 |
(this.text != null && that.text == null) || |
|
273 |
(!this.text.equals(that.text))) |
|
274 |
{ |
|
275 |
return false; |
|
276 |
} |
|
277 |
|
|
278 |
if (this.dmoInfo != that.dmoInfo) |
|
279 |
{ |
|
280 |
return false; |
|
281 |
} |
|
282 |
|
|
283 |
if (this.internStrings != that.internStrings) |
|
284 |
{ |
|
285 |
return false; |
|
286 |
} |
|
287 |
|
|
288 |
return true; |
|
289 |
} |
|
290 |
} |
|
291 |
} |