001 /*
002 * Cumulus4j - Securing your data in the cloud - http://cumulus4j.org
003 * Copyright (C) 2011 NightLabs Consulting GmbH
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program. If not, see <http://www.gnu.org/licenses/>.
017 */
018 package org.cumulus4j.store.fieldmanager;
019
020 import java.lang.reflect.Array;
021 import java.util.ArrayList;
022 import java.util.Collection;
023 import java.util.Collections;
024 import java.util.HashSet;
025 import java.util.Iterator;
026 import java.util.List;
027 import java.util.Map;
028 import java.util.Set;
029
030 import javax.jdo.PersistenceManager;
031 import javax.jdo.spi.JDOImplHelper;
032 import javax.jdo.spi.PersistenceCapable;
033
034 import org.cumulus4j.store.Cumulus4jPersistenceHandler;
035 import org.cumulus4j.store.Cumulus4jStoreManager;
036 import org.cumulus4j.store.EncryptionHandler;
037 import org.cumulus4j.store.ObjectContainerHelper;
038 import org.cumulus4j.store.crypto.CryptoContext;
039 import org.cumulus4j.store.model.ClassMeta;
040 import org.cumulus4j.store.model.DataEntryDAO;
041 import org.cumulus4j.store.model.EmbeddedObjectContainer;
042 import org.cumulus4j.store.model.FieldMeta;
043 import org.cumulus4j.store.model.FieldMetaRole;
044 import org.cumulus4j.store.model.IndexEntry;
045 import org.cumulus4j.store.model.IndexEntryObjectRelationHelper;
046 import org.cumulus4j.store.model.IndexValue;
047 import org.cumulus4j.store.model.ObjectContainer;
048 import org.datanucleus.ExecutionContext;
049 import org.datanucleus.exceptions.NucleusDataStoreException;
050 import org.datanucleus.identity.IdentityUtils;
051 import org.datanucleus.metadata.AbstractClassMetaData;
052 import org.datanucleus.metadata.AbstractMemberMetaData;
053 import org.datanucleus.metadata.RelationType;
054 import org.datanucleus.state.ObjectProvider;
055 import org.datanucleus.store.fieldmanager.AbstractFieldManager;
056 import org.datanucleus.store.types.SCOUtils;
057
058 /**
059 * Manager for the process of fetching a user object from the datastore, handling the translation from the
060 * DataEntry object into the users own object.
061 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
062 */
063 public class FetchFieldManager extends AbstractFieldManager
064 {
065 private ObjectProvider op;
066 private CryptoContext cryptoContext;
067 private PersistenceManager pmData;
068 private PersistenceManager pmIndex;
069 private ExecutionContext ec;
070 private ClassMeta classMeta;
071 private AbstractClassMetaData dnClassMetaData;
072 private ObjectContainer objectContainer;
073
074 public FetchFieldManager(
075 ObjectProvider op,
076 CryptoContext cryptoContext,
077 ClassMeta classMeta,
078 AbstractClassMetaData dnClassMetaData,
079 ObjectContainer objectContainer
080 )
081 {
082 if (op == null)
083 throw new IllegalArgumentException("op == null");
084 if (cryptoContext == null)
085 throw new IllegalArgumentException("cryptoContext == null");
086 if (classMeta == null)
087 throw new IllegalArgumentException("classMeta == null");
088 if (dnClassMetaData == null)
089 throw new IllegalArgumentException("dnClassMetaData == null");
090 if (objectContainer == null)
091 throw new IllegalArgumentException("objectContainer == null");
092
093 this.op = op;
094 this.cryptoContext = cryptoContext;
095 this.pmData = cryptoContext.getPersistenceManagerForData();
096 this.pmIndex = cryptoContext.getPersistenceManagerForIndex();
097 this.ec = op.getExecutionContext();
098 this.classMeta = classMeta;
099 this.dnClassMetaData = dnClassMetaData;
100 this.objectContainer = objectContainer;
101 }
102
103 protected EncryptionHandler getEncryptionHandler()
104 {
105 return ((Cumulus4jStoreManager) ec.getStoreManager()).getEncryptionHandler();
106 }
107
108 private long getFieldID(int fieldNumber)
109 {
110 AbstractMemberMetaData mmd = dnClassMetaData.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
111
112 FieldMeta fieldMeta = classMeta.getFieldMeta(mmd.getClassName(), mmd.getName());
113 if (fieldMeta == null)
114 throw new IllegalStateException("Unknown field! class=" + dnClassMetaData.getFullClassName() + " fieldNumber=" + fieldNumber + " fieldName=" + mmd.getName());
115
116 return fieldMeta.getFieldID();
117 }
118
119 @Override
120 public boolean fetchBooleanField(int fieldNumber) {
121 Object value = objectContainer.getValue(getFieldID(fieldNumber));
122 return value == null ? false : (Boolean)value;
123 }
124
125 @Override
126 public byte fetchByteField(int fieldNumber) {
127 Object value = objectContainer.getValue(getFieldID(fieldNumber));
128 return value == null ? 0 : (Byte)value;
129 }
130
131 @Override
132 public char fetchCharField(int fieldNumber) {
133 Object value = objectContainer.getValue(getFieldID(fieldNumber));
134 return value == null ? 0 : (Character)value;
135 }
136
137 @Override
138 public double fetchDoubleField(int fieldNumber) {
139 Object value = objectContainer.getValue(getFieldID(fieldNumber));
140 return value == null ? 0 : (Double)value;
141 }
142
143 @Override
144 public float fetchFloatField(int fieldNumber) {
145 Object value = objectContainer.getValue(getFieldID(fieldNumber));
146 return value == null ? 0 : (Float)value;
147 }
148
149 @Override
150 public int fetchIntField(int fieldNumber) {
151 Object value = objectContainer.getValue(getFieldID(fieldNumber));
152 return value == null ? 0 : (Integer)value;
153 }
154
155 @Override
156 public long fetchLongField(int fieldNumber) {
157 Object value = objectContainer.getValue(getFieldID(fieldNumber));
158 return value == null ? 0 : (Long)value;
159 }
160
161 @Override
162 public short fetchShortField(int fieldNumber) {
163 Object value = objectContainer.getValue(getFieldID(fieldNumber));
164 return value == null ? 0 : (Short)value;
165 }
166
167 @Override
168 public String fetchStringField(int fieldNumber) {
169 Object value = objectContainer.getValue(getFieldID(fieldNumber));
170 return (String)value;
171 }
172
173 private long thisDataEntryID = -1;
174
175 protected long getThisDataEntryID()
176 {
177 if (thisDataEntryID < 0)
178 thisDataEntryID = new DataEntryDAO(pmData, cryptoContext.getKeyStoreRefID()).getDataEntryID(classMeta, op.getExternalObjectId().toString());
179
180 return thisDataEntryID;
181 }
182
183 @Override
184 public Object fetchObjectField(int fieldNumber)
185 {
186 AbstractMemberMetaData mmd = dnClassMetaData.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
187 FieldMeta fieldMeta = classMeta.getFieldMeta(mmd.getClassName(), mmd.getName());
188 if (fieldMeta == null)
189 throw new IllegalStateException("Unknown field! class=" + dnClassMetaData.getFullClassName() + " fieldNumber=" + fieldNumber + " fieldName=" + mmd.getName());
190
191 Set<Long> mappedByDataEntryIDs = null;
192 if (mmd.getMappedBy() != null) {
193 ClassMeta fieldOrElementTypeClassMeta = fieldMeta.getFieldOrElementTypeClassMeta(ec);
194
195 // IndexEntry indexEntry = IndexEntryObjectRelationHelper.getIndexEntry(cryptoContext, pmIndex, fieldMeta.getMappedByFieldMeta(ec), classMeta, getThisDataEntryID());
196 List<IndexEntry> indexEntries = IndexEntryObjectRelationHelper.getIndexEntriesIncludingSubClasses(cryptoContext, pmIndex, fieldMeta.getMappedByFieldMeta(ec), fieldOrElementTypeClassMeta, getThisDataEntryID());
197 if (indexEntries.isEmpty())
198 mappedByDataEntryIDs = Collections.emptySet();
199 else {
200 for (IndexEntry indexEntry : indexEntries) {
201 IndexValue indexValue = getEncryptionHandler().decryptIndexEntry(cryptoContext, indexEntry);
202 if (mappedByDataEntryIDs == null)
203 mappedByDataEntryIDs = new HashSet<Long>(indexValue.getDataEntryIDs());
204 else
205 mappedByDataEntryIDs.addAll(indexValue.getDataEntryIDs());
206 }
207 }
208 }
209
210 RelationType relationType = mmd.getRelationType(ec.getClassLoaderResolver());
211
212 if (relationType == RelationType.NONE)
213 return fetchObjectFieldWithRelationTypeNone(fieldNumber, mmd, fieldMeta);
214 else if (RelationType.isRelationSingleValued(relationType))
215 return fetchObjectFieldWithRelationTypeSingleValue(fieldNumber, mmd, fieldMeta, mappedByDataEntryIDs);
216 else if (RelationType.isRelationMultiValued(relationType))
217 {
218 // Collection/Map/Array
219 if (mmd.hasCollection())
220 return fetchObjectFieldWithRelationTypeCollection(fieldNumber, mmd, fieldMeta, mappedByDataEntryIDs);
221 else if (mmd.hasMap())
222 return fetchObjectFieldWithRelationTypeMap(fieldNumber, mmd, fieldMeta, mappedByDataEntryIDs);
223 else if (mmd.hasArray())
224 return fetchObjectFieldWithRelationTypeArray(fieldNumber, mmd, fieldMeta, mappedByDataEntryIDs);
225 else
226 throw new IllegalStateException("Unexpected multi-valued relationType: " + relationType);
227 }
228 else
229 throw new IllegalStateException("Unexpected relationType: " + relationType);
230 }
231
232 /**
233 * Fetch related objects that are not persistence-capable.
234 * The related objects might be single-valued, arrays, collections or maps.
235 */
236 protected Object fetchObjectFieldWithRelationTypeNone(int fieldNumber, AbstractMemberMetaData mmd, FieldMeta fieldMeta)
237 {
238 if (mmd.hasCollection())
239 {
240 Collection<Object> collection;
241 @SuppressWarnings("unchecked")
242 Class<? extends Collection<Object>> instanceType = SCOUtils.getContainerInstanceType(mmd.getType(), mmd.getOrderMetaData() != null);
243 try {
244 collection = instanceType.newInstance();
245 } catch (InstantiationException e) {
246 throw new NucleusDataStoreException(e.getMessage(), e);
247 } catch (IllegalAccessException e) {
248 throw new NucleusDataStoreException(e.getMessage(), e);
249 }
250
251 Object array = objectContainer.getValue(fieldMeta.getFieldID());
252 if (array != null) {
253 for (int idx = 0; idx < Array.getLength(array); ++idx) {
254 Object element = Array.get(array, idx);
255 collection.add(element);
256 }
257 }
258 return op.wrapSCOField(fieldNumber, collection, false, false, true);
259 }
260
261 if (mmd.hasMap())
262 {
263 Map<?,?> map = (Map<?,?>) objectContainer.getValue(fieldMeta.getFieldID());
264 return op.wrapSCOField(fieldNumber, map, false, false, true);
265 }
266
267 // Arrays are stored 'as is', thus no conversion necessary.
268 return objectContainer.getValue(getFieldID(fieldNumber));
269 }
270
271 /**
272 * Fetch a single related object (1-1-relationship).
273 * The related object is persistence-capable.
274 */
275 protected Object fetchObjectFieldWithRelationTypeSingleValue(int fieldNumber, AbstractMemberMetaData mmd, FieldMeta fieldMeta, Set<Long> mappedByDataEntryIDs)
276 {
277 if (mmd.isEmbedded()) {
278 Object value = objectContainer.getValue(fieldMeta.getFieldID());
279 if (value == null)
280 return null;
281
282 if (!(value instanceof EmbeddedObjectContainer))
283 throw new IllegalStateException("field claims to be embedded, but persistent field value is not an EmbeddedObjectContainer! fieldID=" + fieldMeta.getFieldID() + " fieldName=" + fieldMeta.getFieldName() + " value=" + value);
284
285 EmbeddedObjectContainer embeddedObjectContainer = (EmbeddedObjectContainer) value;
286 ClassMeta embeddedClassMeta = fieldMeta.getEmbeddedClassMeta();
287 return createPCFromEmbeddedObjectContainer(fieldNumber, fieldMeta, embeddedClassMeta, embeddedObjectContainer);
288 }
289 else {
290 if (mmd.getMappedBy() != null) {
291 if (mappedByDataEntryIDs.isEmpty())
292 return null;
293
294 if (mappedByDataEntryIDs.size() != 1)
295 throw new IllegalStateException("There are multiple objects referencing a 1-1-mapped-by-relationship! Expected 0 or 1! fieldMeta=" + fieldMeta + " dataEntryIDsForMappedBy=" + mappedByDataEntryIDs);
296
297 long dataEntryID = mappedByDataEntryIDs.iterator().next();
298 return getObjectFromDataEntryID(dataEntryID);
299 }
300
301 Object valueID = objectContainer.getValue(fieldMeta.getFieldID());
302 return ObjectContainerHelper.referenceToEntity(cryptoContext, pmData, valueID);
303 }
304 }
305
306 protected Object createPCFromEmbeddedObjectContainer(int fieldNumber, FieldMeta fieldMeta, ClassMeta embeddedClassMeta, EmbeddedObjectContainer embeddedObjectContainer)
307 {
308 if (fieldMeta == null)
309 throw new IllegalArgumentException("fieldMeta == null");
310 if (embeddedClassMeta == null)
311 throw new IllegalArgumentException("embeddedClassMeta == null");
312
313 if (embeddedObjectContainer == null) // we allow null values in embedded lists - or shouldn't we?
314 return null;
315
316 // TODO the newest DN version has a StateManagerFactory that makes the following more convenient (I think) - maybe switch later?!
317 // ClassMeta embeddedClassMeta = ((Cumulus4jStoreManager)ec.getStoreManager()).getClassMeta(ec, embeddedObjectContainer.getClassID(), true);
318 // ClassMeta embeddedClassMeta = fieldMeta.getEmbeddedClassMeta();
319 Class<?> embeddedClass = ec.getClassLoaderResolver().classForName(embeddedClassMeta.getClassName());
320
321 AbstractClassMetaData embeddedDNClassMeta = embeddedClassMeta.getDataNucleusClassMetaData(ec);
322 PersistenceCapable pc = JDOImplHelper.getInstance().newInstance(embeddedClass, null);
323
324 ObjectProvider embeddedOP = ec.getNucleusContext().getObjectProviderFactory().newForEmbedded(ec, pc, false, op, fieldNumber);
325 embeddedOP.replaceFields(
326 embeddedDNClassMeta.getAllMemberPositions(),
327 new FetchFieldManager(embeddedOP, cryptoContext, embeddedClassMeta, embeddedDNClassMeta, embeddedObjectContainer)
328 );
329 return embeddedOP.getObject();
330 }
331
332 /**
333 * Fetch an array of related objects (1-n-relationship).
334 * The related objects are persistence-capable.
335 */
336 protected Object fetchObjectFieldWithRelationTypeArray(int fieldNumber, AbstractMemberMetaData mmd, FieldMeta fieldMeta, Set<Long> mappedByDataEntryIDs)
337 {
338 Class<?> elementType = ec.getClassLoaderResolver().classForName(mmd.getArray().getElementType());
339
340 Object array;
341
342 if (mmd.getArray().isEmbeddedElement()) {
343 Object value = objectContainer.getValue(fieldMeta.getFieldID());
344 if (!(value instanceof EmbeddedObjectContainer[]))
345 throw new IllegalStateException("field claims to be embedded, but persistent field value is not an array of EmbeddedObjectContainer! fieldID=" + fieldMeta.getFieldID() + " fieldName=" + fieldMeta.getFieldName() + " value=" + value);
346
347 EmbeddedObjectContainer[] embeddedObjectContainers = (EmbeddedObjectContainer[]) value;
348 int arrayLength = embeddedObjectContainers.length;
349 array = Array.newInstance(elementType, arrayLength);
350 ClassMeta embeddedClassMeta = fieldMeta.getSubFieldMeta(FieldMetaRole.arrayElement).getEmbeddedClassMeta();
351 for (int i = 0; i < arrayLength; ++i) {
352 Object pc = createPCFromEmbeddedObjectContainer(fieldNumber, fieldMeta, embeddedClassMeta, embeddedObjectContainers[i]);
353 Array.set(array, i, pc);
354 }
355 }
356 else {
357 if (mmd.getMappedBy() != null) {
358 int arrayLength = mappedByDataEntryIDs.size();
359 array = Array.newInstance(elementType, arrayLength);
360 Iterator<Long> it = mappedByDataEntryIDs.iterator();
361 for (int i = 0; i < arrayLength; ++i) {
362 Long dataEntryID = it.next();
363 Object element = getObjectFromDataEntryID(dataEntryID);
364 Array.set(array, i, element);
365 }
366 }
367 else {
368 Object ids = objectContainer.getValue(fieldMeta.getFieldID());
369 if (ids == null)
370 array = null;
371 else {
372 if (((Cumulus4jPersistenceHandler)ec.getStoreManager().getPersistenceHandler()).useReferentialIntegrity()) {
373 // Directly fill the array.
374 int arrayLength = Array.getLength(ids);
375 array = Array.newInstance(elementType, arrayLength);
376 for (int i = 0; i < arrayLength; ++i) {
377 Object id = Array.get(ids, i);
378 Object element = ObjectContainerHelper.referenceToEntity(cryptoContext, pmData, id);
379 Array.set(array, i, element);
380 }
381 }
382 else {
383 // https://sourceforge.net/tracker/?func=detail&aid=3515529&group_id=517465&atid=2102914
384 // First fill a list and then transfer everything into an array, because there might
385 // be elements missing (orphaned references).
386 int arrayLength = Array.getLength(ids);
387 ArrayList<Object> tmpList = new ArrayList<Object>();
388 for (int i = 0; i < arrayLength; ++i) {
389 Object id = Array.get(ids, i);
390 Object element = ObjectContainerHelper.referenceToEntity(cryptoContext, pmData, id);
391 if (element != null)
392 tmpList.add(element);
393 }
394 array = Array.newInstance(elementType, tmpList.size());
395 array = tmpList.toArray((Object[]) array);
396 }
397 }
398 }
399 }
400
401 return array;
402 }
403
404 /**
405 * Fetch a {@link Collection} (<code>List</code>, <code>Set</code>, etc.) of
406 * related objects (1-n-relationship).
407 * The related objects are persistence-capable.
408 */
409 protected Object fetchObjectFieldWithRelationTypeCollection(int fieldNumber, AbstractMemberMetaData mmd, FieldMeta fieldMeta, Set<Long> mappedByDataEntryIDs) {
410 Collection<Object> collection;
411 @SuppressWarnings("unchecked")
412 Class<? extends Collection<Object>> instanceType = SCOUtils.getContainerInstanceType(mmd.getType(), mmd.getOrderMetaData() != null);
413 try {
414 collection = instanceType.newInstance();
415 } catch (InstantiationException e) {
416 throw new NucleusDataStoreException(e.getMessage(), e);
417 } catch (IllegalAccessException e) {
418 throw new NucleusDataStoreException(e.getMessage(), e);
419 }
420
421 if (mmd.getCollection().isEmbeddedElement()) {
422 Object value = objectContainer.getValue(fieldMeta.getFieldID());
423 if (!(value instanceof EmbeddedObjectContainer[]))
424 throw new IllegalStateException("field claims to be embedded, but persistent field value is not an array of EmbeddedObjectContainer! fieldID=" + fieldMeta.getFieldID() + " fieldName=" + fieldMeta.getFieldName() + " value=" + value);
425
426 EmbeddedObjectContainer[] embeddedObjectContainers = (EmbeddedObjectContainer[]) value;
427 ClassMeta embeddedClassMeta = fieldMeta.getSubFieldMeta(FieldMetaRole.collectionElement).getEmbeddedClassMeta();
428 for (EmbeddedObjectContainer embeddedObjectContainer : embeddedObjectContainers) {
429 Object pc = createPCFromEmbeddedObjectContainer(fieldNumber, fieldMeta, embeddedClassMeta, embeddedObjectContainer);
430 collection.add(pc);
431 }
432 }
433 else {
434 if (mmd.getMappedBy() != null) {
435 for (Long mappedByDataEntryID : mappedByDataEntryIDs) {
436 Object element = getObjectFromDataEntryID(mappedByDataEntryID);
437 collection.add(element);
438 }
439 }
440 else {
441 Object ids = objectContainer.getValue(fieldMeta.getFieldID());
442 if (ids != null) {
443 for (int idx = 0; idx < Array.getLength(ids); ++idx) {
444 Object id = Array.get(ids, idx);
445 Object element = ObjectContainerHelper.referenceToEntity(cryptoContext, pmData, id);
446 if (element != null) // orphaned reference - https://sourceforge.net/tracker/?func=detail&aid=3515529&group_id=517465&atid=2102914
447 collection.add(element);
448 }
449 }
450 }
451 }
452
453 return op.wrapSCOField(fieldNumber, collection, false, false, true);
454 }
455
456 /**
457 * Fetch a {@link Map} of related objects (1-n-relationship).
458 * The related objects are persistence-capable.
459 */
460 protected Object fetchObjectFieldWithRelationTypeMap(int fieldNumber, AbstractMemberMetaData mmd, FieldMeta fieldMeta, Set<Long> mappedByDataEntryIDs)
461 {
462 Map<Object, Object> map;
463 @SuppressWarnings("unchecked")
464 Class<? extends Map<Object, Object>> instanceType = SCOUtils.getContainerInstanceType(mmd.getType(), mmd.getOrderMetaData() != null);
465 try {
466 map = instanceType.newInstance();
467 } catch (InstantiationException e) {
468 throw new NucleusDataStoreException(e.getMessage(), e);
469 } catch (IllegalAccessException e) {
470 throw new NucleusDataStoreException(e.getMessage(), e);
471 }
472
473 boolean keyIsPersistent = mmd.getMap().keyIsPersistent();
474 boolean valueIsPersistent = mmd.getMap().valueIsPersistent();
475
476 if (mmd.getMappedBy() != null) {
477 FieldMeta oppositeFieldMetaKey = fieldMeta.getSubFieldMeta(FieldMetaRole.mapKey).getMappedByFieldMeta(ec);
478 FieldMeta oppositeFieldMetaValue = fieldMeta.getSubFieldMeta(FieldMetaRole.mapValue).getMappedByFieldMeta(ec);
479
480 for (Long mappedByDataEntryID : mappedByDataEntryIDs) {
481 Object element = getObjectFromDataEntryID(mappedByDataEntryID);
482 ObjectProvider elementOP = ec.findObjectProvider(element);
483 if (elementOP == null)
484 throw new IllegalStateException("executionContext.findObjectProvider(element) returned null for " + element);
485
486 Object key;
487 if (keyIsPersistent)
488 key = element;
489 else
490 key = elementOP.provideField(oppositeFieldMetaKey.getDataNucleusAbsoluteFieldNumber(ec));
491
492 Object value;
493 if (valueIsPersistent)
494 value = element;
495 else
496 value = elementOP.provideField(oppositeFieldMetaValue.getDataNucleusAbsoluteFieldNumber(ec));
497
498 map.put(key, value);
499 }
500 }
501 else {
502 Map<?,?> idMap = (Map<?,?>) objectContainer.getValue(fieldMeta.getFieldID());
503 if (idMap != null) {
504 for (Map.Entry<?, ?> me : idMap.entrySet()) {
505 Object k = me.getKey();
506 Object v = me.getValue();
507
508 if (keyIsPersistent) {
509 k = ObjectContainerHelper.referenceToEntity(cryptoContext, pmData, k);
510 if (k == null) // orphaned reference - https://sourceforge.net/tracker/?func=detail&aid=3515529&group_id=517465&atid=2102914
511 continue;
512 }
513
514 if (valueIsPersistent) {
515 v = ObjectContainerHelper.referenceToEntity(cryptoContext, pmData, v);
516 if (v == null) // orphaned reference - https://sourceforge.net/tracker/?func=detail&aid=3515529&group_id=517465&atid=2102914
517 continue;
518 }
519
520 map.put(k, v);
521 }
522 }
523 }
524
525 return op.wrapSCOField(fieldNumber, map, false, false, true);
526 }
527
528 protected Object getObjectFromDataEntryID(long dataEntryID)
529 {
530 String idStr = new DataEntryDAO(pmData, cryptoContext.getKeyStoreRefID()).getDataEntry(dataEntryID).getObjectID();
531 return IdentityUtils.getObjectFromIdString(
532 idStr, classMeta.getDataNucleusClassMetaData(ec), ec, true
533 );
534 }
535 }