1
|
/**
|
2
|
*
|
3
|
*/
|
4
|
package eu.etaxonomy.cdm.persistence.dao.initializer;
|
5
|
|
6
|
import java.io.Serializable;
|
7
|
import java.util.ArrayList;
|
8
|
import java.util.Collection;
|
9
|
import java.util.Collections;
|
10
|
import java.util.HashMap;
|
11
|
import java.util.HashSet;
|
12
|
import java.util.List;
|
13
|
import java.util.Map;
|
14
|
import java.util.Set;
|
15
|
|
16
|
import org.apache.commons.lang.StringUtils;
|
17
|
import org.hibernate.collection.internal.AbstractPersistentCollection;
|
18
|
|
19
|
import eu.etaxonomy.cdm.common.CdmUtils;
|
20
|
|
21
|
/**
|
22
|
* @author a.mueller
|
23
|
* @since 2013-10-25
|
24
|
*/
|
25
|
public class BeanInitNode implements Comparable<BeanInitNode>{
|
26
|
|
27
|
// ************************ ATTRIBUTES *******************************/
|
28
|
|
29
|
private final BeanInitNode parent;
|
30
|
|
31
|
private final Map<String, BeanInitNode> children = new HashMap<String, BeanInitNode>();
|
32
|
|
33
|
private final String path;
|
34
|
|
35
|
private boolean isToManyInitialized = false;
|
36
|
|
37
|
private boolean isToOneInitialized = false;
|
38
|
|
39
|
private BeanInitNode wildcardChildCache;
|
40
|
|
41
|
|
42
|
private final Map<Class<?>, Set<Object>> beans = new HashMap<Class<?>, Set<Object>>();
|
43
|
|
44
|
private final Map<Class<?>, Set<Serializable>> lazyBeans = new HashMap<Class<?>, Set<Serializable>>();
|
45
|
|
46
|
private final Map<Class<?>, Map<String, Set<Serializable>>> lazyCollections = new HashMap<Class<?>, Map<String,Set<Serializable>>>();
|
47
|
|
48
|
//java.util.Set is not possible here to avoid initializing of collection during .add()
|
49
|
private final List<AbstractPersistentCollection> uninitializedCollections = new ArrayList<AbstractPersistentCollection>();
|
50
|
|
51
|
// *************************** STATIC METHODS *****************************************/
|
52
|
|
53
|
public static BeanInitNode createInitTree(List<String> propertyPaths) {
|
54
|
|
55
|
//sort paths //TODO needed?
|
56
|
Collections.sort(propertyPaths);
|
57
|
|
58
|
BeanInitNode root = new BeanInitNode(null, "");
|
59
|
|
60
|
for (String fullPath : propertyPaths){
|
61
|
String[] parts = fullPath.split("\\.");
|
62
|
BeanInitNode lastNode = root;
|
63
|
for (String part : parts){
|
64
|
BeanInitNode child = lastNode.children.get(part);
|
65
|
if (child == null){
|
66
|
child = new BeanInitNode(lastNode, part);
|
67
|
}
|
68
|
lastNode = child;
|
69
|
}
|
70
|
}
|
71
|
|
72
|
return root;
|
73
|
}
|
74
|
|
75
|
private static boolean isWildcard(String pathPart) {
|
76
|
return pathPart.equals(AbstractBeanInitializer.LOAD_2ONE_WILDCARD) ||
|
77
|
pathPart.equals(AbstractBeanInitializer.LOAD_2ONE_2MANY_WILDCARD);
|
78
|
}
|
79
|
|
80
|
|
81
|
//***************************** CONSTRUCTOR RELATED ****************************************/
|
82
|
|
83
|
public BeanInitNode(BeanInitNode parent, String part) {
|
84
|
this.path = CdmUtils.Nz(part);
|
85
|
this.parent = parent;
|
86
|
this.isToManyInitialized = this.path.equals(AbstractBeanInitializer.LOAD_2ONE_2MANY_WILDCARD);
|
87
|
this.isToOneInitialized = this.path.equals(AbstractBeanInitializer.LOAD_2ONE_WILDCARD) || this.isToManyInitialized;
|
88
|
if (parent != null){
|
89
|
parent.addChild(part, this);
|
90
|
}
|
91
|
}
|
92
|
|
93
|
private void addChild(String part, BeanInitNode child) {
|
94
|
children.put(part, child);
|
95
|
if (child.isWildcard()){
|
96
|
//set wildcard child if not exists or if child is stronger then existing wildcard child
|
97
|
if (this.wildcardChildCache == null || (! this.wildcardChildCache.isToManyInitialized) && child.isToManyInitialized ){
|
98
|
this.wildcardChildCache = child;
|
99
|
}
|
100
|
}
|
101
|
}
|
102
|
|
103
|
// ************************** ***********************************************************/
|
104
|
|
105
|
public BeanInitNode getChild(String param){
|
106
|
return children.get(param);
|
107
|
}
|
108
|
|
109
|
|
110
|
|
111
|
public List<BeanInitNode> getChildrenList() {
|
112
|
List<BeanInitNode> result = new ArrayList<BeanInitNode>(children.values());
|
113
|
Collections.sort(result);
|
114
|
return result;
|
115
|
}
|
116
|
|
117
|
public BeanInitNode getSibling(String param) {
|
118
|
if (getPath().equals(param) || parent == null){
|
119
|
return null;
|
120
|
}else{
|
121
|
return parent.getChild(param);
|
122
|
}
|
123
|
}
|
124
|
|
125
|
public String getPath() {
|
126
|
return path;
|
127
|
}
|
128
|
|
129
|
public boolean isRoot() {
|
130
|
return StringUtils.isBlank(path);
|
131
|
}
|
132
|
|
133
|
public boolean hasChildren() {
|
134
|
return children.size() > 0;
|
135
|
}
|
136
|
|
137
|
public BeanInitNode getWildcardChild(){
|
138
|
return this.wildcardChildCache;
|
139
|
}
|
140
|
public boolean isWildcard() {
|
141
|
return this.isToManyInitialized || this.isToOneInitialized;
|
142
|
}
|
143
|
public boolean hasWildcardChild() {
|
144
|
return this.wildcardChildCache != null;
|
145
|
}
|
146
|
public boolean hasToManyWildcardChild() {
|
147
|
return this.wildcardChildCache != null;
|
148
|
}
|
149
|
|
150
|
public boolean hasWildcardToManySibling() {
|
151
|
BeanInitNode sibl = getWildcardSibling();
|
152
|
return (sibl != null && sibl.isToManyInitialized);
|
153
|
}
|
154
|
|
155
|
private BeanInitNode getWildcardSibling() {
|
156
|
if (!isWildcard() && parent == null){
|
157
|
return parent.getWildcardChild();
|
158
|
}else{
|
159
|
return null;
|
160
|
}
|
161
|
}
|
162
|
|
163
|
|
164
|
public boolean isToManyWildcard() {
|
165
|
return path.equals(AbstractBeanInitializer.LOAD_2ONE_2MANY_WILDCARD);
|
166
|
}
|
167
|
|
168
|
|
169
|
// ******************* LAZY COLLECTION *****************************************/
|
170
|
|
171
|
public void putLazyCollection(AbstractPersistentCollection collection) {
|
172
|
String role = collection.getRole();
|
173
|
String parameter = role.substring(role.lastIndexOf(".") + 1);
|
174
|
//for embeddable classes we need also the parent parameter
|
175
|
//TODO also allow recursive embedding
|
176
|
String parentRole = role.substring(0, role.lastIndexOf("."));
|
177
|
String parentParameter = parentRole.substring(parentRole.lastIndexOf(".") + 1);
|
178
|
Class<?> ownerClass = collection.getOwner().getClass();
|
179
|
if (Character.isLowerCase(parentParameter.charAt(0))){
|
180
|
parameter = parentParameter + "." + parameter;
|
181
|
}
|
182
|
putLazyCollection(ownerClass, parameter, collection.getKey());
|
183
|
this.uninitializedCollections.add(collection);
|
184
|
}
|
185
|
|
186
|
private void putLazyCollection(Class<?> ownerClazz, String parameter, Serializable id) {
|
187
|
if (ownerClazz != null && parameter != null && id != null){
|
188
|
Map<String, Set<Serializable>> lazyParams = lazyCollections.get(ownerClazz);
|
189
|
if (lazyParams == null){
|
190
|
lazyParams = new HashMap<String, Set<Serializable>>();
|
191
|
lazyCollections.put(ownerClazz, lazyParams);
|
192
|
}
|
193
|
Set<Serializable> layzIds = lazyParams.get(parameter);
|
194
|
if (layzIds == null){
|
195
|
layzIds = new HashSet<Serializable>();
|
196
|
lazyParams.put(parameter, layzIds);
|
197
|
}
|
198
|
layzIds.add(id);
|
199
|
}else{
|
200
|
throw new IllegalArgumentException("Class, parameter and id should not be null");
|
201
|
}
|
202
|
}
|
203
|
public Map<Class<?>, Map<String, Set<Serializable>>> getLazyCollections(){
|
204
|
return this.lazyCollections;
|
205
|
}
|
206
|
public List<AbstractPersistentCollection> getUninitializedCollections(){
|
207
|
return this.uninitializedCollections;
|
208
|
}
|
209
|
public void resetLazyCollections(){
|
210
|
this.lazyCollections.clear();
|
211
|
this.uninitializedCollections.clear();
|
212
|
}
|
213
|
|
214
|
|
215
|
// ******************* LAZY BEAN *****************************************/
|
216
|
|
217
|
public void putLazyBean(Class<?> clazz, Serializable id) {
|
218
|
if (clazz != null && id != null){
|
219
|
Set<Serializable> classedLazies= lazyBeans.get(clazz);
|
220
|
if (classedLazies == null){
|
221
|
classedLazies = new HashSet<Serializable>();
|
222
|
lazyBeans.put(clazz, classedLazies);
|
223
|
}
|
224
|
classedLazies.add(id);
|
225
|
}else{
|
226
|
throw new IllegalArgumentException("Class and id should not be null");
|
227
|
}
|
228
|
}
|
229
|
public Map<Class<?>, Set<Serializable>> getLazyBeans(){
|
230
|
return this.lazyBeans;
|
231
|
}
|
232
|
public void resetLazyBeans(){
|
233
|
this.lazyBeans.clear();
|
234
|
}
|
235
|
|
236
|
// ********************* BEANS ******************************/
|
237
|
|
238
|
private Map<Class<?>, Set<Object>> getClassedBeans(){
|
239
|
return this.beans;
|
240
|
}
|
241
|
|
242
|
|
243
|
/**
|
244
|
* Returns beans represented by this node, split into implementing
|
245
|
* classes.
|
246
|
* @return
|
247
|
*/
|
248
|
public Map<Class<?>, Set<Object>> getBeans() {
|
249
|
return this.beans;
|
250
|
}
|
251
|
|
252
|
public Map<Class<?>, Set<Object>> getParentBeans() {
|
253
|
if (parent == null){
|
254
|
return new HashMap<Class<?>, Set<Object>>();
|
255
|
}else{
|
256
|
return parent.getClassedBeans();
|
257
|
}
|
258
|
}
|
259
|
|
260
|
/**
|
261
|
* Add a bean represented by this node
|
262
|
* @param bean
|
263
|
*/
|
264
|
public void addBean(Object bean) {
|
265
|
if (! isWildcard()){
|
266
|
if (bean != null){
|
267
|
Class<?> key = bean.getClass();
|
268
|
Set<Object> classedBeans = beans.get(key);
|
269
|
if (classedBeans == null){
|
270
|
classedBeans = new HashSet<Object>();
|
271
|
beans.put(key, classedBeans);
|
272
|
}
|
273
|
classedBeans.add(bean);
|
274
|
}
|
275
|
}
|
276
|
}
|
277
|
/**
|
278
|
* Adds beans represented by this node
|
279
|
* @param beans a collection of beans to be added
|
280
|
*/
|
281
|
public void addBeans(Collection<?> beans) {
|
282
|
for (Object bean : beans){
|
283
|
addBean(bean);
|
284
|
}
|
285
|
}
|
286
|
|
287
|
/**
|
288
|
* Removes all beans representing this node.
|
289
|
*/
|
290
|
public void resetBeans(){
|
291
|
beans.clear();
|
292
|
}
|
293
|
|
294
|
|
295
|
// ************************* OVERRIDES **********************************/
|
296
|
|
297
|
@Override
|
298
|
public int compareTo(BeanInitNode o) {
|
299
|
String toMany = AbstractBeanInitializer.LOAD_2ONE_2MANY_WILDCARD;
|
300
|
String toOne = AbstractBeanInitializer.LOAD_2ONE_WILDCARD;
|
301
|
if (this.path.equals(toMany)){
|
302
|
return -1;
|
303
|
}else if (o.path.equals(toMany)){
|
304
|
return 1;
|
305
|
}else if (this.path.equals(toOne)){
|
306
|
return -1;
|
307
|
}else if (o.path.equals(toOne)){
|
308
|
return 1;
|
309
|
}else{
|
310
|
return path.compareTo(o.path);
|
311
|
}
|
312
|
}
|
313
|
|
314
|
|
315
|
@Override
|
316
|
public String toString() {
|
317
|
|
318
|
if(parent == null){
|
319
|
return "/"; //for root node
|
320
|
}else{
|
321
|
String result = parent.toString() + ((parent.parent == null) ? "" : ".") + path;
|
322
|
return result;
|
323
|
}
|
324
|
}
|
325
|
|
326
|
public String toStringNoWildcard(){
|
327
|
return toString().replace(".$", "").replace(".*", "");
|
328
|
}
|
329
|
|
330
|
public String toStringTree() {
|
331
|
|
332
|
String result = (path.equals("") ? "/" : path) + "\n";
|
333
|
|
334
|
for (BeanInitNode child : getChildrenList()){
|
335
|
result += toString() + (result.endsWith("/\n") ? "" : ".") + child.toStringTree();
|
336
|
}
|
337
|
|
338
|
return result;
|
339
|
}
|
340
|
|
341
|
public boolean hasWildcardToOneSibling() {
|
342
|
BeanInitNode sibl = getWildcardSibling();
|
343
|
return (sibl != null && sibl.isToOneInitialized);
|
344
|
}
|
345
|
|
346
|
|
347
|
}
|