1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.caleigo.core.service;
20
21
22 import java.io.*;
23 import java.net.URL;
24 import java.util.*;
25 import java.util.zip.*;
26
27 import org.caleigo.core.*;
28 import org.caleigo.core.exception.*;
29 import org.caleigo.toolkit.log.*;
30 import org.caleigo.toolkit.util.*;
31
32
33 /*** MemoryDataService provides a simple implementation of the IDataService
34 * interface that can be used to store entities in a non-persistent memory
35 * cache. By overiding the loadEntitySelection and storeEntitySelection
36 * entity pesistance can be added in a simple way.
37 *
38 * Note that the class is not suitable to store sensitive data. The class
39 * does not verify foreign keys and should only be used for temporary
40 * storage and/or for test or demonstration purposes.
41 *
42 * Note also that transaction handlig is currently not supported.
43 *
44 * @author Dennis Zikovic
45 * @version 1.00
46 *
47 */ /*
48 *
49 * WHEN WHO WHY & WHAT
50 * ------------------------------------------------------------------------------
51 * 2003-01-02 Dennis Zikovic Creation
52 */
53 public class MemoryDataService extends AbstractDataService
54 {
55
56 protected final Map mTableSelectionMap;
57
58 private boolean mIsSyncroized = true;
59 private boolean mIsAutGenerateEnabled = true;
60
61
62
63 /*** Help method that makes a complete copy of the source data to the
64 * targeted MemoryDataService. The method returns true if the copy was
65 * succesfull.
66 */
67 public static boolean copyDataSource(IDataService source, MemoryDataService target)
68 {
69 if (source == null || target == null || source.getDataSourceDescriptor() != target.getDataSourceDescriptor())
70 return false;
71 boolean success = true;
72
73
74 boolean wasSyncronized = target.isSyncronized();
75 target.setSyncronized(false);
76
77
78 boolean wasAutGenerateEnabled = target.isAutGenerateEnabled();
79 target.setAutGenerateEnabled(false);
80
81 try
82 {
83
84 if (source instanceof CachedDataService)
85 source = ((CachedDataService) source).getSourceDataService();
86
87
88 ISelection entitySelection = null;
89 for (int entityTypeIndex = 0; entityTypeIndex < source.getDataSourceDescriptor().getEntityDescriptorCount(); entityTypeIndex++)
90 {
91
92 entitySelection = source.loadSelection(source.getDataSourceDescriptor().getEntityDescriptor(entityTypeIndex), null);
93 for (int entityIndex = 0; entityIndex < entitySelection.size(); entityIndex++)
94 {
95 entitySelection.getEntity(entityIndex).clearStatusFlag(IEntity.PERSISTENT);
96 target.store(entitySelection.getEntity(entityIndex));
97 }
98
99
100 target.syncronize();
101 }
102 }
103 catch (Exception e)
104 {
105 Log.printError(null, "Failed to copy data source!", e);
106 success = false;
107 }
108
109
110 target.setSyncronized(wasSyncronized);
111
112
113 target.setAutGenerateEnabled(wasAutGenerateEnabled);
114
115 return success;
116 }
117
118
119 public MemoryDataService(IDataSourceDescriptor dataSourceDescriptor)
120 {
121 this(dataSourceDescriptor, dataSourceDescriptor.getSourceName());
122 }
123
124 public MemoryDataService(IDataSourceDescriptor dataSourceDescriptor, Object serviceIdentity)
125 {
126 super(dataSourceDescriptor.getCodeName(), serviceIdentity, dataSourceDescriptor);
127 mTableSelectionMap = new HashMap();
128 }
129
130 protected void finalize()
131 {
132 if (!isSyncronized())
133 this.syncronize();
134 }
135
136
137
138 /*** Returns a new IDataTransaction object that can be used to batch
139 * data operations and wrap them in a transaction.
140 */
141 public IDataTransaction newTransaction()
142 {
143 return new DataTransaction();
144 }
145
146 public boolean ping()
147 {
148 return true;
149 }
150
151
152
153 /*** Can be called to syncronize changes against any persistent storage
154 * provided by a subclass. This mehod does only have to be called if
155 * MemoroDataService is not in a suncronized mode. Calling the method
156 * will have no effect if no persistent storage is provided by a subclass.
157 */
158 public synchronized boolean syncronize()
159 {
160 try
161 {
162 Iterator it = mTableSelectionMap.values().iterator();
163 ISelectionHolder holder;
164
165 while (it.hasNext())
166 {
167 holder = (ISelectionHolder) it.next();
168 if (holder.isDirty())
169 {
170 this.storeTableSelection(holder.getSelection());
171 holder.setDirty(false);
172 }
173 }
174 }
175 catch (Exception e)
176 {
177 Log.printError(null, "Failed to sycronize MemoryDataService!", e);
178 return false;
179 }
180
181 return true;
182 }
183
184 /*** Creates a complete backup of the called MemoryDataService to the
185 * provided file. Returns true is the backup was successfull.
186 */
187 public boolean backupTo(File backupFile)
188 {
189 return this.backupTo(backupFile, null);
190 }
191
192 /*** Creates a backup of the tables defined by the provided descriptor array
193 * in the called MemoryDataService to the provided backup file.
194 * Returns true is the backup was successfull.
195 */
196 public boolean backupTo(File backupFile, IEntityDescriptor[] descriptorArray)
197 {
198 try
199 {
200
201 if (backupFile.exists() && backupFile.isDirectory())
202 return false;
203
204 Log.print(this, "Commencing MemoryDataService backup operation to \"" + backupFile.getName() + "\"");
205 long startTime = System.currentTimeMillis();
206
207
208 ZipOutputStream zipOutput = new ZipOutputStream(new FileOutputStream(backupFile));
209 EntityWriter entityOutput = new EntityWriter(new OutputStreamWriter(zipOutput, "UTF-8"));
210
211
212 Iterator it = null;
213 if (descriptorArray == null)
214 it = this.getDataSourceDescriptor().getEntityDescriptors();
215 else
216 it = Iterators.iterate(descriptorArray);
217
218 while (it.hasNext())
219 {
220 IEntityDescriptor entityDescriptor = (IEntityDescriptor) it.next();
221 try
222 {
223 ISelection selection = this.getTableSelection(entityDescriptor);
224
225 zipOutput.putNextEntry(new ZipEntry(entityDescriptor.getSourceName() + ".txt"));
226 entityOutput.writeMappedSelection(selection);
227 entityOutput.flush();
228
229 Log.print(this, " Stored " + selection.size() + " " + entityDescriptor.getCodeName() + " entities.");
230 }
231 catch(Exception e)
232 {
233 Log.printWarning(this, "Failed to store " + entityDescriptor.getCodeName() + " entities!");
234 }
235 }
236
237
238 entityOutput.close();
239
240 Log.print(this, "Backup completed successfully in " + (System.currentTimeMillis() - startTime) + " ms.");
241 }
242 catch (Exception e)
243 {
244 Log.printError(null, "Failed to backup MemoryDataService!", e);
245 return false;
246 }
247 return true;
248 }
249
250 /*** Restores data from a backup file created by the backupTo method.
251 * Changed data will be restored and deleted entities will be re-added.
252 */
253 public boolean restoreFrom(File backupFile)
254 {
255 return this.restoreFrom(backupFile, null, true);
256 }
257
258 /*** Restores data from a backup file created by the backupTo method.
259 *
260 * @param backupFile The file containing backup data to restore from.
261 * @param descriptorArray This array specifies what entity type that should
262 * be restored. If set to null all entities will be restored.
263 * @param addDeleted The addDeleted flag defines if entities that have been
264 * delted should be re-added or not. Normally this should be set to true.
265 */
266 public boolean restoreFrom(File backupFile, IEntityDescriptor[] descriptorArray, boolean addDeleted)
267 {
268 boolean wasSyncronized = this.isSyncronized();
269 this.setSyncronized(false);
270
271 try
272 {
273
274 if (backupFile.exists() && backupFile.isDirectory())
275 return false;
276
277 Log.print(this, "Commencing MemoryDataService restore operation from \"" + backupFile.getName() + "\"");
278 long startTime = System.currentTimeMillis();
279
280
281 ZipFile zipFile = new ZipFile(backupFile);
282
283
284 Enumeration enum = zipFile.entries();
285 while (enum.hasMoreElements())
286 {
287
288 ZipEntry entry = (ZipEntry) enum.nextElement();
289 EntityReader entityReader = new EntityReader(new InputStreamReader(zipFile.getInputStream(entry), "UTF-8"));
290
291
292 String sourceName = entry.getName();
293 if (sourceName.indexOf('.') > 0)
294 sourceName = sourceName.substring(0, sourceName.indexOf('.'));
295 IEntityDescriptor entityDescriptor = null;
296 for (int j = 0; entityDescriptor == null && j < this.getDataSourceDescriptor().getEntityDescriptorCount(); j++)
297 if (this.getDataSourceDescriptor().getEntityDescriptor(j).getSourceName().equals(sourceName))
298 entityDescriptor = this.getDataSourceDescriptor().getEntityDescriptor(j);
299 if (entityDescriptor == null)
300 {
301 Log.print(this, "Failed restore table data identified as: " + sourceName);
302 continue;
303 }
304
305
306 boolean found = descriptorArray == null;
307 for (int j = 0; !found && j < descriptorArray.length; j++)
308 found = descriptorArray[j] == entityDescriptor;
309 if (!found && descriptorArray != null)
310 continue;
311
312
313 ISelection backupSelection = entityReader.readMappedSelection(entityDescriptor);
314
315
316 entityReader.close();
317
318
319 ISelection currentSelection = this.getTableSelection(entityDescriptor);
320 int added = 0;
321 int updated = 0;
322 if (currentSelection.isEmpty() && addDeleted)
323 {
324
325
326 for (int j = 0; j < backupSelection.size(); j++)
327 {
328 currentSelection.addEntity(backupSelection.getEntity(j));
329 added++;
330 }
331 }
332 else
333 {
334 for (int j = 0; j < backupSelection.size(); j++)
335 {
336
337 int index = currentSelection.indexOf(backupSelection.getEntity(j));
338 if (index >= 0)
339 {
340 currentSelection.getEntity(index).copyData(backupSelection.getEntity(j));
341 if (currentSelection.getEntity(index).isDirty())
342 {
343 updated++;
344 currentSelection.getEntity(index).setStatusFlag(IEntity.PERSISTENT);
345 currentSelection.getEntity(index).clearStatusFlag(IEntity.DIRTY | IEntity.EMPTY);
346 }
347 }
348 else if (addDeleted)
349 {
350 currentSelection.addEntity(backupSelection.getEntity(j));
351 added++;
352 }
353 }
354 }
355
356
357 this.storeTableSelection(currentSelection);
358
359 Log.print(this, " Restored " + entityDescriptor.getCodeName() + " (Added " + added + ", Updated " + updated + ")");
360 }
361
362 Log.print(this, "Restore completed successfully in " + (System.currentTimeMillis() - startTime) + " ms.");
363 }
364 catch (Exception e)
365 {
366 Log.printError(null, "Failed to restore MemoryDataService!", e);
367 return false;
368 }
369 return true;
370 }
371
372 public boolean restoreFromURL(URL backupURL)
373 {
374 return this.restoreFromURL(backupURL, null, true);
375 }
376
377 public boolean restoreFromURL(URL backupURL, IEntityDescriptor[] descriptorArray, boolean addDeleted)
378 {
379 boolean wasSyncronized = this.isSyncronized();
380 this.setSyncronized(false);
381
382 try
383 {
384 Log.print(this, "Commencing MemoryDataService restore operation from \"" + backupURL.getPath() + "\"");
385 long startTime = System.currentTimeMillis();
386
387
388 ZipInputStream zipInputStream = new ZipInputStream(backupURL.openStream());
389
390
391 ZipEntry entry = null;
392 while ((entry = zipInputStream.getNextEntry()) != null)
393 {
394
395 EntityReader entityReader = new EntityReader(new InputStreamReader(zipInputStream, "UTF-8"));
396
397
398 String sourceName = entry.getName();
399 if (sourceName.indexOf('.') > 0)
400 sourceName = sourceName.substring(0, sourceName.indexOf('.'));
401 IEntityDescriptor entityDescriptor = null;
402 for (int j = 0; entityDescriptor == null && j < this.getDataSourceDescriptor().getEntityDescriptorCount(); j++)
403 if (this.getDataSourceDescriptor().getEntityDescriptor(j).getSourceName().equals(sourceName))
404 entityDescriptor = this.getDataSourceDescriptor().getEntityDescriptor(j);
405 if (entityDescriptor == null)
406 {
407 Log.print(this, "Failed restore table data identified as: " + sourceName);
408 continue;
409 }
410
411
412 boolean found = descriptorArray == null;
413 for (int j = 0; !found && j < descriptorArray.length; j++)
414 found = descriptorArray[j] == entityDescriptor;
415 if (!found && descriptorArray != null)
416 continue;
417
418
419 ISelection backupSelection = entityReader.readMappedSelection(entityDescriptor);
420
421
422 ISelection currentSelection = this.getTableSelection(entityDescriptor);
423 int added = 0;
424 int updated = 0;
425 if (currentSelection.isEmpty() && addDeleted)
426 {
427
428
429 for (int j = 0; j < backupSelection.size(); j++)
430 {
431 currentSelection.addEntity(backupSelection.getEntity(j));
432 added++;
433 }
434 }
435 else
436 {
437 for (int j = 0; j < backupSelection.size(); j++)
438 {
439
440 int index = currentSelection.indexOf(backupSelection.getEntity(j));
441 if (index >= 0)
442 {
443 currentSelection.getEntity(index).copyData(backupSelection.getEntity(j));
444 if (currentSelection.getEntity(index).isDirty())
445 {
446 updated++;
447 currentSelection.getEntity(index).setStatusFlag(IEntity.PERSISTENT);
448 currentSelection.getEntity(index).clearStatusFlag(IEntity.DIRTY | IEntity.EMPTY);
449 }
450 }
451 else if (addDeleted)
452 {
453 currentSelection.addEntity(backupSelection.getEntity(j));
454 added++;
455 }
456 }
457 }
458
459
460 this.storeTableSelection(currentSelection);
461
462 Log.print(this, " Restored " + entityDescriptor.getCodeName() + " (Added " + added + ", Updated " + updated + ")");
463 }
464
465
466 zipInputStream.close();
467
468 Log.print(this, "Restore completed successfully in " + (System.currentTimeMillis() - startTime) + " ms.");
469 }
470 catch (Exception e)
471 {
472 Log.printError(null, "Failed to restore MemoryDataService!", e);
473 return false;
474 }
475 return true;
476 }
477
478
479
480 public boolean isSyncronized()
481 {
482 return mIsSyncroized;
483 }
484
485 public synchronized void setSyncronized(boolean syncronize)
486 {
487 mIsSyncroized = syncronize;
488
489 if (mIsSyncroized)
490 this.syncronize();
491 }
492
493 /*** Access method that returns true if autogeneration of identity fields
494 * with the autogen field flags set is enabled.
495 */
496 public boolean isAutGenerateEnabled()
497 {
498 return mIsAutGenerateEnabled;
499 }
500
501 /*** Mutation method that controls true if autogeneration of identity fields
502 * with the autogen field flags should be enabled. This should normally
503 * allways be set to true (default). It can be usable to turn off generation
504 * when copying data between sources in which case the identity data must
505 * be provided.
506 */
507 public synchronized void setAutGenerateEnabled(boolean enabled)
508 {
509 mIsAutGenerateEnabled = enabled;
510 }
511
512
513 protected void executeLoad(IEntity entity, Qualifier qualifier) throws DataServiceException
514 {
515
516 if (DataAccessManager.getManager().getAccessLevel(entity.getEntityDescriptor()) == DataAccessManager.NONE)
517 throw new SecurityException("No read access for " + entity.getEntityDescriptor() + " entities!");
518
519
520 ISelection dbSelection = this.getTableSelection(entity.getEntityDescriptor());
521
522
523 IEntity dbEntity = null;
524 for (int j = 0; j < dbSelection.size(); j++)
525 if (qualifier.doesQualify(dbSelection.getEntity(j)))
526 dbEntity = dbSelection.getEntity(j);
527
528
529 if (dbEntity != null)
530 {
531
532 if (!DataAccessManager.getManager().hasReadAccess(entity))
533 entity.clear();
534 else
535 {
536 entity.copyData(dbEntity);
537 entity.setStatusFlag(IEntity.PERSISTENT);
538 entity.clearStatusFlag(IEntity.DIRTY | IEntity.EMPTY);
539 }
540 }
541 else
542 {
543 entity.setStatusFlag(IEntity.EMPTY);
544 entity.clearStatusFlag(IEntity.DIRTY | IEntity.PERSISTENT);
545 }
546 }
547
548 protected void executeQuery(DataQuery query, ISelection selection) throws DataServiceException
549 {
550
551 if (DataAccessManager.getManager().getAccessLevel(query.getEntityDescriptor()) == DataAccessManager.NONE)
552 throw new SecurityException("No read access for " + query.getEntityDescriptor() + " entities!");
553
554
555 ISelection dbSelection = this.getTableSelection(query.getEntityDescriptor());
556 if (dbSelection != null && query.getQualifier() != null)
557 dbSelection = dbSelection.createSubSelection(query.getQualifier());
558
559
560 IEntity entity;
561 for (int j = 0; dbSelection != null && j < dbSelection.size(); j++)
562 {
563 entity = query.getEntityDescriptor().createEntity(dbSelection.getEntity(j));
564 entity.setStatusFlag(IEntity.PERSISTENT);
565 entity.clearStatusFlag(IEntity.DIRTY | IEntity.EMPTY);
566 selection.addEntity(entity);
567 }
568 }
569
570 protected void executeInsert(IEntity entity) throws DataServiceException
571 {
572
573 this.checkEntityAsStorable(entity);
574
575
576 ISelection dbSelection = this.getTableSelection(entity.getEntityDescriptor());
577
578
579 IFieldDescriptor field = null;
580 for (int j = 0; j < entity.getEntityDescriptor().getFieldCount(); j++)
581 {
582 field = entity.getEntityDescriptor().getFieldDescriptor(j);
583
584
585 if (mIsAutGenerateEnabled && field.isAutoGenerated() && field.isIdentityField() && field.getDataType() == DataType.INTEGER)
586 {
587 int max = 0;
588 for (int k = 0; k < dbSelection.size(); k++)
589 if (!dbSelection.getEntity(k).isDataNull(field))
590 max = Math.max(max, ((Integer) dbSelection.getEntity(k).getData(field)).intValue());
591 entity.setData(field, new Integer(max + 1));
592 }
593 }
594
595
596 IEntity dbEntity = entity.getEntityDescriptor().createEntity();
597 dbEntity.copyData(entity);
598 dbEntity.setStatusFlag(IEntity.PERSISTENT);
599 dbEntity.clearStatusFlag(IEntity.DIRTY | IEntity.EMPTY);
600 dbSelection.addEntity(entity);
601
602
603 this.markTableAsChanged(entity.getEntityDescriptor());
604
605
606 entity.setStatusFlag(IEntity.PERSISTENT);
607 entity.clearStatusFlag(IEntity.DIRTY | IEntity.EMPTY);
608 }
609
610 protected void executeUpdate(IEntity entity, Qualifier qualifier) throws DataServiceException
611 {
612
613 this.checkEntityAsStorable(entity);
614
615
616 ISelection dbSelection = this.getTableSelection(entity.getEntityDescriptor());
617
618
619 IEntity dbEntity = null;
620 for (int j = 0; j < dbSelection.size(); j++)
621 if (qualifier.doesQualify(dbSelection.getEntity(j)))
622 dbEntity = dbSelection.getEntity(j);
623
624 if (dbEntity != null)
625 {
626
627 dbEntity.copyData(entity);
628 for (int j = 0; j < entity.getEntityDescriptor().getFieldCount(); j++)
629 if (entity.isFieldDirty(entity.getEntityDescriptor().getFieldDescriptor(j)))
630 dbEntity.setData(entity.getEntityDescriptor().getFieldDescriptor(j), entity.getData(entity.getEntityDescriptor().getFieldDescriptor(j)));
631 dbEntity.setStatusFlag(IEntity.PERSISTENT);
632 dbEntity.clearStatusFlag(IEntity.DIRTY | IEntity.EMPTY);
633
634
635 this.markTableAsChanged(entity.getEntityDescriptor());
636
637
638 entity.setStatusFlag(IEntity.PERSISTENT);
639 entity.clearStatusFlag(IEntity.DIRTY | IEntity.EMPTY);
640 }
641 }
642
643 protected void executeDelete(IEntity entity) throws DataServiceException
644 {
645
646 this.checkEntityAsDeletable(entity);
647
648
649 ISelection dbSelection = this.getTableSelection(entity.getEntityDescriptor());
650 Qualifier qualifier = entity.getOriginQualifier();
651
652
653 IEntity dbEntity = null;
654 for (int j = 0; j < dbSelection.size(); j++)
655 if (qualifier.doesQualify(dbSelection.getEntity(j)))
656 dbEntity = dbSelection.getEntity(j);
657
658 if (dbEntity != null)
659 {
660 dbSelection.removeEntity(dbEntity);
661
662
663 this.markTableAsChanged(entity.getEntityDescriptor());
664
665
666 entity.clearStatusFlag(IEntity.DIRTY | IEntity.EMPTY | IEntity.PERSISTENT);
667 }
668 }
669
670 protected void markTableAsChanged(IEntityDescriptor entityDescriptor)
671 {
672 ISelectionHolder holder = (ISelectionHolder) mTableSelectionMap.get(entityDescriptor);
673 if (holder != null)
674 holder.setDirty(true);
675 }
676
677 protected ISelection getTableSelection(IEntityDescriptor entityDescriptor)
678 {
679 ISelection dbSelection = null;
680
681 ISelectionHolder holder = (ISelectionHolder) mTableSelectionMap.get(entityDescriptor);
682 if (holder == null)
683 {
684 dbSelection = this.loadTableSelection(entityDescriptor);
685 if (dbSelection == null)
686 dbSelection = new Selection(entityDescriptor);
687
688 holder = this.createSelectionHolder(dbSelection);
689 mTableSelectionMap.put(entityDescriptor, holder);
690 }
691 dbSelection = holder.getSelection();
692
693 return dbSelection;
694 }
695
696 /*** This method can be overriden to provide a simple persistent storage
697 * for the MemoryDataService. The method is called prior to any access
698 * of addressed table.
699 */
700 protected ISelection loadTableSelection(IEntityDescriptor entityDescriptor)
701 {
702 return null;
703 }
704
705 /*** This method can be overriden to provide a simple persistent storage
706 * for the MemoryDataService. The method is called to store changes when
707 * neaded.
708 */
709 protected void storeTableSelection(ISelection tableSelection)
710 {
711 }
712
713 /*** Can be overriden to provide a smarter ISelectionHolder class.
714 */
715 protected ISelectionHolder createSelectionHolder(ISelection tableSelection)
716 {
717 return new DefaultSelectionHolder(tableSelection);
718 }
719
720
721
722 protected interface ISelectionHolder
723 {
724 public ISelection getSelection();
725
726 public boolean isDirty();
727 public void setDirty(boolean dirty);
728 }
729
730 protected class DefaultSelectionHolder implements ISelectionHolder
731 {
732
733 private ISelection mSelection;
734 private boolean mIsDirty;
735
736
737
738 public DefaultSelectionHolder(ISelection selection)
739 {
740 mSelection = selection;
741 mIsDirty = false;
742 }
743
744
745
746 public ISelection getSelection()
747 {
748 return mSelection;
749 }
750
751 public boolean isDirty()
752 {
753 return mIsDirty;
754 }
755
756 public void setDirty(boolean dirty)
757 {
758 mIsDirty = dirty;
759 }
760 }
761
762 protected class DataTransaction extends AbstractDataTransaction
763 {
764
765 public DataTransaction()
766 {
767 super(getTimeout());
768 }
769
770 public void commit() throws DataServiceException
771 {
772 synchronized (MemoryDataService.this)
773 {
774
775 Enumeration dataOperations = this.getOperations();
776
777
778 try
779 {
780
781 while (dataOperations.hasMoreElements())
782 {
783 DataOperation operation = (DataOperation) dataOperations.nextElement();
784 switch (operation.getOperationType())
785 {
786 case DataOperation.LOAD :
787 executeLoad(operation.getEntity(), operation.getQualifier());
788 break;
789 case DataOperation.QUERY :
790 executeQuery(operation.getDataQuery(), operation.getEntitySelection());
791 break;
792 case DataOperation.STORE :
793 if (operation.getEntity().isPersistent())
794 executeUpdate(operation.getEntity(), operation.getQualifier());
795 else
796 executeInsert(operation.getEntity());
797 break;
798 case DataOperation.DELETE :
799 executeDelete(operation.getEntity());
800 break;
801 case DataOperation.REFRESH :
802 executeLoad(operation.getEntity(), operation.getQualifier());
803 break;
804 }
805 }
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827 }
828 catch (Exception e)
829 {
830 throw new DataServiceException("Transaction failed: " + e.getClass().getName() + " - " + e.getMessage(), e);
831 }
832
833
834 if (isSyncronized())
835 syncronize();
836 }
837 }
838
839 public void abortTransaction() throws DataServiceException
840 {
841 throw new UnsupportedOperationException();
842 }
843 }
844 }