1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.modeshape.connector.store.jpa.model.simple;
25
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.HashSet;
29 import java.util.List;
30 import javax.persistence.Column;
31 import javax.persistence.Entity;
32 import javax.persistence.EntityManager;
33 import javax.persistence.FetchType;
34 import javax.persistence.GeneratedValue;
35 import javax.persistence.GenerationType;
36 import javax.persistence.Id;
37 import javax.persistence.JoinColumn;
38 import javax.persistence.JoinTable;
39 import javax.persistence.Lob;
40 import javax.persistence.ManyToMany;
41 import javax.persistence.ManyToOne;
42 import javax.persistence.NamedQueries;
43 import javax.persistence.NamedQuery;
44 import javax.persistence.OneToMany;
45 import javax.persistence.OrderBy;
46 import javax.persistence.Query;
47 import javax.persistence.Table;
48 import org.hibernate.annotations.Index;
49 import org.modeshape.common.text.Inflector;
50 import org.modeshape.common.util.HashCode;
51 import org.modeshape.connector.store.jpa.model.common.NamespaceEntity;
52 import org.modeshape.connector.store.jpa.util.Serializer;
53
54
55
56
57
58
59
60 @Entity
61 @org.hibernate.annotations.Table( appliesTo = "MODE_SIMPLE_NODE", indexes = {
62 @Index( name = "NODEUUID_INX", columnNames = {"WORKSPACE_ID", "NODE_UUID"} ),
63 @Index( name = "CHILDINDEX_INX", columnNames = {"WORKSPACE_ID", "PARENT_ID", "CHILD_INDEX"} ),
64 @Index( name = "CHILDNAME_INX", columnNames = {"WORKSPACE_ID", "PARENT_ID", "CHILD_NAME_NS_ID", "CHILD_NAME_LOCAL",
65 "SNS_INDEX"} )} )
66 @Table( name = "MODE_SIMPLE_NODE" )
67 @NamedQueries( {
68 @NamedQuery( name = "NodeEntity.findByNodeUuid", query = "from NodeEntity as node where node.workspaceId = :workspaceId and node.nodeUuidString = :nodeUuidString" ),
69 @NamedQuery( name = "NodeEntity.findInWorkspace", query = "from NodeEntity as node where node.workspaceId = :workspaceId" ),
70 @NamedQuery( name = "NodeEntity.deleteAllInWorkspace", query = "delete from NodeEntity where workspaceId = :workspaceId" ),
71 @NamedQuery( name = "NodeEntity.withLargeValues", query = "from NodeEntity as node where node.workspaceId = :workspaceId and size(node.largeValues) > 0" )} )
72 public class NodeEntity {
73
74 @Id
75 @GeneratedValue( strategy = GenerationType.AUTO )
76 @Column( name = "ID" )
77 private long id;
78
79 @Column( name = "WORKSPACE_ID", nullable = false )
80 private long workspaceId;
81
82 @ManyToOne( fetch = FetchType.LAZY )
83 @JoinColumn( name = "PARENT_ID", referencedColumnName = "id", nullable = true )
84 private NodeEntity parent;
85
86 @Column( name = "NODE_UUID", nullable = false, length = 36 )
87 private String nodeUuidString;
88
89
90 @Column( name = "CHILD_INDEX", nullable = false, unique = false )
91 private int indexInParent = 0;
92
93 @ManyToOne( fetch = FetchType.LAZY )
94 @JoinColumn( name = "CHILD_NAME_NS_ID", nullable = true )
95 private NamespaceEntity childNamespace;
96
97 @Column( name = "CHILD_NAME_LOCAL", nullable = true, unique = false, length = 512 )
98 private String childName;
99
100 @Column( name = "SNS_INDEX", nullable = false, unique = false )
101 private int sameNameSiblingIndex = 1;
102
103 @OneToMany( fetch = FetchType.LAZY, mappedBy = "parent" )
104 @OrderBy( "indexInParent" )
105 private final List<NodeEntity> children = new ArrayList<NodeEntity>();
106
107
108
109
110 @Column( name = "ALLOWS_SNS", nullable = false, unique = false )
111 private boolean allowsSameNameChildren;
112
113 @Lob
114 @Column( name = "DATA", nullable = true, unique = false )
115 private byte[] data;
116
117 @Column( name = "NUM_PROPS", nullable = false )
118 private int propertyCount;
119
120
121
122
123 @Column( name = "COMPRESSED", nullable = true )
124 private Boolean compressed;
125
126
127
128
129 @Column( name = "ENFORCEREFINTEG", nullable = false )
130 private boolean referentialIntegrityEnforced = true;
131
132
133
134
135 @ManyToMany
136 @JoinTable( name = "ModeShape_LARGEVALUE_USAGES", joinColumns = {@JoinColumn( name = "ID" )} )
137 private final Collection<LargeValueEntity> largeValues = new HashSet<LargeValueEntity>();
138
139 public NodeEntity() {
140 }
141
142 public NodeEntity( long id,
143 NodeEntity parent,
144 String nodeUuidString,
145 long workspaceId,
146 int indexInParent,
147 NamespaceEntity ns,
148 String name ) {
149 this.id = id;
150 this.parent = parent;
151 this.nodeUuidString = nodeUuidString;
152 this.workspaceId = workspaceId;
153 this.indexInParent = indexInParent;
154 this.childNamespace = ns;
155 this.childName = name;
156 this.sameNameSiblingIndex = 1;
157 }
158
159 public NodeEntity( long id,
160 NodeEntity parent,
161 String nodeUuidString,
162 long workspaceId,
163 int indexInParent,
164 NamespaceEntity ns,
165 String name,
166 int sameNameSiblingIndex ) {
167 this.id = id;
168 this.parent = parent;
169 this.nodeUuidString = nodeUuidString;
170 this.workspaceId = workspaceId;
171 this.indexInParent = indexInParent;
172 this.childNamespace = ns;
173 this.childName = name;
174 this.sameNameSiblingIndex = sameNameSiblingIndex;
175 }
176
177
178
179
180
181
182 public long getNodeId() {
183 return id;
184 }
185
186
187
188
189 public void setNodeId( long id ) {
190 this.id = id;
191 }
192
193
194
195
196
197
198 public NodeEntity getParent() {
199 return parent;
200 }
201
202
203
204
205
206
207 public void setParent( NodeEntity parent ) {
208 this.parent = parent;
209 }
210
211
212
213
214
215
216 public String getNodeUuidString() {
217 return nodeUuidString;
218 }
219
220
221
222
223
224
225 public void setNodeUuidString( String nodeUuidString ) {
226 this.nodeUuidString = nodeUuidString;
227 }
228
229
230
231
232
233
234 public long getWorkspaceId() {
235 return workspaceId;
236 }
237
238
239
240
241
242
243 public void setWorkspaceId( long workspaceId ) {
244 this.workspaceId = workspaceId;
245 }
246
247
248
249
250
251
252 public int getIndexInParent() {
253 return indexInParent;
254 }
255
256
257
258
259 public void setIndexInParent( int index ) {
260 this.indexInParent = index;
261 }
262
263
264
265
266 public String getChildName() {
267 return childName;
268 }
269
270
271
272
273 public void setChildName( String childName ) {
274 this.childName = childName;
275 }
276
277
278
279
280 public NamespaceEntity getChildNamespace() {
281 return childNamespace;
282 }
283
284
285
286
287 public void setChildNamespace( NamespaceEntity childNamespace ) {
288 this.childNamespace = childNamespace;
289 }
290
291
292
293
294 public int getSameNameSiblingIndex() {
295 return sameNameSiblingIndex;
296 }
297
298
299
300
301 public void setSameNameSiblingIndex( int sameNameSiblingIndex ) {
302 this.sameNameSiblingIndex = sameNameSiblingIndex;
303 }
304
305
306
307
308 public boolean getAllowsSameNameChildren() {
309 return allowsSameNameChildren;
310 }
311
312
313
314
315 public void setAllowsSameNameChildren( boolean allowsSameNameChildren ) {
316 this.allowsSameNameChildren = allowsSameNameChildren;
317 }
318
319
320
321
322
323
324 public byte[] getData() {
325 return data;
326 }
327
328
329
330
331
332
333 public void setData( byte[] data ) {
334 this.data = data;
335 }
336
337
338
339
340 public int getPropertyCount() {
341 return propertyCount;
342 }
343
344
345
346
347 public void setPropertyCount( int propertyCount ) {
348 this.propertyCount = propertyCount;
349 }
350
351
352
353
354 public boolean isCompressed() {
355 return compressed != null && compressed.booleanValue();
356 }
357
358
359
360
361 public void setCompressed( boolean compressed ) {
362 this.compressed = Boolean.valueOf(compressed);
363 }
364
365 public List<NodeEntity> getChildren() {
366 return children;
367 }
368
369 public void addChild( NodeEntity child ) {
370 children.add(child);
371 child.setIndexInParent(children.size() - 1);
372 }
373
374 public void addChild( int index,
375 NodeEntity child ) {
376 for (NodeEntity existing : children.subList(index, children.size() - 1)) {
377 existing.setIndexInParent(existing.getIndexInParent() + 1);
378 }
379
380 children.add(index, child);
381 child.setIndexInParent(index);
382 }
383
384 public boolean removeChild( int index ) {
385 NodeEntity removedNode = children.remove(index);
386 if (removedNode == null) return false;
387 removedNode.setParent(null);
388
389 if (index < children.size()) {
390 for (NodeEntity child : children.subList(index, children.size() - 1)) {
391 child.setIndexInParent(child.getIndexInParent() - 1);
392 }
393 }
394 return true;
395 }
396
397
398
399
400 public Collection<LargeValueEntity> getLargeValues() {
401 return largeValues;
402 }
403
404
405
406
407 public boolean isReferentialIntegrityEnforced() {
408 return referentialIntegrityEnforced;
409 }
410
411
412
413
414 public void setReferentialIntegrityEnforced( boolean referentialIntegrityEnforced ) {
415 this.referentialIntegrityEnforced = referentialIntegrityEnforced;
416 }
417
418
419
420
421
422
423 @Override
424 public int hashCode() {
425 return HashCode.compute(id);
426 }
427
428
429
430
431
432
433 @Override
434 public boolean equals( Object obj ) {
435 if (obj == this) return true;
436 if (obj instanceof NodeEntity) {
437 NodeEntity that = (NodeEntity)obj;
438 if (this.id != that.id) return false;
439 return true;
440 }
441 return false;
442 }
443
444
445
446
447
448
449 @Override
450 public String toString() {
451 StringBuilder sb = new StringBuilder();
452 if (childNamespace != null) {
453 sb.append('{').append(childNamespace).append("}:");
454 }
455 sb.append(childName);
456 if (sameNameSiblingIndex > 1) {
457 sb.append('[').append(sameNameSiblingIndex).append(']');
458 }
459 sb.append(" (id=").append(getNodeUuidString()).append(")");
460 if (parent != null) {
461 sb.append(" is ");
462 sb.append(Inflector.getInstance().ordinalize(indexInParent));
463 sb.append(" child of ");
464 sb.append(parent.getNodeId());
465 sb.append(" in workspace ");
466 sb.append(getWorkspaceId());
467 } else {
468 sb.append(" is root in workspace ");
469 sb.append(getWorkspaceId());
470 }
471 return sb.toString();
472 }
473
474 @SuppressWarnings( "unchecked" )
475 public static void adjustSnsIndexesAndIndexesAfterRemoving( EntityManager entities,
476 Long workspaceId,
477 String uuidParent,
478 String childName,
479 long childNamespaceIndex,
480 int childIndex ) {
481
482 Query query = entities.createNamedQuery("NodeEntity.findChildrenAfterIndexUnderParent");
483 query.setParameter("workspaceId", workspaceId);
484 query.setParameter("parentUuidString", uuidParent);
485 query.setParameter("afterIndex", childIndex);
486 for (NodeEntity entity : (List<NodeEntity>)query.getResultList()) {
487
488 entity.setIndexInParent(entity.getIndexInParent() - 1);
489 if (entity.getChildName().equals(childName) && entity.getChildNamespace().getId() == childNamespaceIndex) {
490
491 entity.setSameNameSiblingIndex(entity.getSameNameSiblingIndex() - 1);
492 }
493 }
494 }
495
496 @SuppressWarnings( "unchecked" )
497 public static int adjustSnsIndexesAndIndexes( EntityManager entities,
498 Long workspaceId,
499 String uuidParent,
500 int afterIndex,
501 int untilIndex,
502 long childNamespaceIndex,
503 String childName,
504 int modifier ) {
505 int snsCount = 0;
506
507
508 Query query = entities.createNamedQuery("NodeEntity.findChildrenAfterIndexUnderParent");
509 query.setParameter("workspaceId", workspaceId);
510 query.setParameter("parentUuidString", uuidParent);
511 query.setParameter("afterIndex", afterIndex);
512
513 int index = afterIndex;
514 for (NodeEntity entity : (List<NodeEntity>)query.getResultList()) {
515 if (++index > untilIndex) {
516 break;
517 }
518
519
520 entity.setIndexInParent(entity.getIndexInParent() + modifier);
521 if (entity.getChildName().equals(childName) && entity.getChildNamespace().getId() == childNamespaceIndex) {
522
523 entity.setSameNameSiblingIndex(entity.getSameNameSiblingIndex() + modifier);
524 snsCount++;
525 }
526 }
527
528 return snsCount;
529 }
530 }