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.io.ByteArrayInputStream;
27 import java.io.ByteArrayOutputStream;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.io.ObjectInputStream;
31 import java.io.ObjectOutputStream;
32 import java.io.OutputStream;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.HashMap;
38 import java.util.HashSet;
39 import java.util.Iterator;
40 import java.util.LinkedList;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Set;
44 import java.util.UUID;
45 import java.util.zip.GZIPInputStream;
46 import java.util.zip.GZIPOutputStream;
47 import javax.persistence.EntityManager;
48 import javax.persistence.EntityTransaction;
49 import javax.persistence.NoResultException;
50 import javax.persistence.Query;
51 import net.jcip.annotations.NotThreadSafe;
52 import org.modeshape.common.util.IoUtil;
53 import org.modeshape.common.util.StringUtil;
54 import org.modeshape.connector.store.jpa.JpaConnectorI18n;
55 import org.modeshape.connector.store.jpa.model.common.WorkspaceEntity;
56 import org.modeshape.connector.store.jpa.util.Namespaces;
57 import org.modeshape.connector.store.jpa.util.Serializer;
58 import org.modeshape.connector.store.jpa.util.Workspaces;
59 import org.modeshape.connector.store.jpa.util.Serializer.LargeValues;
60 import org.modeshape.graph.ExecutionContext;
61 import org.modeshape.graph.Location;
62 import org.modeshape.graph.ModeShapeLexicon;
63 import org.modeshape.graph.connector.LockFailedException;
64 import org.modeshape.graph.connector.map.AbstractMapWorkspace;
65 import org.modeshape.graph.connector.map.MapNode;
66 import org.modeshape.graph.connector.map.MapRepository;
67 import org.modeshape.graph.connector.map.MapRepositoryTransaction;
68 import org.modeshape.graph.connector.map.MapWorkspace;
69 import org.modeshape.graph.property.Binary;
70 import org.modeshape.graph.property.Name;
71 import org.modeshape.graph.property.NameFactory;
72 import org.modeshape.graph.property.Path;
73 import org.modeshape.graph.property.PathFactory;
74 import org.modeshape.graph.property.Property;
75 import org.modeshape.graph.property.PropertyFactory;
76 import org.modeshape.graph.property.PropertyType;
77 import org.modeshape.graph.property.Reference;
78 import org.modeshape.graph.property.UuidFactory;
79 import org.modeshape.graph.property.ValueFactories;
80 import org.modeshape.graph.property.ValueFactory;
81 import org.modeshape.graph.property.Path.Segment;
82 import org.modeshape.graph.request.CompositeRequest;
83 import org.modeshape.graph.request.LockBranchRequest.LockScope;
84
85
86
87
88
89
90
91
92
93
94
95
96
97 public class SimpleJpaRepository extends MapRepository {
98
99 protected final EntityManager entityManager;
100 protected final Workspaces workspaceEntities;
101 protected final Namespaces namespaceEntities;
102 protected final ExecutionContext context;
103 protected final PathFactory pathFactory;
104 protected final NameFactory nameFactory;
105 private final List<String> predefinedWorkspaceNames;
106 protected final boolean compressData;
107 protected final boolean creatingWorkspacesAllowed;
108 protected final long minimumSizeOfLargeValuesInBytes;
109 protected final String dialect;
110
111 public SimpleJpaRepository( String sourceName,
112 UUID rootNodeUuid,
113 String defaultWorkspaceName,
114 String[] predefinedWorkspaceNames,
115 EntityManager entityManager,
116 ExecutionContext context,
117 boolean compressData,
118 boolean creatingWorkspacesAllowed,
119 long minimumSizeOfLargeValuesInBytes,
120 String dialect ) {
121 super(sourceName, rootNodeUuid, defaultWorkspaceName);
122
123 this.context = context;
124 ValueFactories valueFactories = context.getValueFactories();
125 this.nameFactory = valueFactories.getNameFactory();
126 this.pathFactory = valueFactories.getPathFactory();
127 this.predefinedWorkspaceNames = Arrays.asList(predefinedWorkspaceNames);
128 this.compressData = compressData;
129 this.creatingWorkspacesAllowed = creatingWorkspacesAllowed;
130 this.minimumSizeOfLargeValuesInBytes = minimumSizeOfLargeValuesInBytes;
131 this.dialect = dialect;
132
133 this.entityManager = entityManager;
134 workspaceEntities = new Workspaces(entityManager);
135 namespaceEntities = new Namespaces(entityManager);
136 super.initialize();
137 }
138
139 public SimpleJpaRepository( String sourceName,
140 UUID rootNodeUuid,
141 EntityManager entityManager,
142 ExecutionContext context,
143 boolean compressData,
144 boolean creatingWorkspacesAllowed,
145 long minimumSizeOfLargeValuesInBytes,
146 String dialect ) {
147 super(sourceName, rootNodeUuid);
148
149 this.context = context;
150 ValueFactories valueFactories = context.getValueFactories();
151 this.nameFactory = valueFactories.getNameFactory();
152 this.pathFactory = valueFactories.getPathFactory();
153 this.predefinedWorkspaceNames = Collections.emptyList();
154 this.compressData = compressData;
155 this.creatingWorkspacesAllowed = creatingWorkspacesAllowed;
156 this.minimumSizeOfLargeValuesInBytes = minimumSizeOfLargeValuesInBytes;
157 this.dialect = dialect;
158
159 this.entityManager = entityManager;
160 workspaceEntities = new Workspaces(entityManager);
161 namespaceEntities = new Namespaces(entityManager);
162 super.initialize();
163 }
164
165
166
167
168
169
170
171 final boolean creatingWorkspacesAllowed() {
172 return this.creatingWorkspacesAllowed;
173 }
174
175
176
177
178
179 @Override
180 protected MapWorkspace createWorkspace( ExecutionContext context,
181 String name ) {
182
183 WorkspaceEntity entity = workspaceEntities.get(name, false);
184
185 if (entity != null) {
186 return new Workspace(this, name, entity.getId().intValue());
187 }
188
189 entity = workspaceEntities.create(name);
190
191
192 entityManager.flush();
193
194 Workspace workspace = new Workspace(this, name, entity.getId().intValue());
195 workspace.createRootNode();
196
197 return workspace;
198 }
199
200
201
202
203
204 @Override
205 public MapWorkspace getWorkspace( String name ) {
206 MapWorkspace workspace = super.getWorkspace(name);
207 if (workspace != null) return workspace;
208
209
210 if (name == null) name = getDefaultWorkspaceName();
211 WorkspaceEntity entity = workspaceEntities.get(name, false);
212 if (entity == null) {
213 if (this.predefinedWorkspaceNames.contains(name)) {
214 return createWorkspace(context, name);
215 }
216
217 return null;
218 }
219
220 return new Workspace(this, name, entity.getId());
221 }
222
223
224
225
226
227 @Override
228 public Set<String> getWorkspaceNames() {
229 Set<String> workspaceNames = new HashSet<String>(super.getWorkspaceNames());
230 workspaceNames.addAll(predefinedWorkspaceNames);
231
232 return workspaceNames;
233 }
234
235
236
237
238
239
240 @Override
241 public MapRepositoryTransaction startTransaction( boolean readonly ) {
242 EntityTransaction txn = entityManager.getTransaction();
243 return new SimpleJpaTransaction(txn);
244 }
245
246
247
248
249
250
251
252
253 @SuppressWarnings( "synthetic-access" )
254 protected class Workspace extends AbstractMapWorkspace {
255 private final long workspaceId;
256 private final Map<Path, MapNode> nodesByPath = new HashMap<Path, MapNode>();
257
258 public Workspace( MapRepository repository,
259 String name,
260 long workspaceId ) {
261 super(repository, name);
262
263 this.workspaceId = workspaceId;
264
265
266
267
268 }
269
270 void createRootNode() {
271 initialize();
272 }
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287 @Override
288 public MapNode copyNode( ExecutionContext context,
289 MapNode original,
290 MapWorkspace newWorkspace,
291 MapNode newParent,
292 Name desiredName,
293 boolean recursive ) {
294
295 Map<UUID, UUID> oldToNewUuids = new HashMap<UUID, UUID>();
296 MapNode copyRoot = copyNode(context, original, newWorkspace, newParent, desiredName, true, oldToNewUuids);
297
298
299
300 PropertyFactory propertyFactory = context.getPropertyFactory();
301 UuidFactory uuidFactory = context.getValueFactories().getUuidFactory();
302 ValueFactory<Reference> referenceFactory = context.getValueFactories().getReferenceFactory();
303 boolean refChanged = false;
304 for (Map.Entry<UUID, UUID> oldToNew : oldToNewUuids.entrySet()) {
305 MapNode oldNode = this.getNode(oldToNew.getKey());
306 MapNode newNode = newWorkspace.getNode(oldToNew.getValue());
307 assert oldNode != null;
308 assert newNode != null;
309
310 for (Map.Entry<Name, Property> entry : newNode.getProperties().entrySet()) {
311 Property property = entry.getValue();
312
313 List<Object> newValues = new ArrayList<Object>();
314 boolean foundReference = false;
315 for (Iterator<?> iter = property.getValues(); iter.hasNext();) {
316 Object value = iter.next();
317 PropertyType type = PropertyType.discoverType(value);
318 if (type == PropertyType.REFERENCE) {
319 UUID oldReferencedUuid = uuidFactory.create(value);
320 UUID newReferencedUuid = oldToNewUuids.get(oldReferencedUuid);
321 if (newReferencedUuid != null) {
322 newValues.add(referenceFactory.create(newReferencedUuid));
323 foundReference = true;
324 refChanged = true;
325 }
326 } else {
327 newValues.add(value);
328 }
329 }
330
331 if (foundReference) {
332 Property newProperty = propertyFactory.create(property.getName(), newValues);
333 entry.setValue(newProperty);
334 }
335 }
336
337 if (refChanged) {
338 ((JpaNode)newNode).serializeProperties();
339 }
340 }
341 return copyRoot;
342 }
343
344
345
346
347
348 @Override
349 protected void correctSameNameSiblingIndexes( ExecutionContext context,
350 MapNode parentNode,
351 Name name ) {
352 int snsIndex = 1;
353 int parentIndex = 0;
354 List<MapNode> children = parentNode.getChildren();
355
356 for (MapNode child : children) {
357 NodeEntity childNode = ((JpaNode)child).entity;
358 if (parentIndex != childNode.getIndexInParent()) {
359 childNode.setIndexInParent(parentIndex);
360 }
361
362 if (name.equals(child.getName().getName())) {
363 if (snsIndex != childNode.getSameNameSiblingIndex()) {
364 childNode.setSameNameSiblingIndex(snsIndex);
365 }
366 snsIndex++;
367
368 }
369 parentIndex++;
370 }
371
372 }
373
374
375
376
377
378
379
380
381
382 @Override
383 protected void addNodeToMap( MapNode node ) {
384 assert node != null;
385
386 NodeEntity nodeEntity = ((JpaNode)node).entity;
387 nodeEntity.setWorkspaceId(this.workspaceId);
388 nodeEntity.setReferentialIntegrityEnforced(false);
389
390 entityManager.persist(nodeEntity);
391 }
392
393 @Override
394 protected MapNode removeNodeFromMap( UUID nodeUuid ) {
395 throw new IllegalStateException("This code should be unreachable");
396 }
397
398
399
400
401
402
403
404 @Override
405 protected void removeUuidReference( MapNode node ) {
406 SubgraphQuery branch = SubgraphQuery.create(entityManager, workspaceId, node.getUuid(), 0);
407
408 branch.deleteSubgraph(true);
409 branch.close();
410
411
412 LargeValueEntity.deleteUnused(entityManager, dialect);
413
414
415 this.nodesByPath.clear();
416 }
417
418
419
420
421
422 @Override
423 protected MapNode createMapNode( UUID uuid ) {
424 return new JpaNode(uuid);
425 }
426
427
428
429
430 @Override
431 protected void removeAllNodesFromMap() {
432 Query query = entityManager.createQuery("NodeEntity.deleteAllInWorkspace");
433 query.setParameter("workspaceId", workspaceId);
434 query.executeUpdate();
435
436
437 LargeValueEntity.deleteUnused(entityManager, dialect);
438 }
439
440
441
442
443
444 @Override
445 public JpaNode getNode( UUID nodeUuid ) {
446 assert nodeUuid != null;
447
448 Query query = entityManager.createNamedQuery("NodeEntity.findByNodeUuid");
449 query.setParameter("workspaceId", workspaceId);
450 query.setParameter("nodeUuidString", nodeUuid.toString());
451 try {
452
453 NodeEntity result = (NodeEntity)query.getSingleResult();
454 return new JpaNode(result);
455 } catch (NoResultException e) {
456 return null;
457 }
458 }
459
460
461
462
463
464 @Override
465 public MapNode getNode( Path path ) {
466 MapNode node = nodesByPath.get(path);
467 if (node != null) return node;
468
469 node = super.getNode(path);
470 nodesByPath.put(path, node);
471 return node;
472 }
473
474
475
476
477
478
479
480
481
482
483 public List<MapNode> getBranch( Location rootLocation,
484 int maximumDepth ) {
485 assert rootLocation.getUuid() != null || rootLocation.getPath() != null;
486 UUID subgraphRootUuid = rootLocation.getUuid();
487
488 if (subgraphRootUuid == null) {
489 MapNode rootNode = getNode(rootLocation.getPath());
490 subgraphRootUuid = rootNode.getUuid();
491 assert subgraphRootUuid != null;
492 }
493
494 SubgraphQuery subgraph = SubgraphQuery.create(entityManager, workspaceId, subgraphRootUuid, maximumDepth);
495
496 List<NodeEntity> entities = subgraph.getNodes(true, true);
497 List<MapNode> nodes = new ArrayList<MapNode>(entities.size());
498
499 for (NodeEntity entity : entities) {
500 nodes.add(new JpaNode(entity));
501 }
502
503 subgraph.close();
504
505 return nodes;
506 }
507
508
509
510
511
512
513
514
515
516 public void lockNode( MapNode node,
517 LockScope lockScope,
518 long lockTimeoutInMillis ) throws LockFailedException {
519
520 }
521
522
523
524
525
526
527 public void unlockNode( MapNode node ) {
528
529 }
530
531 }
532
533
534
535
536
537 @SuppressWarnings( "synthetic-access" )
538 @NotThreadSafe
539 protected class JpaNode implements MapNode {
540 private final NodeEntity entity;
541 private Map<Name, Property> properties = null;
542
543 protected JpaNode( NodeEntity entity ) {
544 this.entity = entity;
545 }
546
547 public JpaNode( UUID uuid ) {
548 this.entity = new NodeEntity();
549 entity.setNodeUuidString(uuid.toString());
550 }
551
552 private final JpaNode jpaNodeFor( MapNode node ) {
553 if (!(node instanceof JpaNode)) {
554 throw new IllegalStateException();
555 }
556 return (JpaNode)node;
557 }
558
559 public void addChild( int index,
560 MapNode child ) {
561 entity.addChild(index, jpaNodeFor(child).entity);
562 }
563
564 public void addChild( MapNode child ) {
565 entity.addChild(jpaNodeFor(child).entity);
566 }
567
568 public List<MapNode> getChildren() {
569 List<MapNode> children = new ArrayList<MapNode>(entity.getChildren().size());
570
571 for (NodeEntity child : entity.getChildren()) {
572 children.add(new JpaNode(child));
573 }
574
575 return Collections.unmodifiableList(children);
576 }
577
578 public Segment getName() {
579 return pathFactory.createSegment(nameFactory.create(entity.getChildNamespace().getUri(), entity.getChildName()),
580 entity.getSameNameSiblingIndex());
581 }
582
583 public MapNode getParent() {
584 if (entity.getParent() == null) return null;
585 return new JpaNode(entity.getParent());
586 }
587
588 private void ensurePropertiesLoaded() {
589 if (properties != null) return;
590
591 Collection<Property> propsCollection = new LinkedList<Property>();
592
593 if (entity.getData() != null) {
594 Serializer serializer = new Serializer(context, true);
595 ObjectInputStream ois = null;
596
597 try {
598 LargeValueSerializer largeValues = new LargeValueSerializer(entity);
599 ois = new ObjectInputStream(new ByteArrayInputStream(entity.getData()));
600 serializer.deserializeAllProperties(ois, propsCollection, largeValues);
601
602 } catch (IOException ioe) {
603 throw new IllegalStateException(ioe);
604 } catch (ClassNotFoundException cnfe) {
605 throw new IllegalStateException(cnfe);
606 } finally {
607 try {
608 if (ois != null) ois.close();
609 } catch (Exception ex) {
610 }
611 }
612 }
613
614 PropertyFactory propertyFactory = context.getPropertyFactory();
615 Map<Name, Property> properties = new HashMap<Name, Property>();
616 properties.put(ModeShapeLexicon.UUID, propertyFactory.create(ModeShapeLexicon.UUID, getUuid()));
617 for (Property prop : propsCollection) {
618 properties.put(prop.getName(), prop);
619 }
620
621 this.properties = properties;
622 }
623
624 private void serializeProperties() {
625 Serializer serializer = new Serializer(context, true);
626 ObjectOutputStream oos = null;
627
628 try {
629 ByteArrayOutputStream baos = new ByteArrayOutputStream();
630 oos = new ObjectOutputStream(baos);
631
632 LargeValueSerializer largeValues = new LargeValueSerializer(entity);
633
634 int numberOfPropertiesToSerialize = properties.size() - 1;
635 serializer.serializeProperties(oos,
636 numberOfPropertiesToSerialize,
637 properties.values(),
638 largeValues,
639 Serializer.NO_REFERENCES_VALUES);
640 oos.flush();
641 entity.setData(baos.toByteArray());
642 entity.setPropertyCount(properties.size());
643 } catch (IOException ioe) {
644 throw new IllegalStateException(ioe);
645 } finally {
646 try {
647 if (oos != null) oos.close();
648 } catch (Exception ignore) {
649 }
650 }
651 }
652
653 public MapNode removeProperty( Name propertyName ) {
654 ensurePropertiesLoaded();
655
656 if (properties.containsKey(propertyName)) {
657 properties.remove(propertyName);
658 serializeProperties();
659 }
660 return this;
661 }
662
663 public Map<Name, Property> getProperties() {
664 ensurePropertiesLoaded();
665 return properties;
666 }
667
668 public Property getProperty( ExecutionContext context,
669 String name ) {
670 return getProperty(context.getValueFactories().getNameFactory().create(name));
671 }
672
673 public Property getProperty( Name name ) {
674 ensurePropertiesLoaded();
675 return properties.get(name);
676 }
677
678 public Set<Name> getUniqueChildNames() {
679 List<NodeEntity> children = entity.getChildren();
680 Set<Name> uniqueNames = new HashSet<Name>(children.size());
681
682 for (NodeEntity child : children) {
683 uniqueNames.add(nameFactory.create(child.getChildNamespace().getUri(), child.getChildName()));
684 }
685
686 return uniqueNames;
687 }
688
689 public UUID getUuid() {
690 if (entity.getNodeUuidString() == null) return null;
691 return UUID.fromString(entity.getNodeUuidString());
692 }
693
694 public boolean removeChild( MapNode child ) {
695
696
697
698
699
700
701
702
703 List<NodeEntity> children = entity.getChildren();
704
705 int index = -1;
706 String childUuidString = jpaNodeFor(child).entity.getNodeUuidString();
707 for (int i = 0; i < children.size(); i++) {
708 if (childUuidString.equals(children.get(i).getNodeUuidString())) {
709 index = i;
710 break;
711 }
712 }
713
714
715
716 if (index < 0) return false;
717
718 entity.removeChild(index);
719
720 assert !entity.getChildren().contains(child);
721 assert child.getParent() == null;
722
723 return true;
724 }
725
726 public void clearChildren() {
727 entity.getChildren().clear();
728 }
729
730 public void setName( Segment name ) {
731 entity.setChildNamespace(namespaceEntities.get(name.getName().getNamespaceUri(), true));
732
733 entity.setChildName(name.getName().getLocalName());
734 entity.setSameNameSiblingIndex(name.getIndex());
735 }
736
737 public void setParent( MapNode parent ) {
738 if (parent == null) {
739 entity.setParent(null);
740 } else {
741 entity.setParent(jpaNodeFor(parent).entity);
742 }
743 }
744
745 public MapNode setProperty( ExecutionContext context,
746 String name,
747 Object... values ) {
748 PropertyFactory propertyFactory = context.getPropertyFactory();
749
750 return this.setProperty(propertyFactory.create(nameFactory.create(name), values));
751 }
752
753 public MapNode setProperty( Property property ) {
754 ensurePropertiesLoaded();
755
756 properties.put(property.getName(), property);
757 serializeProperties();
758
759 return this;
760 }
761
762 public MapNode setProperties( Iterable<Property> properties ) {
763 ensurePropertiesLoaded();
764
765 for (Property property : properties) {
766 this.properties.put(property.getName(), property);
767 }
768
769 serializeProperties();
770
771 return this;
772 }
773
774 @Override
775 public String toString() {
776 if (entity.getNodeUuidString().equals(rootNodeUuid.toString())) return "<root>";
777 return getName().getString() + " (" + entity.getNodeUuidString() + ")";
778 }
779
780 @Override
781 public boolean equals( Object obj ) {
782 if (!(obj instanceof JpaNode)) return false;
783
784 JpaNode other = (JpaNode)obj;
785 return entity.getNodeUuidString().equals(other.entity.getNodeUuidString());
786 }
787
788 @Override
789 public int hashCode() {
790 return entity.getNodeUuidString().hashCode();
791 }
792
793 }
794
795 protected class LargeValueSerializer implements LargeValues {
796 private final NodeEntity node;
797 private final Set<String> written;
798
799 public LargeValueSerializer( NodeEntity entity ) {
800 this.node = entity;
801 this.written = null;
802 }
803
804 public LargeValueSerializer( NodeEntity entity,
805 Set<String> written ) {
806 this.node = entity;
807 this.written = written;
808 }
809
810
811
812
813
814
815 public long getMinimumSize() {
816 return minimumSizeOfLargeValuesInBytes;
817 }
818
819
820
821
822
823
824
825 public Object read( ValueFactories valueFactories,
826 byte[] hash,
827 long length ) throws IOException {
828 String hashStr = StringUtil.getHexString(hash);
829
830 LargeValueEntity entity = entityManager.find(LargeValueEntity.class, hashStr);
831 if (entity != null) {
832
833 byte[] data = entity.getData();
834 if (entity.isCompressed()) {
835 InputStream stream = new GZIPInputStream(new ByteArrayInputStream(data));
836 try {
837 data = IoUtil.readBytes(stream);
838 } finally {
839 stream.close();
840 }
841 }
842 return valueFactories.getValueFactory(entity.getType()).create(data);
843 }
844 throw new IOException(JpaConnectorI18n.unableToReadLargeValue.text(getSourceName(), hashStr));
845 }
846
847
848
849
850
851
852
853 public void write( byte[] hash,
854 long length,
855 PropertyType type,
856 Object value ) throws IOException {
857 if (value == null) return;
858 String hashStr = StringUtil.getHexString(hash);
859 if (written != null) written.add(hashStr);
860
861
862 for (LargeValueEntity existing : node.getLargeValues()) {
863 if (existing.getHash().equals(hashStr)) {
864
865 return;
866 }
867 }
868 LargeValueEntity entity = entityManager.find(LargeValueEntity.class, hashStr);
869 if (entity == null) {
870
871 entity = new LargeValueEntity();
872 entity.setCompressed(compressData);
873 entity.setHash(hashStr);
874 entity.setLength(length);
875 entity.setType(type);
876 ValueFactories factories = context.getValueFactories();
877 byte[] bytes = null;
878 switch (type) {
879 case BINARY:
880 Binary binary = factories.getBinaryFactory().create(value);
881 InputStream stream = null;
882 try {
883 binary.acquire();
884 stream = binary.getStream();
885 if (compressData) stream = new GZIPInputStream(stream);
886 bytes = IoUtil.readBytes(stream);
887 } finally {
888 try {
889 if (stream != null) stream.close();
890 } finally {
891 binary.release();
892 }
893 }
894 break;
895 case URI:
896
897 default:
898 String str = factories.getStringFactory().create(value);
899 if (compressData) {
900 ByteArrayOutputStream bs = new ByteArrayOutputStream();
901 OutputStream strStream = new GZIPOutputStream(bs);
902 try {
903 IoUtil.write(str, strStream);
904 } finally {
905 strStream.close();
906 }
907 bytes = bs.toByteArray();
908 } else {
909 bytes = str.getBytes();
910 }
911 break;
912 }
913 entity.setData(bytes);
914 entityManager.persist(entity);
915 }
916
917 assert entity.getHash() != null;
918 node.getLargeValues().add(entity);
919 }
920
921 }
922
923 }