@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) {
     LOG.error("Problem fetching results for " + ceilingEntityFullyQualifiedClassname, e);
     throw new ServiceException(
         "Unable to fetch results for " + ceilingEntityFullyQualifiedClassname, 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(),
                  "");
      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,
                  "");
      BaseCtoConverter ctoConverter =
          getAdornedTargetCtoConverter(
              persistencePerspective, cto, mergedProperties, adornedTargetList);
      PersistentEntityCriteria queryCriteria =
          ctoConverter.convert(cto, adornedTargetList.getAdornedTargetEntityClassname());
      List<Serializable> records =
          persistenceManager
              .getDynamicEntityDao()
              .query(
                  queryCriteria,
                  Class.forName(adornedTargetList.getAdornedTargetEntityClassname()));
      payload =
          getRecords(
              mergedPropertiesTarget,
              records,
              mergedProperties,
              adornedTargetList.getTargetObjectPath());
      totalRecords = getTotalRecords(persistencePackage, cto, ctoConverter);
    } catch (Exception e) {
      LOG.error(
          "Problem fetching results for " + adornedTargetList.getAdornedTargetEntityClassname(), e);
      throw new ServiceException(
          "Unable to fetch results for " + adornedTargetList.getAdornedTargetEntityClassname(), e);
    }

    DynamicResultSet results = new DynamicResultSet(null, payload, totalRecords);

    return results;
  }
  @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);
      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());
      BaseCtoConverter ctoConverterInserted =
          getAdornedTargetCtoConverter(
              persistencePerspective, ctoInserted, mergedProperties, adornedTargetList);
      PersistentEntityCriteria queryCriteriaInserted =
          ctoConverterInserted.convert(
              ctoInserted, adornedTargetList.getAdornedTargetEntityClassname());
      List<Serializable> recordsInserted =
          persistenceManager
              .getDynamicEntityDao()
              .query(
                  queryCriteriaInserted,
                  Class.forName(adornedTargetList.getAdornedTargetEntityClassname()));

      persistenceManager.getDynamicEntityDao().remove(recordsInserted.get(0));
    } catch (Exception e) {
      LOG.error("Problem removing entity", e);
      throw new ServiceException("Problem removing entity : " + e.getMessage(), e);
    }
  }
  @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);
    try {
      AdornedTargetRetrieval adornedTargetRetrieval =
          new AdornedTargetRetrieval(persistencePerspective, entity, adornedTargetList).invoke();
      List<Serializable> records = adornedTargetRetrieval.getRecords();
      int index = adornedTargetRetrieval.getIndex();
      Map<String, FieldMetadata> mergedProperties = adornedTargetRetrieval.getMergedProperties();
      FieldManager fieldManager = getFieldManager();
      if (adornedTargetList.getSortField() != null
          && entity.findProperty(adornedTargetList.getSortField()).getValue() != null) {
        Serializable myRecord = records.remove(index);
        myRecord = createPopulatedInstance(myRecord, entity, mergedProperties, false);
        Integer newPos =
            Integer.valueOf(entity.findProperty(adornedTargetList.getSortField()).getValue());
        if (CollectionUtils.isEmpty(records)) {
          records.add(myRecord);
        } else {
          records.add(newPos, myRecord);
        }
        index = 1;
        for (Serializable record : records) {
          fieldManager.setFieldValue(record, adornedTargetList.getSortField(), Long.valueOf(index));
          index++;
        }
      } else {
        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(),
                    "");
        Serializable myRecord = records.get(index);
        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) {
      LOG.error("Problem editing entity", e);
      throw new ServiceException("Problem updating entity : " + e.getMessage(), 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);
    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());
      BaseCtoConverter ctoConverterInserted =
          getAdornedTargetCtoConverter(
              persistencePerspective, ctoInserted, mergedProperties, adornedTargetList);
      PersistentEntityCriteria queryCriteriaInserted =
          ctoConverterInserted.convert(
              ctoInserted, adornedTargetList.getAdornedTargetEntityClassname());
      List<Serializable> recordsInserted =
          persistenceManager
              .getDynamicEntityDao()
              .query(
                  queryCriteriaInserted,
                  Class.forName(adornedTargetList.getAdornedTargetEntityClassname()));
      if (recordsInserted.size() > 0) {
        payload =
            getRecords(
                mergedPropertiesTarget,
                recordsInserted,
                mergedProperties,
                adornedTargetList.getTargetObjectPath())[0];
      } else {
        Serializable instance = createPopulatedAdornedTargetInstance(adornedTargetList, entity);
        instance = createPopulatedInstance(instance, entity, mergedProperties, false);
        instance = createPopulatedInstance(instance, entity, mergedPropertiesTarget, false);
        FieldManager fieldManager = getFieldManager();
        if (fieldManager.getField(instance.getClass(), "id") != null) {
          fieldManager.setFieldValue(instance, "id", null);
        }
        if (adornedTargetList.getSortField() != null) {
          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());
          sortCriteria.setSortAscending(adornedTargetList.getSortAscending());
          BaseCtoConverter ctoConverter =
              getAdornedTargetCtoConverter(
                  persistencePerspective, cto, mergedProperties, adornedTargetList);
          int totalRecords = getTotalRecords(persistencePackage, cto, ctoConverter);
          fieldManager.setFieldValue(
              instance, adornedTargetList.getSortField(), Long.valueOf(totalRecords + 1));
        }
        instance = persistenceManager.getDynamicEntityDao().merge(instance);
        persistenceManager.getDynamicEntityDao().flush();
        persistenceManager.getDynamicEntityDao().clear();

        List<Serializable> recordsInserted2 =
            persistenceManager
                .getDynamicEntityDao()
                .query(
                    queryCriteriaInserted,
                    Class.forName(adornedTargetList.getAdornedTargetEntityClassname()));

        payload =
            getRecords(
                mergedPropertiesTarget,
                recordsInserted2,
                mergedProperties,
                adornedTargetList.getTargetObjectPath())[0];
      }
    } catch (Exception e) {
      LOG.error("Problem editing entity", e);
      throw new ServiceException("Problem adding new entity : " + e.getMessage(), e);
    }

    return payload;
  }