/* * #%L * BroadleafCommerce Open Admin Platform * %% * Copyright (C) 2009 - 2013 Broadleaf Commerce * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ package org.broadleafcommerce.openadmin.server.service.persistence.module; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.broadleafcommerce.common.exception.SecurityServiceException; import org.broadleafcommerce.common.exception.ServiceException; import org.broadleafcommerce.common.presentation.client.OperationType; import org.broadleafcommerce.common.presentation.client.PersistencePerspectiveItemType; import org.broadleafcommerce.common.presentation.client.SupportedFieldType; import org.broadleafcommerce.openadmin.dto.AdornedTargetList; import org.broadleafcommerce.openadmin.dto.BasicFieldMetadata; import org.broadleafcommerce.openadmin.dto.CriteriaTransferObject; import org.broadleafcommerce.openadmin.dto.DynamicResultSet; import org.broadleafcommerce.openadmin.dto.Entity; import org.broadleafcommerce.openadmin.dto.FieldMetadata; import org.broadleafcommerce.openadmin.dto.FilterAndSortCriteria; import org.broadleafcommerce.openadmin.dto.ForeignKey; import org.broadleafcommerce.openadmin.dto.MergedPropertyType; import org.broadleafcommerce.openadmin.dto.PersistencePackage; import org.broadleafcommerce.openadmin.dto.PersistencePerspective; import org.broadleafcommerce.openadmin.dto.Property; import org.broadleafcommerce.openadmin.server.service.persistence.module.criteria.FieldPath; import org.broadleafcommerce.openadmin.server.service.persistence.module.criteria.FieldPathBuilder; import org.broadleafcommerce.openadmin.server.service.persistence.module.criteria.FilterMapping; import org.broadleafcommerce.openadmin.server.service.persistence.module.criteria.Restriction; import org.broadleafcommerce.openadmin.server.service.persistence.module.criteria.predicate.PredicateProvider; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.springframework.util.Assert; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.From; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; /** * @author jfischer */ @Component("blAdornedTargetListPersistenceModule") @Scope("prototype") public class AdornedTargetListPersistenceModule extends BasicPersistenceModule { private static final Log LOG = LogFactory.getLog(AdornedTargetListPersistenceModule.class); @Override public boolean isCompatible(OperationType operationType) { return OperationType.ADORNEDTARGETLIST.equals(operationType); } @Override public void extractProperties(Class<?>[] inheritanceLine, Map<MergedPropertyType, Map<String, FieldMetadata>> mergedProperties, List<Property> properties) throws NumberFormatException { if (mergedProperties.get(MergedPropertyType.ADORNEDTARGETLIST) != null) { extractPropertiesFromMetadata(inheritanceLine, mergedProperties.get(MergedPropertyType.ADORNEDTARGETLIST), properties, true, MergedPropertyType.ADORNEDTARGETLIST); } } public List<FilterMapping> getBasicFilterMappings(PersistencePerspective persistencePerspective, CriteriaTransferObject cto, Map<String, FieldMetadata> mergedProperties, String cefqcn) { return getFilterMappings(persistencePerspective, cto, cefqcn, mergedProperties); } public List<FilterMapping> getAdornedTargetFilterMappings(PersistencePerspective persistencePerspective, CriteriaTransferObject cto, Map<String, FieldMetadata> mergedProperties, AdornedTargetList adornedTargetList) throws ClassNotFoundException { List<FilterMapping> filterMappings = getFilterMappings(persistencePerspective, cto, adornedTargetList. getAdornedTargetEntityClassname(), mergedProperties); FilterMapping filterMapping = new FilterMapping() .withFieldPath(new FieldPath() .withTargetProperty(adornedTargetList.getLinkedObjectPath() + "." + adornedTargetList.getLinkedIdProperty())) .withFilterValues(cto.get(adornedTargetList.getCollectionFieldName()).getFilterValues()) .withRestriction(new Restriction() .withPredicateProvider(new PredicateProvider<Serializable, String>() { @Override public Predicate buildPredicate(CriteriaBuilder builder, FieldPathBuilder fieldPathBuilder, From root, String ceilingEntity, String fullPropertyName, Path<Serializable> explicitPath, List<String> directValues) { if (String.class.isAssignableFrom(explicitPath.getJavaType())) { return builder.equal(explicitPath, directValues.get(0)); } else { return builder.equal(explicitPath, Long.parseLong(directValues.get(0))); } } }) ); filterMappings.add(filterMapping); FilterMapping filterMapping2 = new FilterMapping() .withFieldPath(new FieldPath() .withTargetProperty(adornedTargetList.getTargetObjectPath() + "." + adornedTargetList.getTargetIdProperty())) .withFilterValues(cto.get(adornedTargetList.getCollectionFieldName() + "Target").getFilterValues()) .withRestriction(new Restriction() .withPredicateProvider(new PredicateProvider<Serializable, String>() { @Override public Predicate buildPredicate(CriteriaBuilder builder, FieldPathBuilder fieldPathBuilder, From root, String ceilingEntity, String fullPropertyName, Path<Serializable> explicitPath, List<String> directValues) { if (String.class.isAssignableFrom(explicitPath.getJavaType())) { return builder.equal(explicitPath, directValues.get(0)); } else { return builder.equal(explicitPath, Long.parseLong(directValues.get(0))); } } }) ); filterMappings.add(filterMapping2); return filterMappings; } protected Serializable createPopulatedAdornedTargetInstance(AdornedTargetList adornedTargetList, Entity entity) throws InstantiationException, IllegalAccessException, ClassNotFoundException, NumberFormatException, InvocationTargetException, NoSuchMethodException, FieldNotAvailableException { Serializable instance = (Serializable) Class.forName(StringUtils.isEmpty(adornedTargetList .getAdornedTargetEntityPolymorphicType())? adornedTargetList.getAdornedTargetEntityClassname(): adornedTargetList.getAdornedTargetEntityPolymorphicType()).newInstance(); String targetPath = adornedTargetList.getTargetObjectPath() + "." + adornedTargetList.getTargetIdProperty(); String linkedPath = adornedTargetList.getLinkedObjectPath() + "." + adornedTargetList.getLinkedIdProperty(); getFieldManager().setFieldValue(instance, linkedPath, Long.valueOf(entity.findProperty(linkedPath).getValue())); Object test1 = getFieldManager().getFieldValue(instance, adornedTargetList.getLinkedObjectPath()); Object test1PersistedObject = persistenceManager.getDynamicEntityDao().retrieve(test1.getClass(), Long.valueOf(entity.findProperty(linkedPath).getValue())); Assert.isTrue(test1PersistedObject != null, "Entity not found"); Class<?> type = getFieldManager().getField(instance.getClass(), targetPath).getType(); if (String.class.isAssignableFrom(type)) { getFieldManager().setFieldValue(instance, targetPath, entity.findProperty(targetPath).getValue()); } else { getFieldManager().setFieldValue(instance, targetPath, Long.valueOf(entity.findProperty(targetPath).getValue())); } Object test2 = getFieldManager().getFieldValue(instance, adornedTargetList.getTargetObjectPath()); Object test2PersistedObject; if (String.class.isAssignableFrom(type)) { test2PersistedObject = persistenceManager.getDynamicEntityDao().retrieve(test2.getClass(), entity.findProperty(targetPath).getValue()); } else { test2PersistedObject = persistenceManager.getDynamicEntityDao().retrieve(test2.getClass(), Long.valueOf(entity.findProperty(targetPath).getValue())); } Assert.isTrue(test2PersistedObject != null, "Entity not found"); return instance; } @Override public void updateMergedProperties(PersistencePackage persistencePackage, Map<MergedPropertyType, Map<String, FieldMetadata>> allMergedProperties) throws ServiceException { String ceilingEntityFullyQualifiedClassname = persistencePackage.getCeilingEntityFullyQualifiedClassname(); try { PersistencePerspective persistencePerspective = persistencePackage.getPersistencePerspective(); AdornedTargetList adornedTargetList = (AdornedTargetList) persistencePerspective.getPersistencePerspectiveItems().get(PersistencePerspectiveItemType.ADORNEDTARGETLIST); if (adornedTargetList != null) { Class<?>[] entities = persistenceManager.getPolymorphicEntities(adornedTargetList.getAdornedTargetEntityClassname()); Map<String, FieldMetadata> joinMergedProperties = persistenceManager.getDynamicEntityDao().getMergedProperties( adornedTargetList.getAdornedTargetEntityClassname(), entities, null, new String[]{}, new ForeignKey[]{}, MergedPropertyType.ADORNEDTARGETLIST, persistencePerspective.getPopulateToOneFields(), persistencePerspective.getIncludeFields(), persistencePerspective.getExcludeFields(), persistencePerspective.getConfigurationKey(), "" ); String idProp = null; for (String key : joinMergedProperties.keySet()) { if (joinMergedProperties.get(key) instanceof BasicFieldMetadata && ((BasicFieldMetadata) joinMergedProperties.get(key)).getFieldType() == SupportedFieldType.ID) { idProp = key; break; } } if (idProp != null) { joinMergedProperties.remove(idProp); } allMergedProperties.put(MergedPropertyType.ADORNEDTARGETLIST, joinMergedProperties); } } catch (Exception e) { throw new ServiceException("Unable to fetch results for " + ceilingEntityFullyQualifiedClassname, e); } } @Override public Entity add(PersistencePackage persistencePackage) throws ServiceException { String[] customCriteria = persistencePackage.getCustomCriteria(); if (customCriteria != null && customCriteria.length > 0) { LOG.warn("custom persistence handlers and custom criteria not supported for add types other than BASIC"); } PersistencePerspective persistencePerspective = persistencePackage.getPersistencePerspective(); String ceilingEntityFullyQualifiedClassname = persistencePackage.getCeilingEntityFullyQualifiedClassname(); Entity entity = persistencePackage.getEntity(); AdornedTargetList adornedTargetList = (AdornedTargetList) persistencePerspective.getPersistencePerspectiveItems().get(PersistencePerspectiveItemType.ADORNEDTARGETLIST); if (!adornedTargetList.getMutable()) { throw new SecurityServiceException("Field is not mutable"); } Entity payload; try { Class<?>[] entities = persistenceManager.getPolymorphicEntities(ceilingEntityFullyQualifiedClassname); Map<String, FieldMetadata> mergedPropertiesTarget = persistenceManager.getDynamicEntityDao().getMergedProperties( ceilingEntityFullyQualifiedClassname, entities, null, persistencePerspective.getAdditionalNonPersistentProperties(), persistencePerspective.getAdditionalForeignKeys(), MergedPropertyType.PRIMARY, persistencePerspective.getPopulateToOneFields(), persistencePerspective.getIncludeFields(), persistencePerspective.getExcludeFields(), persistencePerspective.getConfigurationKey(), "" ); Class<?>[] entities2 = persistenceManager.getPolymorphicEntities(adornedTargetList.getAdornedTargetEntityClassname()); Map<String, FieldMetadata> mergedProperties = persistenceManager.getDynamicEntityDao().getMergedProperties( adornedTargetList.getAdornedTargetEntityClassname(), entities2, null, new String[]{}, new ForeignKey[]{}, MergedPropertyType.ADORNEDTARGETLIST, false, new String[]{}, new String[]{}, null, "" ); CriteriaTransferObject ctoInserted = new CriteriaTransferObject(); FilterAndSortCriteria filterCriteriaInsertedLinked = ctoInserted.get(adornedTargetList.getCollectionFieldName()); String linkedPath; String targetPath; if (adornedTargetList.getInverse()) { linkedPath = adornedTargetList.getTargetObjectPath() + "." + adornedTargetList.getTargetIdProperty(); targetPath = adornedTargetList.getLinkedObjectPath() + "." + adornedTargetList.getLinkedIdProperty(); } else { targetPath = adornedTargetList.getTargetObjectPath() + "." + adornedTargetList.getTargetIdProperty(); linkedPath = adornedTargetList.getLinkedObjectPath() + "." + adornedTargetList.getLinkedIdProperty(); } filterCriteriaInsertedLinked.setFilterValue(entity.findProperty(adornedTargetList.getInverse() ? targetPath : linkedPath).getValue()); FilterAndSortCriteria filterCriteriaInsertedTarget = ctoInserted.get(adornedTargetList.getCollectionFieldName() + "Target"); filterCriteriaInsertedTarget.setFilterValue(entity.findProperty(adornedTargetList.getInverse() ? linkedPath : targetPath).getValue()); List<FilterMapping> filterMappingsInserted = getAdornedTargetFilterMappings(persistencePerspective, ctoInserted, mergedProperties, adornedTargetList); List<Serializable> recordsInserted = getPersistentRecords(adornedTargetList.getAdornedTargetEntityClassname(), filterMappingsInserted, ctoInserted.getFirstResult(), ctoInserted.getMaxResults()); if (recordsInserted.size() > 0) { payload = getRecords(mergedPropertiesTarget, recordsInserted, mergedProperties, adornedTargetList.getTargetObjectPath())[0]; } else { Serializable instance = createPopulatedAdornedTargetInstance(adornedTargetList, entity); instance = createPopulatedInstance(instance, entity, mergedProperties, false, persistencePackage.isValidateUnsubmittedProperties()); instance = createPopulatedInstance(instance, entity, mergedPropertiesTarget, false, persistencePackage.isValidateUnsubmittedProperties()); FieldManager fieldManager = getFieldManager(); if (fieldManager.getField(instance.getClass(), "id") != null) { fieldManager.setFieldValue(instance, "id", null); } if (adornedTargetList.getSortField() != null) { // Construct a query that gets the last element in the join list ordered by the sort property. This will // ensure that the new record is always the last element in the list CriteriaTransferObject cto = new CriteriaTransferObject(); FilterAndSortCriteria filterCriteria = cto.get(adornedTargetList.getCollectionFieldName()); filterCriteria.setFilterValue(entity.findProperty(adornedTargetList.getInverse() ? targetPath : linkedPath).getValue()); FilterAndSortCriteria sortCriteria = cto.get(adornedTargetList.getSortField()); // criteria for which way to sort should be the opposite of how it is normally sorted so that it is // always inserted at the end sortCriteria.setSortAscending(!adornedTargetList.getSortAscending()); List<FilterMapping> filterMappings = getAdornedTargetFilterMappings(persistencePerspective, cto, mergedProperties, adornedTargetList); List<Serializable> joinList = getPersistentRecords(adornedTargetList.getAdornedTargetEntityClassname(), filterMappings, 0, 1); Object adornedLastOrdering = null; if (CollectionUtils.isNotEmpty(joinList)) { adornedLastOrdering = fieldManager.getFieldValue(joinList.get(0), adornedTargetList.getSortField()); } Field sortFieldDef = fieldManager.getField(instance.getClass(), adornedTargetList.getSortField()); int add = (adornedLastOrdering == null) ? 0 : 1; if (sortFieldDef.getType().isAssignableFrom(Long.class)) { adornedLastOrdering = (adornedLastOrdering == null) ? new Long(0) : adornedLastOrdering; fieldManager.setFieldValue(instance, adornedTargetList.getSortField(), new Long(((Long) adornedLastOrdering).longValue() + add)); } else if (sortFieldDef.getType().isAssignableFrom(Integer.class)) { adornedLastOrdering = (adornedLastOrdering == null) ? new Integer(0) : adornedLastOrdering; fieldManager.setFieldValue(instance, adornedTargetList.getSortField(), new Integer(((Integer) adornedLastOrdering).intValue() + add)); } else if (sortFieldDef.getType().isAssignableFrom(BigDecimal.class)) { adornedLastOrdering = (adornedLastOrdering == null) ? BigDecimal.ZERO : adornedLastOrdering; fieldManager.setFieldValue(instance, adornedTargetList.getSortField(), ((BigDecimal) adornedLastOrdering).add(new BigDecimal(add))); } } instance = persistenceManager.getDynamicEntityDao().merge(instance); persistenceManager.getDynamicEntityDao().clear(); List<Serializable> recordsInserted2 = getPersistentRecords(adornedTargetList.getAdornedTargetEntityClassname(), filterMappingsInserted, ctoInserted.getFirstResult(), ctoInserted.getMaxResults()); payload = getRecords(mergedPropertiesTarget, recordsInserted2, mergedProperties, adornedTargetList.getTargetObjectPath())[0]; } } catch (Exception e) { throw new ServiceException("Problem adding new entity : " + e.getMessage(), e); } return payload; } @Override public Entity update(PersistencePackage persistencePackage) throws ServiceException { String[] customCriteria = persistencePackage.getCustomCriteria(); if (customCriteria != null && customCriteria.length > 0) { LOG.warn("custom persistence handlers and custom criteria not supported for update types other than BASIC"); } PersistencePerspective persistencePerspective = persistencePackage.getPersistencePerspective(); Entity entity = persistencePackage.getEntity(); AdornedTargetList adornedTargetList = (AdornedTargetList) persistencePerspective.getPersistencePerspectiveItems().get(PersistencePerspectiveItemType.ADORNEDTARGETLIST); if (!adornedTargetList.getMutable()) { throw new SecurityServiceException("Field is not mutable"); } try { AdornedTargetRetrieval adornedTargetRetrieval = new AdornedTargetRetrieval(persistencePackage, entity, adornedTargetList).invokeForUpdate(); List<Serializable> records = adornedTargetRetrieval.getRecords(); Assert.isTrue(!CollectionUtils.isEmpty(records), "Entity not found"); int index = adornedTargetRetrieval.getIndex(); Map<String, FieldMetadata> mergedProperties = adornedTargetRetrieval.getMergedProperties(); FieldManager fieldManager = getFieldManager(); Serializable myRecord; if (adornedTargetList.getSortField() != null && entity.findProperty(adornedTargetList.getSortField()).getValue() != null) { myRecord = records.get(index); BigDecimal requestedSequence = new BigDecimal(entity.findProperty(adornedTargetList.getSortField()).getValue()); BigDecimal previousSequence = new BigDecimal(String.valueOf(getFieldManager().getFieldValue(myRecord, adornedTargetList.getSortField()))); if (!previousSequence.equals(requestedSequence)) { // Sequence has changed. Rebalance the list myRecord = records.remove(index); myRecord = createPopulatedInstance(myRecord, entity, mergedProperties, false); if (CollectionUtils.isEmpty(records)) { records.add(myRecord); } else { records.add(requestedSequence.intValue() - 1, myRecord); } index = 1; Class<?> type = fieldManager.getField(myRecord.getClass(), adornedTargetList.getSortField()).getType(); boolean isBigDecimal = BigDecimal.class.isAssignableFrom(type); for (Serializable record : records) { fieldManager.setFieldValue(record, adornedTargetList.getSortField(), isBigDecimal?new BigDecimal(index):Long.valueOf(index)); index++; } } } else { myRecord = records.get(index); } String ceilingEntityFullyQualifiedClassname = persistencePackage.getCeilingEntityFullyQualifiedClassname(); Class<?>[] entities = persistenceManager.getPolymorphicEntities(ceilingEntityFullyQualifiedClassname); Map<String, FieldMetadata> mergedPropertiesTarget = persistenceManager.getDynamicEntityDao().getMergedProperties( ceilingEntityFullyQualifiedClassname, entities, null, persistencePerspective.getAdditionalNonPersistentProperties(), persistencePerspective.getAdditionalForeignKeys(), MergedPropertyType.PRIMARY, persistencePerspective.getPopulateToOneFields(), persistencePerspective.getIncludeFields(), persistencePerspective.getExcludeFields(), persistencePerspective.getConfigurationKey(), "" ); myRecord = createPopulatedInstance(myRecord, entity, mergedProperties, false); myRecord = persistenceManager.getDynamicEntityDao().merge(myRecord); List<Serializable> myList = new ArrayList<Serializable>(); myList.add(myRecord); Entity[] payload = getRecords(mergedPropertiesTarget, myList, mergedProperties, adornedTargetList.getTargetObjectPath()); entity = payload[0]; return entity; } catch (Exception e) { throw new ServiceException("Problem updating entity : " + e.getMessage(), e); } } @Override public void remove(PersistencePackage persistencePackage) throws ServiceException { String[] customCriteria = persistencePackage.getCustomCriteria(); if (customCriteria != null && customCriteria.length > 0) { LOG.warn("custom persistence handlers and custom criteria not supported for remove types other than BASIC"); } PersistencePerspective persistencePerspective = persistencePackage.getPersistencePerspective(); Entity entity = persistencePackage.getEntity(); try { AdornedTargetList adornedTargetList = (AdornedTargetList) persistencePerspective.getPersistencePerspectiveItems().get(PersistencePerspectiveItemType.ADORNEDTARGETLIST); if (!adornedTargetList.getMutable()) { throw new SecurityServiceException("Field is not mutable"); } Class<?>[] entities = persistenceManager.getPolymorphicEntities(adornedTargetList.getAdornedTargetEntityClassname()); Map<String, FieldMetadata> mergedProperties = persistenceManager.getDynamicEntityDao().getMergedProperties( adornedTargetList.getAdornedTargetEntityClassname(), entities, null, new String[]{}, new ForeignKey[]{}, MergedPropertyType.ADORNEDTARGETLIST, false, new String[]{}, new String[]{}, null, "" ); CriteriaTransferObject ctoInserted = new CriteriaTransferObject(); FilterAndSortCriteria filterCriteriaInsertedLinked = ctoInserted.get(adornedTargetList.getCollectionFieldName()); filterCriteriaInsertedLinked.setFilterValue(entity.findProperty(adornedTargetList.getLinkedObjectPath() + "." + adornedTargetList.getLinkedIdProperty()).getValue()); FilterAndSortCriteria filterCriteriaInsertedTarget = ctoInserted.get(adornedTargetList.getCollectionFieldName() + "Target"); filterCriteriaInsertedTarget.setFilterValue(entity.findProperty(adornedTargetList.getTargetObjectPath() + "." + adornedTargetList.getTargetIdProperty()).getValue()); List<FilterMapping> filterMappings = getAdornedTargetFilterMappings(persistencePerspective, ctoInserted, mergedProperties, adornedTargetList); List<Serializable> recordsInserted = getPersistentRecords(adornedTargetList.getAdornedTargetEntityClassname(), filterMappings, ctoInserted.getFirstResult(), ctoInserted.getMaxResults()); Assert.isTrue(!CollectionUtils.isEmpty(recordsInserted), "Entity not found"); persistenceManager.getDynamicEntityDao().remove(recordsInserted.get(0)); } catch (Exception e) { throw new ServiceException("Problem removing entity : " + e.getMessage(), e); } } @Override public DynamicResultSet fetch(PersistencePackage persistencePackage, CriteriaTransferObject cto) throws ServiceException { PersistencePerspective persistencePerspective = persistencePackage.getPersistencePerspective(); String ceilingEntityFullyQualifiedClassname = persistencePackage.getCeilingEntityFullyQualifiedClassname(); AdornedTargetList adornedTargetList = (AdornedTargetList) persistencePerspective.getPersistencePerspectiveItems().get(PersistencePerspectiveItemType.ADORNEDTARGETLIST); Entity[] payload; int totalRecords; try { Class<?>[] entities = persistenceManager.getPolymorphicEntities(ceilingEntityFullyQualifiedClassname); Map<String, FieldMetadata> mergedPropertiesTarget = persistenceManager.getDynamicEntityDao().getMergedProperties( ceilingEntityFullyQualifiedClassname, entities, null, persistencePerspective.getAdditionalNonPersistentProperties(), persistencePerspective.getAdditionalForeignKeys(), MergedPropertyType.PRIMARY, persistencePerspective.getPopulateToOneFields(), persistencePerspective.getIncludeFields(), persistencePerspective.getExcludeFields(), persistencePerspective.getConfigurationKey(), "" ); AdornedTargetRetrieval adornedTargetRetrieval = new AdornedTargetRetrieval(persistencePackage, adornedTargetList, cto).invokeForFetch(); List<Serializable> records = adornedTargetRetrieval.getRecords(); Map<String, FieldMetadata> mergedProperties = adornedTargetRetrieval.getMergedProperties(); payload = getRecords(mergedPropertiesTarget, records, mergedProperties, adornedTargetList.getTargetObjectPath()); totalRecords = getTotalRecords(adornedTargetList.getAdornedTargetEntityClassname(), adornedTargetRetrieval.getFilterMappings()); } catch (Exception e) { throw new ServiceException("Unable to fetch results for " + adornedTargetList.getAdornedTargetEntityClassname(), e); } DynamicResultSet results = new DynamicResultSet(null, payload, totalRecords); return results; } public class AdornedTargetRetrieval { private final PersistencePackage persistencePackage; private final PersistencePerspective persistencePerspective; private Entity entity; private final AdornedTargetList adornedTargetList; private Map<String, FieldMetadata> mergedProperties; private List<Serializable> records; private int index; private List<FilterMapping> filterMappings; private final CriteriaTransferObject cto; // This constructor is used by the update method public AdornedTargetRetrieval(PersistencePackage persistencePackage, Entity entity, AdornedTargetList adornedTargetList) { this(persistencePackage, adornedTargetList, new CriteriaTransferObject()); this.entity = entity; } // This constructor is used by the fetch method public AdornedTargetRetrieval(PersistencePackage persistencePackage, AdornedTargetList adornedTargetList, CriteriaTransferObject cto) { this.persistencePackage = persistencePackage; this.persistencePerspective = persistencePackage.getPersistencePerspective(); this.adornedTargetList = adornedTargetList; this.cto = cto; } public Map<String, FieldMetadata> getMergedProperties() { return mergedProperties; } public List<Serializable> getRecords() { return records; } public int getIndex() { return index; } public List<FilterMapping> getFilterMappings() { return filterMappings; } public AdornedTargetRetrieval invokeForFetch() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, FieldNotAvailableException, NoSuchFieldException { invokeInternal(); return this; } public AdornedTargetRetrieval invokeForUpdate() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, FieldNotAvailableException, NoSuchFieldException { FilterAndSortCriteria filterCriteria = cto.get(adornedTargetList.getCollectionFieldName()); filterCriteria.setFilterValue(entity.findProperty(adornedTargetList.getLinkedObjectPath() + "." + adornedTargetList.getLinkedIdProperty()).getValue()); invokeInternal(); index = 0; Long myEntityId = Long.valueOf(entity.findProperty(adornedTargetList.getTargetObjectPath() + "." + adornedTargetList.getTargetIdProperty()).getValue()); FieldManager fieldManager = getFieldManager(); for (Serializable record : records) { Long targetId = (Long) fieldManager.getFieldValue(record, adornedTargetList.getTargetObjectPath() + "." + adornedTargetList.getTargetIdProperty()); if (myEntityId.equals(targetId)) { break; } index++; } return this; } private void invokeInternal() throws ClassNotFoundException { if (adornedTargetList.getSortField() != null) { FilterAndSortCriteria sortCriteria = cto.get(adornedTargetList.getSortField()); sortCriteria.setSortAscending(adornedTargetList.getSortAscending()); } Class<?>[] entities = persistenceManager.getPolymorphicEntities(adornedTargetList .getAdornedTargetEntityClassname()); mergedProperties = persistenceManager.getDynamicEntityDao().getMergedProperties( adornedTargetList.getAdornedTargetEntityClassname(), entities, null, new String[]{}, new ForeignKey[]{}, MergedPropertyType.ADORNEDTARGETLIST, persistencePerspective.getPopulateToOneFields(), persistencePerspective.getIncludeFields(), persistencePerspective.getExcludeFields(), persistencePerspective.getConfigurationKey(), "" ); filterMappings = getAdornedTargetFilterMappings(persistencePerspective, cto, mergedProperties, adornedTargetList); if (CollectionUtils.isNotEmpty(cto.getAdditionalFilterMappings())) { filterMappings.addAll(cto.getAdditionalFilterMappings()); } String ceilingEntityFullyQualifiedClassname = persistencePackage.getCeilingEntityFullyQualifiedClassname(); Class<?>[] entities2 = persistenceManager.getPolymorphicEntities(ceilingEntityFullyQualifiedClassname); Map<String, FieldMetadata> mergedPropertiesTarget = persistenceManager.getDynamicEntityDao() .getMergedProperties( ceilingEntityFullyQualifiedClassname, entities2, null, persistencePerspective.getAdditionalNonPersistentProperties(), persistencePerspective.getAdditionalForeignKeys(), MergedPropertyType.PRIMARY, persistencePerspective.getPopulateToOneFields(), persistencePerspective.getIncludeFields(), persistencePerspective.getExcludeFields(), persistencePerspective.getConfigurationKey(), "" ); // We need to make sure that the target merged properties have the target object path prefix Map<String, FieldMetadata> convertedMergedPropertiesTarget = new HashMap<String, FieldMetadata>(); String prefix = adornedTargetList.getTargetObjectPath(); for (Entry<String, FieldMetadata> entry : mergedPropertiesTarget.entrySet()) { convertedMergedPropertiesTarget.put(prefix + "." + entry.getKey(), entry.getValue()); } records = getPersistentRecords(adornedTargetList.getAdornedTargetEntityClassname(), filterMappings, cto.getFirstResult(), cto.getMaxResults()); } } }