/*
* #%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.provider;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.broadleafcommerce.common.exception.ExceptionHelper;
import org.broadleafcommerce.common.extension.ExtensionResultHolder;
import org.broadleafcommerce.common.extension.ExtensionResultStatusType;
import org.broadleafcommerce.common.presentation.RuleIdentifier;
import org.broadleafcommerce.common.presentation.client.SupportedFieldType;
import org.broadleafcommerce.common.rule.QuantityBasedRule;
import org.broadleafcommerce.common.rule.SimpleRule;
import org.broadleafcommerce.common.sandbox.SandBoxHelper;
import org.broadleafcommerce.openadmin.dto.BasicFieldMetadata;
import org.broadleafcommerce.openadmin.dto.Entity;
import org.broadleafcommerce.openadmin.dto.FieldMetadata;
import org.broadleafcommerce.openadmin.dto.Property;
import org.broadleafcommerce.openadmin.server.service.persistence.ParentEntityPersistenceException;
import org.broadleafcommerce.openadmin.server.service.persistence.PersistenceException;
import org.broadleafcommerce.openadmin.server.service.persistence.module.FieldManager;
import org.broadleafcommerce.openadmin.server.service.persistence.module.FieldNotAvailableException;
import org.broadleafcommerce.openadmin.server.service.persistence.module.provider.extension.RuleFieldPersistenceProviderExtensionManager;
import org.broadleafcommerce.openadmin.server.service.persistence.module.provider.request.AddFilterPropertiesRequest;
import org.broadleafcommerce.openadmin.server.service.persistence.module.provider.request.ExtractValueRequest;
import org.broadleafcommerce.openadmin.server.service.persistence.module.provider.request.PopulateValueRequest;
import org.broadleafcommerce.openadmin.server.service.type.FieldProviderResponse;
import org.broadleafcommerce.openadmin.web.rulebuilder.DataDTOToMVELTranslator;
import org.broadleafcommerce.openadmin.web.rulebuilder.MVELToDataWrapperTranslator;
import org.broadleafcommerce.openadmin.web.rulebuilder.MVELTranslationException;
import org.broadleafcommerce.openadmin.web.rulebuilder.dto.DataDTO;
import org.broadleafcommerce.openadmin.web.rulebuilder.dto.DataWrapper;
import org.broadleafcommerce.openadmin.web.rulebuilder.service.RuleBuilderFieldServiceFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.OneToMany;
/**
* Provides persistence (read/write) behavior for rule builder fields. This includes two types: Rule with quantity, and
* simple rule. OfferImpl#targetItemCriteria and OfferImpl#offerMatchRules are examples of each, respectively. This class
* is only compatible with quantity-based rules modeled using a Set and @OneToMany, and with simple rules modeled using
* a Map and @OneToMany.
*
* @author Jeff Fischer
*/
@Component("blRuleFieldPersistenceProvider")
@Scope("prototype")
public class RuleFieldPersistenceProvider extends FieldPersistenceProviderAdapter {
protected boolean canHandlePersistence(PopulateValueRequest populateValueRequest, Serializable instance) {
return populateValueRequest.getMetadata().getFieldType() == SupportedFieldType.RULE_WITH_QUANTITY ||
populateValueRequest.getMetadata().getFieldType() == SupportedFieldType.RULE_SIMPLE;
}
protected boolean canHandleExtraction(ExtractValueRequest extractValueRequest, Property property) {
return extractValueRequest.getMetadata().getFieldType() == SupportedFieldType.RULE_WITH_QUANTITY ||
extractValueRequest.getMetadata().getFieldType() == SupportedFieldType.RULE_SIMPLE;
}
@Resource(name = "blRuleBuilderFieldServiceFactory")
protected RuleBuilderFieldServiceFactory ruleBuilderFieldServiceFactory;
@Resource(name = "blSandBoxHelper")
protected SandBoxHelper sandBoxHelper;
@Resource(name = "blRuleFieldExtractionUtility")
protected RuleFieldExtractionUtility ruleFieldExtractionUtility;
@Resource(name = "blRuleFieldPersistenceProviderExtensionManager")
protected RuleFieldPersistenceProviderExtensionManager extensionManager;
@Override
public FieldProviderResponse populateValue(PopulateValueRequest populateValueRequest, Serializable instance) throws PersistenceException {
if (!canHandlePersistence(populateValueRequest, instance)) {
return FieldProviderResponse.NOT_HANDLED;
}
boolean dirty = false;
try {
setNonDisplayableValues(populateValueRequest);
switch (populateValueRequest.getMetadata().getFieldType()) {
case RULE_WITH_QUANTITY:{
dirty = populateQuantityRule(populateValueRequest, instance);
break;
}
case RULE_SIMPLE:{
dirty = populateSimpleRule(populateValueRequest, instance);
break;
}
}
} catch (Exception e) {
throw ExceptionHelper.refineException(PersistenceException.class, PersistenceException.class, e);
}
populateValueRequest.getProperty().setIsDirty(dirty);
return FieldProviderResponse.HANDLED_BREAK;
}
@Override
public FieldProviderResponse extractValue(ExtractValueRequest extractValueRequest, Property property) throws PersistenceException {
if (!canHandleExtraction(extractValueRequest, property)) {
return FieldProviderResponse.NOT_HANDLED;
}
ObjectMapper mapper = new ObjectMapper();
MVELToDataWrapperTranslator translator = new MVELToDataWrapperTranslator();
if (extractValueRequest.getMetadata().getFieldType()== SupportedFieldType.RULE_SIMPLE) {
extractSimpleRule(extractValueRequest, property, mapper, translator);
}
if (extractValueRequest.getMetadata().getFieldType()==SupportedFieldType.RULE_WITH_QUANTITY) {
extractQuantityRule(extractValueRequest, mapper, translator);
}
return FieldProviderResponse.HANDLED_BREAK;
}
@Override
public FieldProviderResponse filterProperties(AddFilterPropertiesRequest addFilterPropertiesRequest, Map<String, FieldMetadata> properties) {
//This may contain rule Json fields - convert and filter out
List<Property> propertyList = new ArrayList<Property>();
propertyList.addAll(Arrays.asList(addFilterPropertiesRequest.getEntity().getProperties()));
Iterator<Property> itr = propertyList.iterator();
List<Property> additionalProperties = new ArrayList<Property>();
while(itr.hasNext()) {
Property prop = itr.next();
if (prop.getName().endsWith("Json")) {
for (Map.Entry<String, FieldMetadata> entry : properties.entrySet()) {
if (prop.getName().startsWith(entry.getKey())) {
BasicFieldMetadata originalFM = (BasicFieldMetadata) entry.getValue();
if (originalFM.getFieldType() == SupportedFieldType.RULE_SIMPLE ||
originalFM.getFieldType() == SupportedFieldType.RULE_WITH_QUANTITY) {
Property originalProp = addFilterPropertiesRequest.getEntity().findProperty(entry.getKey());
if (originalProp == null) {
originalProp = new Property();
originalProp.setName(entry.getKey());
additionalProperties.add(originalProp);
}
originalProp.setValue(prop.getValue());
originalProp.setRawValue(prop.getRawValue());
originalProp.setUnHtmlEncodedValue(prop.getUnHtmlEncodedValue());
itr.remove();
break;
}
}
}
}
}
propertyList.addAll(additionalProperties);
addFilterPropertiesRequest.getEntity().setProperties(propertyList.toArray(new Property[propertyList.size()]));
return FieldProviderResponse.HANDLED;
}
protected void extractSimpleRule(ExtractValueRequest extractValueRequest, Property property, ObjectMapper mapper, MVELToDataWrapperTranslator translator) {
String val = null;
if (extractValueRequest.getRequestedValue() != null) {
if (extractValueRequest.getRequestedValue() instanceof String) {
val = (String) extractValueRequest.getRequestedValue();
property.setValue(val);
property.setDisplayValue(extractValueRequest.getDisplayVal());
} else {
Object simpleRule = extractValueRequest.getRequestedValue();
if (simpleRule != null) {
if (simpleRule instanceof SimpleRule) {
val = ((SimpleRule) simpleRule).getMatchRule();
property.setValue(val);
property.setDisplayValue(extractValueRequest.getDisplayVal());
} else {
throw new UnsupportedOperationException("RULE_SIMPLE type is currently only supported on " +
"fields of type SimpleRule");
}
}
}
}
Property jsonProperty = ruleFieldExtractionUtility.convertSimpleRuleToJson(translator, mapper, val,
property.getName() + "Json", extractValueRequest.getMetadata().getRuleIdentifier());
extractValueRequest.getProps().add(jsonProperty);
}
protected void extractQuantityRule(ExtractValueRequest extractValueRequest, ObjectMapper mapper, MVELToDataWrapperTranslator translator) {
if (extractValueRequest.getRequestedValue() != null) {
if (extractValueRequest.getRequestedValue() instanceof Collection) {
//these quantity rules are in a list - this is a special, valid case for quantity rules
Property jsonProperty = convertQuantityBasedRuleToJson(translator,
mapper, (Collection<QuantityBasedRule>) extractValueRequest
.getRequestedValue(),
extractValueRequest.getMetadata().getName() + "Json", extractValueRequest.getMetadata()
.getRuleIdentifier());
extractValueRequest.getProps().add(jsonProperty);
} else {
//TODO support a single quantity based rule
throw new UnsupportedOperationException("RULE_WITH_QUANTITY type is currently only supported" +
"on collection fields. A single field with this type is not currently supported.");
}
}
}
protected boolean populateSimpleRule(PopulateValueRequest populateValueRequest, Serializable instance) throws Exception {
boolean dirty = false;
String prop = populateValueRequest.getProperty().getName();
if (prop.contains(FieldManager.MAPFIELDSEPARATOR)) {
Field field = populateValueRequest.getFieldManager().getField(instance.getClass(), prop.substring(0, prop.indexOf(FieldManager.MAPFIELDSEPARATOR)));
if (field.getAnnotation(OneToMany.class) == null) {
throw new UnsupportedOperationException("RuleFieldPersistenceProvider is currently only compatible with map fields when modelled using @OneToMany");
}
}
DataDTOToMVELTranslator translator = new DataDTOToMVELTranslator();
//AntiSamy HTML encodes the rule JSON - pass the unHTMLEncoded version
DataWrapper dw = ruleFieldExtractionUtility.convertJsonToDataWrapper(populateValueRequest.getProperty().getUnHtmlEncodedValue());
if (dw == null || StringUtils.isEmpty(dw.getError())) {
String mvel = ruleFieldExtractionUtility.convertSimpleMatchRuleJsonToMvel(translator, RuleIdentifier.ENTITY_KEY_MAP.get(populateValueRequest.getMetadata().getRuleIdentifier()),
populateValueRequest.getMetadata().getRuleIdentifier(), dw);
Class<?> valueType = getStartingValueType(populateValueRequest);
//This is a simple String field (or String map field)
if (String.class.isAssignableFrom(valueType)) {
//first check if the property is null and the mvel is null
if (instance != null && mvel == null) {
Object value = populateValueRequest.getFieldManager().getFieldValue(instance, populateValueRequest.getProperty().getName());
dirty = value != null;
} else {
dirty = checkDirtyState(populateValueRequest, instance, mvel);
}
populateValueRequest.getFieldManager().setFieldValue(instance, populateValueRequest.getProperty().getName(), mvel);
}
if (SimpleRule.class.isAssignableFrom(valueType)) {
boolean persist = false;
SimpleRule rule;
try {
rule = (SimpleRule) populateValueRequest.getFieldManager().getFieldValue(instance,
populateValueRequest.getProperty().getName());
if (rule == null) {
rule = (SimpleRule) valueType.newInstance();
Field field = populateValueRequest.getFieldManager().getField(instance.getClass(),
prop.substring(0, prop.indexOf(FieldManager.MAPFIELDSEPARATOR)));
OneToMany oneToMany = field.getAnnotation(OneToMany.class);
Object parent = extractParent(populateValueRequest, instance);
populateValueRequest.getFieldManager().setFieldValue(rule, oneToMany.mappedBy(), parent);
populateValueRequest.getFieldManager().setFieldValue(rule, populateValueRequest.getMetadata().
getMapKeyValueProperty(), prop.substring(prop.indexOf(
FieldManager.MAPFIELDSEPARATOR) + FieldManager.MAPFIELDSEPARATOR.length(),
prop.length()));
persist = true;
}
} catch (FieldNotAvailableException e) {
throw new IllegalArgumentException(e);
}
if (mvel == null) {
//cause the rule to be deleted
dirty = populateValueRequest.getFieldManager().getFieldValue(instance, populateValueRequest.getProperty().getName()) != null;
if (dirty) {
if (!populateValueRequest.getProperty().getName().contains(FieldManager.MAPFIELDSEPARATOR)) {
populateValueRequest.getFieldManager().setFieldValue(instance, populateValueRequest.getProperty().getName(), null);
} else {
populateValueRequest.getPersistenceManager().getDynamicEntityDao().remove(rule);
}
}
} else if (rule != null) {
dirty = !mvel.equals(rule.getMatchRule());
if (!dirty && extensionManager != null) {
ExtensionResultHolder<Boolean> resultHolder = new ExtensionResultHolder<Boolean>();
ExtensionResultStatusType result = extensionManager.getProxy().establishDirtyState(rule,
resultHolder);
if (ExtensionResultStatusType.NOT_HANDLED != result && resultHolder.getResult() != null) {
dirty = resultHolder.getResult();
}
}
if (dirty) {
updateSimpleRule(populateValueRequest, mvel, persist, rule);
}
}
}
}
return dirty;
}
protected Object extractParent(PopulateValueRequest populateValueRequest, Serializable instance) throws IllegalAccessException, FieldNotAvailableException {
Object parent = instance;
String parentName = populateValueRequest.getProperty().getName();
if (parentName.contains(".")) {
parent = populateValueRequest.getFieldManager().getFieldValue(instance,
parentName.substring(0, parentName.lastIndexOf(".")));
}
if (!populateValueRequest.getPersistenceManager().getDynamicEntityDao().getStandardEntityManager().contains(parent)) {
try {
populateValueRequest.getPersistenceManager().getDynamicEntityDao().persist(parent);
} catch (Exception e) {
throw new ParentEntityPersistenceException("Unable to Persist the parent entity during rule builder field population", e);
}
}
return parent;
}
protected boolean populateQuantityRule(PopulateValueRequest populateValueRequest, Serializable instance) throws FieldNotAvailableException, IllegalAccessException {
String prop = populateValueRequest.getProperty().getName();
Field field = populateValueRequest.getFieldManager().getField(instance.getClass(), prop);
OneToMany oneToMany = field.getAnnotation(OneToMany.class);
if (oneToMany == null) {
throw new UnsupportedOperationException("RuleFieldPersistenceProvider is currently only compatible with collection fields when modelled using @OneToMany");
}
boolean dirty;//currently, this only works with Collection fields
Class<?> valueType = getListFieldType(instance, populateValueRequest
.getFieldManager(), populateValueRequest.getProperty(), populateValueRequest.getPersistenceManager());
if (valueType == null) {
throw new IllegalAccessException("Unable to determine the valueType for the rule field (" +
populateValueRequest.getProperty().getName() + ")");
}
DataDTOToMVELTranslator translator = new DataDTOToMVELTranslator();
Collection<QuantityBasedRule> rules;
rules = (Collection<QuantityBasedRule>) populateValueRequest.getFieldManager().getFieldValue
(instance, populateValueRequest.getProperty().getName());
Object parent = extractParent(populateValueRequest, instance);
//AntiSamy HTML encodes the rule JSON - pass the unHTMLEncoded version
dirty = updateQuantityRule(
populateValueRequest.getPersistenceManager().getDynamicEntityDao().getStandardEntityManager(),
translator, RuleIdentifier.ENTITY_KEY_MAP.get(populateValueRequest.getMetadata().getRuleIdentifier()),
populateValueRequest.getMetadata().getRuleIdentifier(),
populateValueRequest.getProperty().getUnHtmlEncodedValue(), rules, valueType, parent,
oneToMany.mappedBy(),
populateValueRequest.getProperty());
return dirty;
}
protected Property convertQuantityBasedRuleToJson(MVELToDataWrapperTranslator translator, ObjectMapper mapper,
Collection<QuantityBasedRule> quantityBasedRules, String jsonProp, String fieldService) {
int k=0;
Entity[] targetItemCriterias = new Entity[quantityBasedRules.size()];
for (QuantityBasedRule quantityBasedRule : quantityBasedRules) {
Property[] properties = new Property[3];
Property mvelProperty = new Property();
mvelProperty.setName("matchRule");
mvelProperty.setValue(quantityBasedRule.getMatchRule());
Property quantityProperty = new Property();
quantityProperty.setName("quantity");
quantityProperty.setValue(quantityBasedRule.getQuantity().toString());
Property idProperty = new Property();
idProperty.setName("id");
Long id = quantityBasedRule.getId();
if (extensionManager != null) {
ExtensionResultHolder<Long> resultHolder = new ExtensionResultHolder<Long>();
ExtensionResultStatusType result = extensionManager.getProxy().transformId(quantityBasedRule, resultHolder);
if (ExtensionResultStatusType.NOT_HANDLED != result && resultHolder.getResult() != null) {
id = resultHolder.getResult();
}
}
idProperty.setValue(String.valueOf(id));
properties[0] = mvelProperty;
properties[1] = quantityProperty;
properties[2] = idProperty;
Entity criteria = new Entity();
criteria.setProperties(properties);
targetItemCriterias[k] = criteria;
k++;
}
String json;
try {
DataWrapper oiWrapper = translator.createRuleData(targetItemCriterias, "matchRule", "quantity", "id",
ruleBuilderFieldServiceFactory.createInstance(fieldService));
json = mapper.writeValueAsString(oiWrapper);
} catch (Exception e) {
throw new RuntimeException(e);
}
Property p = new Property();
p.setName(jsonProp);
p.setValue(json);
return p;
}
protected boolean updateQuantityRule(EntityManager em, DataDTOToMVELTranslator translator, String entityKey,
String fieldService, String jsonPropertyValue,
Collection<QuantityBasedRule> criteriaList, Class<?> memberType,
Object parent, String mappedBy, Property property) {
boolean dirty = false;
if (!StringUtils.isEmpty(jsonPropertyValue)) {
//avoid lazy init exception on the criteria list for criteria created during an add
criteriaList.size();
DataWrapper dw = ruleFieldExtractionUtility.convertJsonToDataWrapper(jsonPropertyValue);
if (dw != null && StringUtils.isEmpty(dw.getError())) {
List<QuantityBasedRule> updatedRules = new ArrayList<QuantityBasedRule>();
for (DataDTO dto : dw.getData()) {
if (dto.getId() != null && !CollectionUtils.isEmpty(criteriaList)) {
checkId: {
//updates are comprehensive, even data that was not changed
//is submitted here
//Update Existing Criteria
for (QuantityBasedRule quantityBasedRule : criteriaList) {
//make compatible with enterprise module
Long id = sandBoxHelper.getOriginalId(quantityBasedRule);
boolean isMatch = dto.getId().equals(id) || dto.getId().equals(quantityBasedRule.getId());
if (isMatch){
String mvel;
//don't update if the data has not changed
if (!quantityBasedRule.getQuantity().equals(dto.getQuantity())) {
dirty = true;
}
try {
mvel = ruleFieldExtractionUtility.convertDTOToMvelString(translator, entityKey, dto, fieldService);
if (!quantityBasedRule.getMatchRule().equals(mvel)) {
dirty = true;
}
} catch (MVELTranslationException e) {
throw new RuntimeException(e);
}
if (!dirty && extensionManager != null) {
ExtensionResultHolder<Boolean> resultHolder = new ExtensionResultHolder<Boolean>();
ExtensionResultStatusType result = extensionManager.getProxy().establishDirtyState(quantityBasedRule,
resultHolder);
if (ExtensionResultStatusType.NOT_HANDLED != result && resultHolder.getResult() != null) {
dirty = resultHolder.getResult();
}
}
if (dirty) {
quantityBasedRule.setQuantity(dto.getQuantity());
quantityBasedRule.setMatchRule(mvel);
quantityBasedRule = em.merge(quantityBasedRule);
}
updatedRules.add(quantityBasedRule);
break checkId;
}
}
throw new IllegalArgumentException("Unable to update the rule of type (" + memberType.getName() +
") because an update was requested for id (" + dto.getId() + "), which does not exist.");
}
} else {
//Create a new Criteria
QuantityBasedRule quantityBasedRule;
try {
quantityBasedRule = (QuantityBasedRule) memberType.newInstance();
quantityBasedRule.setQuantity(dto.getQuantity());
quantityBasedRule.setMatchRule(ruleFieldExtractionUtility.convertDTOToMvelString(translator, entityKey, dto, fieldService));
if (StringUtils.isEmpty(quantityBasedRule.getMatchRule()) && !StringUtils.isEmpty(dw.getRawMvel())) {
quantityBasedRule.setMatchRule(dw.getRawMvel());
}
PropertyUtils.setNestedProperty(quantityBasedRule, mappedBy, parent);
} catch (Exception e) {
throw new RuntimeException(e);
}
em.persist(quantityBasedRule);
dto.setId(quantityBasedRule.getId());
if (extensionManager != null) {
ExtensionResultHolder resultHolder = new ExtensionResultHolder();
extensionManager.getProxy().postAdd(quantityBasedRule, resultHolder);
if (resultHolder.getResult() != null) {
quantityBasedRule = (QuantityBasedRule) resultHolder.getResult();
}
}
updatedRules.add(quantityBasedRule);
dirty = true;
}
}
//if an item was not included in the comprehensive submit from the client, we can assume that the
//listing was deleted, so we remove it here.
Iterator<QuantityBasedRule> itr = criteriaList.iterator();
while (itr.hasNext()) {
checkForRemove:
{
QuantityBasedRule original = itr.next();
for (QuantityBasedRule quantityBasedRule : updatedRules) {
Long id = sandBoxHelper.getOriginalId(quantityBasedRule);
boolean isMatch = original.getId().equals(id) || original.getId().equals(quantityBasedRule.getId());
if (isMatch) {
break checkForRemove;
}
}
em.remove(original);
itr.remove();
dirty = true;
}
}
ObjectMapper mapper = new ObjectMapper();
String json;
try {
json = mapper.writeValueAsString(dw);
} catch (Exception e) {
throw new RuntimeException(e);
}
property.setValue(json);
}
}
return dirty;
}
protected void updateSimpleRule(PopulateValueRequest populateValueRequest, String mvel, boolean persist,
SimpleRule rule) throws IllegalAccessException, FieldNotAvailableException {
if (!persist) {
//pre-merge (can result in a clone for enterprise)
rule = populateValueRequest.getPersistenceManager().getDynamicEntityDao().merge(rule);
}
rule.setMatchRule(mvel);
if (persist) {
populateValueRequest.getPersistenceManager().getDynamicEntityDao().persist(rule);
if (extensionManager != null) {
ExtensionResultHolder resultHolder = new ExtensionResultHolder();
extensionManager.getProxy().postAdd(rule, resultHolder);
}
}
}
protected Class<?> getStartingValueType(PopulateValueRequest populateValueRequest) throws ClassNotFoundException, IllegalAccessException {
Class<?> startingValueType = null;
if (!populateValueRequest.getProperty().getName().contains(FieldManager.MAPFIELDSEPARATOR)) {
startingValueType = populateValueRequest.getReturnType();
} else {
String valueClassName = populateValueRequest.getMetadata().getMapFieldValueClass();
if (valueClassName != null) {
startingValueType = Class.forName(valueClassName);
}
if (startingValueType == null) {
startingValueType = populateValueRequest.getReturnType();
}
}
if (startingValueType == null) {
throw new IllegalAccessException("Unable to determine the valueType for the rule field (" + populateValueRequest.getProperty().getName() + ")");
}
return startingValueType;
}
@Override
public int getOrder() {
return FieldPersistenceProvider.RULE;
}
}