/**
* ***************************************************************************
* Copyright (c) 2010 Qcadoo Limited
* Project: Qcadoo Framework
* Version: 1.4
*
* This file is part of Qcadoo.
*
* Qcadoo is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation; either version 3 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* ***************************************************************************
*/
package com.qcadoo.model.internal.definitionconverter;
import com.google.common.collect.Lists;
import com.qcadoo.localization.api.TranslationService;
import com.qcadoo.localization.api.utils.DateUtils;
import com.qcadoo.model.api.DataDefinition;
import com.qcadoo.model.api.DictionaryService;
import com.qcadoo.model.api.FieldDefinition;
import com.qcadoo.model.api.types.Cascadeable;
import com.qcadoo.model.api.types.FieldType;
import com.qcadoo.model.constants.VersionableConstants;
import com.qcadoo.model.internal.AbstractModelXmlConverter;
import com.qcadoo.model.internal.DataDefinitionImpl;
import com.qcadoo.model.internal.FieldDefinitionImpl;
import com.qcadoo.model.internal.MasterModel;
import com.qcadoo.model.internal.api.*;
import com.qcadoo.model.internal.hooks.EntityHookDefinitionImpl;
import com.qcadoo.model.internal.hooks.FieldHookDefinitionImpl;
import com.qcadoo.model.internal.hooks.HookInitializationException;
import com.qcadoo.model.internal.types.*;
import com.qcadoo.model.internal.utils.ClassNameUtils;
import com.qcadoo.model.internal.validators.*;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import static com.google.common.base.Preconditions.checkState;
import static com.qcadoo.model.internal.AbstractModelXmlConverter.FieldsTag.PRIORITY;
import static com.qcadoo.model.internal.AbstractModelXmlConverter.OtherTag.IDENTIFIER;
import static com.qcadoo.model.internal.AbstractModelXmlConverter.OtherTag.MASTERMODEL;
import static org.springframework.context.i18n.LocaleContextHolder.getLocale;
import static org.springframework.util.StringUtils.hasText;
@Service
public final class ModelXmlToDefinitionConverterImpl extends AbstractModelXmlConverter implements ModelXmlToDefinitionConverter {
private static final Logger LOG = LoggerFactory.getLogger(ModelXmlToDefinitionConverterImpl.class);
private static final String L_PARSE_ERROR = "Error while parsing model.xml: ";
@Autowired
private DictionaryService dictionaryService;
@Autowired
private InternalDataDefinitionService dataDefinitionService;
@Autowired
private DataAccessService dataAccessService;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private TranslationService translationService;
@Transactional
@Override
public Collection<DataDefinition> convert(final Resource... resources) {
List<DataDefinition> dataDefinitions = new ArrayList<DataDefinition>();
for (Resource resource : resources) {
if (resource.isReadable()) {
LOG.info("Creating dataDefinition from " + resource);
try {
dataDefinitions.add(parse(resource.getInputStream()));
} catch (HookInitializationException | IOException | ModelXmlParsingException | XMLStreamException
| javax.xml.stream.FactoryConfigurationError e) {
throw new IllegalStateException(L_PARSE_ERROR + e.getMessage(), e);
}
}
}
return dataDefinitions;
}
private DataDefinition parse(final InputStream stream) throws HookInitializationException, ModelXmlParsingException,
XMLStreamException {
XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(stream);
DataDefinition dataDefinition = null;
while (reader.hasNext() && reader.next() > 0) {
if (isTagStarted(reader, TAG_MODEL)) {
dataDefinition = getDataDefinition(reader, getPluginIdentifier(reader));
break;
}
}
reader.close();
return dataDefinition;
}
private DataDefinition getDataDefinition(final XMLStreamReader reader, final String pluginIdentifier)
throws XMLStreamException, HookInitializationException, ModelXmlParsingException {
DataDefinitionImpl dataDefinition = getModelDefinition(reader, pluginIdentifier);
LOG.info("Creating dataDefinition " + dataDefinition);
parseElementChildren(reader, TAG_MODEL, childTag -> {
if (TAG_FIELDS.equals(getTagStarted(reader))) {
parseFields(reader, dataDefinition);
}
if (TAG_HOOKS.equals(getTagStarted(reader))) {
parseHooks(reader, dataDefinition);
}
String tag = getTagStarted(reader);
if (tag != null) {
addOtherElement(reader, dataDefinition, tag);
}
});
dataDefinitionService.save(dataDefinition);
return dataDefinition;
}
private void addAuditFields(final DataDefinitionImpl dataDefinition) {
dataDefinition.withField(getAuditFieldDefinition(dataDefinition, "createDate", new DateTimeType()));
dataDefinition.withField(getAuditFieldDefinition(dataDefinition, "updateDate", new DateTimeType()));
dataDefinition.withField(getAuditFieldDefinition(dataDefinition, "createUser", new StringType()));
dataDefinition.withField(getAuditFieldDefinition(dataDefinition, "updateUser", new StringType()));
}
private void addVersionFields(final DataDefinitionImpl dataDefinition) {
FieldDefinitionImpl fieldDefinition = new FieldDefinitionImpl(dataDefinition, VersionableConstants.VERSION_FIELD_NAME);
fieldDefinition.withReadOnly(false);
fieldDefinition.setPersistent(true);
fieldDefinition.withType(new LongType(false));
dataDefinition.withField(fieldDefinition);
}
private void parseFields(final XMLStreamReader reader, final DataDefinitionImpl dataDefinition) throws XMLStreamException,
HookInitializationException, ModelXmlParsingException {
parseElementChildren(reader, TAG_FIELDS, childTag -> addFieldElement(reader, dataDefinition, childTag));
}
private void parseHooks(final XMLStreamReader reader, final DataDefinitionImpl dataDefinition) throws XMLStreamException,
HookInitializationException, ModelXmlParsingException {
parseElementChildren(reader, TAG_HOOKS, childTag -> addHookElement(reader, dataDefinition, childTag));
}
public interface ParseElementChildrenAction {
void apply(final String childTag) throws XMLStreamException, HookInitializationException, ModelXmlParsingException;
}
private void parseElementChildren(final XMLStreamReader reader, final String tag, final ParseElementChildrenAction strategy)
throws XMLStreamException, HookInitializationException, ModelXmlParsingException {
while (reader.hasNext() && reader.next() > 0) {
if (isTagEnded(reader, tag)) {
break;
}
String childTag = getTagStarted(reader);
if (childTag != null) {
strategy.apply(childTag);
}
}
}
private void addHookElement(final XMLStreamReader reader, final DataDefinitionImpl dataDefinition, final String tag)
throws XMLStreamException, HookInitializationException, ModelXmlParsingException {
HooksTag hooksTag;
try {
hooksTag = HooksTag.valueOf(tag.toUpperCase(Locale.ENGLISH));
} catch (Exception e) {
throw new ModelXmlParsingException("Illegal type of model's hook '" + tag + "'");
}
EntityHookDefinition hookDefinition = getHookDefinition(reader);
if (HooksTag.VALIDATESWITH.equals(hooksTag)) {
hookDefinition = new CustomEntityValidator(hookDefinition);
}
dataDefinition.addHook(hooksTag, hookDefinition);
}
private void addOtherElement(final XMLStreamReader reader, final DataDefinitionImpl dataDefinition, final String tag)
throws XMLStreamException {
OtherTag otherTag = OtherTag.valueOf(tag.toUpperCase(Locale.ENGLISH));
if (otherTag == IDENTIFIER) {
dataDefinition.setIdentifierExpression(getIdentifierExpression(reader));
} else if(otherTag == MASTERMODEL){
dataDefinition.setMasterModel(getMasterModel(reader));
}
}
private void addFieldElement(final XMLStreamReader reader, final DataDefinitionImpl dataDefinition, final String tag)
throws XMLStreamException, HookInitializationException, ModelXmlParsingException {
FieldsTag fieldTag = FieldsTag.valueOf(tag.toUpperCase(Locale.ENGLISH));
if (fieldTag == PRIORITY) {
dataDefinition.addPriorityField(getPriorityFieldDefinition(reader, dataDefinition));
} else {
dataDefinition.withField(getFieldDefinition(reader, dataDefinition, fieldTag));
}
}
private DataDefinitionImpl getModelDefinition(final XMLStreamReader reader, final String pluginIdentifier) {
String modelName = getStringAttribute(reader, "name");
LOG.info("Reading model " + modelName + " for plugin " + pluginIdentifier);
DataDefinitionImpl dataDefinition = new DataDefinitionImpl(pluginIdentifier, modelName, dataAccessService);
dataDefinition.setDeletable(getBooleanAttribute(reader, "deletable", true));
dataDefinition.setInsertable(getBooleanAttribute(reader, "insertable", true));
dataDefinition.setUpdatable(getBooleanAttribute(reader, "updatable", true));
dataDefinition.setActivable(getBooleanAttribute(reader, "activable", false));
dataDefinition.setAuditable(getBooleanAttribute(reader, "auditable", false));
if (dataDefinition.isAuditable()) {
addAuditFields(dataDefinition);
}
dataDefinition.setVersionable(getBooleanAttribute(reader, VersionableConstants.VERSIONABLE_ATTRIBUTE_NAME, false));
if (dataDefinition.isVersionable()) {
addVersionFields(dataDefinition);
}
dataDefinition.setFullyQualifiedClassName(ClassNameUtils.getFullyQualifiedClassName(pluginIdentifier, modelName));
return dataDefinition;
}
private FieldType getDictionaryType(final XMLStreamReader reader) {
String dictionaryName = getStringAttribute(reader, "dictionary");
checkState(hasText(dictionaryName), "Dictionary name is required");
return new DictionaryType(dictionaryName, dictionaryService, getBooleanAttribute(reader, "copyable", true));
}
private FieldType getEnumType(final XMLStreamReader reader, final boolean copyable, final String translationPath)
throws XMLStreamException {
String values = getStringAttribute(reader, "values");
if (hasText(values)) {
return new EnumType(translationService, translationPath, copyable, values.split(","));
} else {
return new EnumType(translationService, translationPath, copyable);
}
}
private FieldType getHasManyType(final XMLStreamReader reader, final String pluginIdentifier) {
CollectionTypeCommonParams params = new CollectionTypeCommonParams(reader, pluginIdentifier);
return new HasManyEntitiesType(params.getPluginName(), params.getModelName(), params.getJoinFieldName(),
params.getCascade(), params.isCopyable(), dataDefinitionService);
}
private FieldType getManyToManyType(final XMLStreamReader reader, final String pluginIdentifier) {
CollectionTypeCommonParams params = new CollectionTypeCommonParams(reader, pluginIdentifier);
return new ManyToManyEntitiesType(params.getPluginName(), params.getModelName(), params.getJoinFieldName(),
params.getCascade(), params.isCopyable(), params.isLazyLoading(), dataDefinitionService);
}
private FieldType getTreeType(final XMLStreamReader reader, final String pluginIdentifier) {
CollectionTypeCommonParams params = new CollectionTypeCommonParams(reader, pluginIdentifier);
return new TreeEntitiesType(params.getPluginName(), params.getModelName(), params.getJoinFieldName(),
params.getCascade(), params.isCopyable(), dataDefinitionService);
}
private final class CollectionTypeCommonParams {
private final String pluginName;
private final String modelName;
private final String joinFieldName;
private final Cascadeable.Cascade cascade;
private final boolean isCopyable;
private final boolean isLazyLoading;
private CollectionTypeCommonParams(final XMLStreamReader reader, final String pluginIdentifier) {
pluginName = getStringAttribute(reader, TAG_PLUGIN, pluginIdentifier);
modelName = getStringAttribute(reader, TAG_MODEL);
joinFieldName = getStringAttribute(reader, TAG_JOIN_FIELD);
cascade = Cascadeable.Cascade.parse(getStringAttribute(reader, "cascade"));
isCopyable = getBooleanAttribute(reader, "copyable", false);
isLazyLoading = getBooleanAttribute(reader, "lazy", false);
}
public String getPluginName() {
return pluginName;
}
public String getModelName() {
return modelName;
}
public String getJoinFieldName() {
return joinFieldName;
}
public Cascadeable.Cascade getCascade() {
return cascade;
}
public boolean isCopyable() {
return isCopyable;
}
public boolean isLazyLoading() {
return isLazyLoading;
}
}
private FieldType getBelongsToType(final XMLStreamReader reader, final String pluginIdentifier) {
String pluginName = getStringAttribute(reader, TAG_PLUGIN, pluginIdentifier);
String modelName = getStringAttribute(reader, TAG_MODEL);
boolean lazy = getBooleanAttribute(reader, "lazy", true);
boolean isCopyable = getBooleanAttribute(reader, "copyable", true);
return new BelongsToEntityType(pluginName, modelName, dataDefinitionService, lazy, isCopyable);
}
private FieldDefinition getAuditFieldDefinition(final DataDefinitionImpl dataDefinition, final String name,
final FieldType type) {
FieldDefinitionImpl fieldDefinition = new FieldDefinitionImpl(dataDefinition, name);
fieldDefinition.withReadOnly(false);
fieldDefinition.setPersistent(true);
fieldDefinition.withType(type);
return fieldDefinition;
}
private FieldDefinition getFieldDefinition(final XMLStreamReader reader, final DataDefinitionImpl dataDefinition,
final FieldsTag fieldTag) throws XMLStreamException, HookInitializationException, ModelXmlParsingException {
String fieldType = reader.getLocalName();
String name = getStringAttribute(reader, "name");
FieldDefinitionImpl fieldDefinition = new FieldDefinitionImpl(dataDefinition, name);
fieldDefinition.withReadOnly(getBooleanAttribute(reader, "readonly", false));
fieldDefinition.withDefaultValue(getStringAttribute(reader, "default"));
fieldDefinition.setPersistent(getBooleanAttribute(reader, "persistent", true));
fieldDefinition.setExpression(getStringAttribute(reader, "expression"));
FieldType type = getFieldType(reader, dataDefinition, name, fieldTag, fieldType);
fieldDefinition.withType(type);
if (getBooleanAttribute(reader, "required", false)) {
fieldDefinition.withValidator(getValidatorDefinition(reader, new RequiredValidator()));
}
if (getBooleanAttribute(reader, "unique", false)) {
if (type.isCopyable() && !fieldDefinition.canBeBothCopyableAndUnique()) {
String message = String
.format("Unique field can not have the copyable attribute set to true. Add 'copyable=\"false\"' to #%s_%s.%s to fix it.",
dataDefinition.getPluginIdentifier(), dataDefinition.getName(), name);
throw new IllegalStateException(message);
}
fieldDefinition.withValidator(getValidatorDefinition(reader, new UniqueValidator()));
}
parseFieldValidators(reader, fieldType, fieldDefinition).forEach(fieldDefinition::withValidator);
fieldDefinition.withMissingDefaultValidators();
return fieldDefinition;
}
private Collection<FieldHookDefinition> parseFieldValidators(final XMLStreamReader reader, final String fieldType,
final FieldDefinition fieldDefinition) throws XMLStreamException, HookInitializationException,
ModelXmlParsingException {
List<FieldHookDefinition> fieldValidators = Lists.newArrayList();
while (reader.hasNext() && reader.next() > 0) {
if (isTagEnded(reader, fieldType)) {
break;
}
String tag = getTagStarted(reader);
if (tag == null) {
continue;
}
fieldValidators.add(createFieldElement(reader, fieldDefinition, tag));
}
return fieldValidators;
}
private FieldHookDefinition createFieldElement(final XMLStreamReader reader, final FieldDefinition fieldDefinition,
final String tag) throws HookInitializationException, ModelXmlParsingException {
FieldHookDefinition fieldHookDefinition;
switch (FieldTag.valueOf(tag.toUpperCase(Locale.ENGLISH))) {
case VALIDATESLENGTH:
fieldHookDefinition = getValidatorDefinition(reader, new LengthValidator(getIntegerAttribute(reader, "min"),
getIntegerAttribute(reader, "is"), getIntegerAttribute(reader, "max")));
break;
case VALIDATESUNSCALEDVALUE:
fieldHookDefinition = getValidatorDefinition(reader,
new UnscaledValueValidator(getIntegerAttribute(reader, "min"), getIntegerAttribute(reader, "is"),
getIntegerAttribute(reader, "max")));
break;
case VALIDATESSCALE:
fieldHookDefinition = getValidatorDefinition(reader, new ScaleValidator(getIntegerAttribute(reader, "min"),
getIntegerAttribute(reader, "is"), getIntegerAttribute(reader, "max")));
break;
case VALIDATESRANGE:
FieldType type = fieldDefinition.getType();
Object from = getRangeForType(getStringAttribute(reader, "from"), type);
Object to = getRangeForType(getStringAttribute(reader, "to"), type);
boolean exclusively = getBooleanAttribute(reader, "exclusively", false);
fieldHookDefinition = getValidatorDefinition(reader, new RangeValidator(from, to, exclusively));
break;
case VALIDATESWITH:
fieldHookDefinition = getValidatorDefinition(reader, new CustomValidator(getFieldHookDefinition(reader)));
break;
case VALIDATESREGEX:
fieldHookDefinition = getValidatorDefinition(reader, new RegexValidator(getStringAttribute(reader, "pattern")));
break;
default:
throw new ModelXmlParsingException("Illegal type of field's validator '" + tag + "'");
}
return fieldHookDefinition;
}
private FieldType getFieldType(final XMLStreamReader reader, final DataDefinition dataDefinition, final String fieldName,
final FieldsTag fieldTag, final String fieldType) throws XMLStreamException, ModelXmlParsingException {
// TODO DEV_TEAM consider move default value resolving from converter into concrete field type's constructor.
Boolean isCopyable = getBooleanAttribute(reader, "copyable", true);
switch (fieldTag) {
case INTEGER:
return new IntegerType(isCopyable);
case STRING:
return new StringType(isCopyable);
case FILE:
return new FileType(isCopyable);
case TEXT:
return new TextType(isCopyable);
case DECIMAL:
return new DecimalType(isCopyable);
case DATETIME:
return new DateTimeType(isCopyable);
case DATE:
return new DateType(isCopyable);
case BOOLEAN:
return new BooleanType(isCopyable);
case BELONGSTO:
return getBelongsToType(reader, dataDefinition.getPluginIdentifier());
case HASMANY:
return getHasManyType(reader, dataDefinition.getPluginIdentifier());
case MANYTOMANY:
return getManyToManyType(reader, dataDefinition.getPluginIdentifier());
case TREE:
return getTreeType(reader, dataDefinition.getPluginIdentifier());
case ENUM:
String translationPath = dataDefinition.getPluginIdentifier() + "." + dataDefinition.getName() + "." + fieldName;
return getEnumType(reader, isCopyable, translationPath);
case DICTIONARY:
return getDictionaryType(reader);
case PASSWORD:
return new PasswordType(passwordEncoder, isCopyable);
default:
throw new ModelXmlParsingException("Illegal type of field '" + fieldType + "'");
}
}
private Object getRangeForType(final String range, final FieldType type) throws ModelXmlParsingException {
if (range == null) {
return null;
} else if (type instanceof DateTimeType) {
try {
return new SimpleDateFormat(DateUtils.L_DATE_TIME_FORMAT, getLocale()).parse(range);
} catch (ParseException e) {
throw new ModelXmlParsingException("Range '" + range + "' has invalid datetime format, should match "
+ DateUtils.L_DATE_TIME_FORMAT, e);
}
} else if (type instanceof DateType) {
try {
return new SimpleDateFormat(DateUtils.L_DATE_FORMAT, getLocale()).parse(range);
} catch (ParseException e) {
throw new ModelXmlParsingException("Range '" + range + "' has invalid date format, should match "
+ DateUtils.L_DATE_FORMAT, e);
}
} else if (type instanceof DecimalType) {
return new BigDecimal(range);
} else if (type instanceof IntegerType) {
return Integer.parseInt(range);
} else {
return range;
}
}
private FieldHookDefinition getValidatorDefinition(final XMLStreamReader reader, final FieldHookDefinition validator) {
String customMessage = getStringAttribute(reader, "message");
if (StringUtils.hasText(customMessage) && validator instanceof ErrorMessageDefinition) {
((ErrorMessageDefinition) validator).setErrorMessage(customMessage);
}
return validator;
}
private EntityHookDefinition getHookDefinition(final XMLStreamReader reader) throws HookInitializationException {
return getHookDefinition(reader, null);
}
private EntityHookDefinition getHookDefinition(final XMLStreamReader reader, final String pluginIdentifier)
throws HookInitializationException {
String className = getStringAttribute(reader, "class");
String methodName = getStringAttribute(reader, "method");
return new EntityHookDefinitionImpl(className, methodName, pluginIdentifier, applicationContext);
}
private FieldHookDefinition getFieldHookDefinition(final XMLStreamReader reader) throws HookInitializationException {
return getFieldHookDefinition(reader, null);
}
private FieldHookDefinition getFieldHookDefinition(final XMLStreamReader reader, final String pluginIdentifier)
throws HookInitializationException {
String className = getStringAttribute(reader, "class");
String methodName = getStringAttribute(reader, "method");
return new FieldHookDefinitionImpl(className, methodName, pluginIdentifier, applicationContext);
}
private FieldDefinition getPriorityFieldDefinition(final XMLStreamReader reader, final DataDefinitionImpl dataDefinition) {
String scopeAttribute = getStringAttribute(reader, "scope");
FieldDefinition scopedField = null;
if (scopeAttribute != null) {
scopedField = dataDefinition.getField(scopeAttribute);
}
return new FieldDefinitionImpl(dataDefinition, getStringAttribute(reader, "name"))
.withType(new PriorityType(scopedField));
}
protected MasterModel getMasterModel(final XMLStreamReader reader) {
return new MasterModel(getStringAttribute(reader, "plugin"), getStringAttribute(reader, "model"));
}
@Aspect
static class PluginIdentifierInjectionAspect {
@Pointcut("execution(* ModelXmlToDefinitionConverterImpl.getDataDefinition(javax.xml.stream.XMLStreamReader, String)) && args(*, pluginIdentifier)")
public void execGetDataDefinition(final String pluginIdentifier) {
}
@Pointcut("execution((com.qcadoo.model.internal.api.EntityHookDefinition || com.qcadoo.model.internal.api.FieldHookDefinition) ModelXmlToDefinitionConverterImpl.*(javax.xml.stream.XMLStreamReader, String)) && args(reader, *)")
public void execHookDefinitionGetter(final XMLStreamReader reader) {
}
@Pointcut("execution(com.qcadoo.model.api.FieldDefinition ModelXmlToDefinitionConverterImpl.getFieldDefinition(javax.xml.stream.XMLStreamReader, com.qcadoo.model.internal.DataDefinitionImpl, com.qcadoo.model.internal.AbstractModelXmlConverter.FieldsTag)) && args(reader, ..)")
public void execFieldDefinitionGetter(final XMLStreamReader reader) {
}
@Around("execHookDefinitionGetter(reader) && cflow(execGetDataDefinition(pluginIdentifier))")
public Object appendPluginIdentifierToHook(final ProceedingJoinPoint pjp, final XMLStreamReader reader,
final String pluginIdentifier) throws Throwable {
Object[] args = pjp.getArgs();
args[1] = getSourcePluginName(reader, pluginIdentifier);
return pjp.proceed(args);
}
@Around("execFieldDefinitionGetter(reader) && cflow(execGetDataDefinition(pluginIdentifier))")
public Object appendPluginIdentifierToField(final ProceedingJoinPoint pjp, final XMLStreamReader reader,
final String pluginIdentifier) throws Throwable {
String sourcePluginIdentifier = getSourcePluginName(reader, pluginIdentifier);
FieldDefinitionImpl fieldDefinition = (FieldDefinitionImpl) pjp.proceed();
fieldDefinition.setPluginIdentifier(sourcePluginIdentifier);
return fieldDefinition;
}
private String getSourcePluginName(final XMLStreamReader reader, final String targetPluginName) {
String sourcePluginIdentifier = reader.getAttributeValue(null, "sourcePluginIdentifier");
if (sourcePluginIdentifier == null && targetPluginName == null) {
throw new IllegalStateException("Missing plugin identifier");
} else if (sourcePluginIdentifier == null) {
return targetPluginName;
} else {
return sourcePluginIdentifier;
}
}
}
}