package org.springframework.roo.addon.web.mvc.controller.details;
import static org.springframework.roo.classpath.customdata.CustomDataKeys.COUNT_ALL_METHOD;
import static org.springframework.roo.classpath.customdata.CustomDataKeys.FIND_ALL_METHOD;
import static org.springframework.roo.classpath.customdata.CustomDataKeys.FIND_ENTRIES_METHOD;
import static org.springframework.roo.classpath.customdata.CustomDataKeys.FIND_METHOD;
import static org.springframework.roo.classpath.customdata.CustomDataKeys.IDENTIFIER_ACCESSOR_METHOD;
import static org.springframework.roo.classpath.customdata.CustomDataKeys.IDENTIFIER_TYPE;
import static org.springframework.roo.classpath.customdata.CustomDataKeys.MERGE_METHOD;
import static org.springframework.roo.classpath.customdata.CustomDataKeys.PERSIST_METHOD;
import static org.springframework.roo.classpath.customdata.CustomDataKeys.REMOVE_METHOD;
import static org.springframework.roo.classpath.customdata.CustomDataKeys.VERSION_ACCESSOR_METHOD;
import static org.springframework.roo.model.Jsr303JavaType.NOT_NULL;
import static org.springframework.roo.model.RooJavaType.ROO_WEB_SCAFFOLD;
import static org.springframework.roo.model.SpringJavaType.DATE_TIME_FORMAT;
import java.beans.Introspector;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.logging.Logger;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.springframework.roo.addon.finder.FinderMetadata;
import org.springframework.roo.addon.plural.PluralMetadata;
import org.springframework.roo.addon.web.mvc.controller.scaffold.WebScaffoldMetadata;
import org.springframework.roo.classpath.PhysicalTypeCategory;
import org.springframework.roo.classpath.PhysicalTypeIdentifier;
import org.springframework.roo.classpath.TypeLocationService;
import org.springframework.roo.classpath.customdata.tagkeys.MethodMetadataCustomDataKey;
import org.springframework.roo.classpath.details.BeanInfoUtils;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails;
import org.springframework.roo.classpath.details.FieldMetadata;
import org.springframework.roo.classpath.details.FieldMetadataBuilder;
import org.springframework.roo.classpath.details.MemberFindingUtils;
import org.springframework.roo.classpath.details.MethodMetadata;
import org.springframework.roo.classpath.details.annotations.AnnotatedJavaType;
import org.springframework.roo.classpath.details.annotations.AnnotationAttributeValue;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadata;
import org.springframework.roo.classpath.details.annotations.ClassAttributeValue;
import org.springframework.roo.classpath.layers.LayerService;
import org.springframework.roo.classpath.layers.LayerType;
import org.springframework.roo.classpath.layers.MemberTypeAdditions;
import org.springframework.roo.classpath.layers.MethodParameter;
import org.springframework.roo.classpath.persistence.PersistenceMemberLocator;
import org.springframework.roo.classpath.scanner.MemberDetails;
import org.springframework.roo.classpath.scanner.MemberDetailsScanner;
import org.springframework.roo.metadata.MetadataDependencyRegistry;
import org.springframework.roo.metadata.MetadataIdentificationUtils;
import org.springframework.roo.metadata.MetadataService;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.model.JdkJavaType;
import org.springframework.roo.project.LogicalPath;
import org.springframework.roo.support.logging.HandlerUtils;
import org.springframework.roo.support.util.CollectionUtils;
/**
* Implementation of {@link WebMetadataService} to retrieve various metadata
* information for use by Web scaffolding add-ons.
*
* @author Stefan Schmidt
* @since 1.1.2
*/
@Component
@Service
public class WebMetadataServiceImpl implements WebMetadataService {
private static final MethodParameter FIRST_RESULT_PARAMETER = new MethodParameter(
JavaType.INT_PRIMITIVE, "firstResult");
private static final int LAYER_POSITION = LayerType.HIGHEST.getPosition();
private static final Logger LOGGER = HandlerUtils
.getLogger(WebMetadataServiceImpl.class);
private static final MethodParameter MAX_RESULTS_PARAMETER = new MethodParameter(
JavaType.INT_PRIMITIVE, "sizeNo");
@Reference private LayerService layerService;
@Reference private MemberDetailsScanner memberDetailsScanner;
@Reference private MetadataDependencyRegistry metadataDependencyRegistry;
@Reference private MetadataService metadataService;
@Reference private PersistenceMemberLocator persistenceMemberLocator;
@Reference private TypeLocationService typeLocationService;
private final Map<String, String> pathMap = new HashMap<String, String>();
private String getControllerPathForType(final JavaType type,
final String metadataIdentificationString) {
if (pathMap.containsKey(type.getFullyQualifiedTypeName())
&& !typeLocationService.hasTypeChanged(getClass().getName(),
type)) {
return pathMap.get(type.getFullyQualifiedTypeName());
}
String webScaffoldMetadataKey = null;
WebScaffoldMetadata webScaffoldMetadata = null;
for (final ClassOrInterfaceTypeDetails cid : typeLocationService
.findClassesOrInterfaceDetailsWithAnnotation(ROO_WEB_SCAFFOLD)) {
for (final AnnotationMetadata annotation : cid.getAnnotations()) {
if (annotation.getAnnotationType().equals(ROO_WEB_SCAFFOLD)) {
final AnnotationAttributeValue<?> formBackingObject = annotation
.getAttribute(new JavaSymbolName(
"formBackingObject"));
if (formBackingObject instanceof ClassAttributeValue) {
final ClassAttributeValue formBackingObjectValue = (ClassAttributeValue) formBackingObject;
if (formBackingObjectValue.getValue().equals(type)) {
final AnnotationAttributeValue<String> path = annotation
.getAttribute("path");
if (path != null) {
final String pathString = path.getValue();
pathMap.put(type.getFullyQualifiedTypeName(),
pathString);
return pathString;
}
final LogicalPath cidPath = PhysicalTypeIdentifier
.getPath(cid.getDeclaredByMetadataId());
webScaffoldMetadataKey = WebScaffoldMetadata
.createIdentifier(cid.getName(), cidPath);
webScaffoldMetadata = (WebScaffoldMetadata) metadataService
.get(webScaffoldMetadataKey);
break;
}
}
}
}
}
if (webScaffoldMetadata != null) {
registerDependency(webScaffoldMetadataKey,
metadataIdentificationString);
final String path = webScaffoldMetadata.getAnnotationValues()
.getPath();
pathMap.put(type.getFullyQualifiedTypeName(), path);
return path;
}
return getPlural(type, metadataIdentificationString).toLowerCase();
}
public Map<MethodMetadataCustomDataKey, MemberTypeAdditions> getCrudAdditions(
final JavaType domainType, final String metadataId) {
final String domainTypeMid = typeLocationService
.getPhysicalTypeIdentifier(domainType);
if (domainTypeMid != null) {
metadataDependencyRegistry.registerDependency(domainTypeMid,
metadataId);
}
final JavaTypePersistenceMetadataDetails persistenceDetails = getJavaTypePersistenceMetadataDetails(
domainType, getMemberDetails(domainType), metadataId);
if (persistenceDetails == null) {
return Collections.emptyMap();
}
final Map<MethodMetadataCustomDataKey, MemberTypeAdditions> additions = new HashMap<MethodMetadataCustomDataKey, MemberTypeAdditions>();
additions.put(COUNT_ALL_METHOD, persistenceDetails.getCountMethod());
additions.put(REMOVE_METHOD, persistenceDetails.getRemoveMethod());
additions.put(FIND_METHOD, persistenceDetails.getFindMethod());
additions.put(FIND_ALL_METHOD, persistenceDetails.getFindAllMethod());
additions.put(FIND_ENTRIES_METHOD,
persistenceDetails.getFindEntriesMethod());
additions.put(MERGE_METHOD, persistenceDetails.getMergeMethod());
additions.put(PERSIST_METHOD, persistenceDetails.getPersistMethod());
return additions;
}
public Map<JavaSymbolName, DateTimeFormatDetails> getDatePatterns(
final JavaType javaType, final MemberDetails memberDetails,
final String metadataIdentificationString) {
Validate.notNull(javaType, "Java type required");
Validate.notNull(memberDetails, "Member details required");
final MethodMetadata identifierAccessor = persistenceMemberLocator
.getIdentifierAccessor(javaType);
final MethodMetadata versionAccessor = persistenceMemberLocator
.getVersionAccessor(javaType);
final Map<JavaSymbolName, DateTimeFormatDetails> dates = new LinkedHashMap<JavaSymbolName, DateTimeFormatDetails>();
final JavaTypePersistenceMetadataDetails javaTypePersistenceMetadataDetails = getJavaTypePersistenceMetadataDetails(
javaType, memberDetails, metadataIdentificationString);
for (final MethodMetadata method : memberDetails.getMethods()) {
// Only interested in accessors
if (!BeanInfoUtils.isAccessorMethod(method)) {
continue;
}
// Not interested in fields that are not exposed via a mutator and
// accessor and in identifiers and version fields
if (method.hasSameName(identifierAccessor, versionAccessor)) {
continue;
}
final FieldMetadata field = BeanInfoUtils
.getFieldForJavaBeanMethod(memberDetails, method);
if (field == null
|| !BeanInfoUtils.hasAccessorAndMutator(field,
memberDetails)) {
continue;
}
final JavaType returnType = method.getReturnType();
if (!JdkJavaType.isDateField(returnType)) {
continue;
}
final AnnotationMetadata annotation = MemberFindingUtils
.getAnnotationOfType(field.getAnnotations(),
DATE_TIME_FORMAT);
final JavaSymbolName patternSymbol = new JavaSymbolName("pattern");
final JavaSymbolName styleSymbol = new JavaSymbolName("style");
DateTimeFormatDetails dateTimeFormat = null;
if (annotation != null) {
if (annotation.getAttributeNames().contains(styleSymbol)) {
dateTimeFormat = DateTimeFormatDetails.withStyle(annotation
.getAttribute(styleSymbol).getValue().toString());
}
else if (annotation.getAttributeNames().contains(patternSymbol)) {
dateTimeFormat = DateTimeFormatDetails
.withPattern(annotation.getAttribute(patternSymbol)
.getValue().toString());
}
}
if (dateTimeFormat != null) {
registerDependency(field.getDeclaredByMetadataId(),
metadataIdentificationString);
dates.put(field.getFieldName(), dateTimeFormat);
if (javaTypePersistenceMetadataDetails != null) {
for (final String finder : javaTypePersistenceMetadataDetails
.getFinderNames()) {
if (finder.contains(StringUtils.capitalize(field
.getFieldName().getSymbolName()) + "Between")) {
dates.put(
new JavaSymbolName("min"
+ StringUtils.capitalize(field
.getFieldName()
.getSymbolName())),
dateTimeFormat);
dates.put(
new JavaSymbolName("max"
+ StringUtils.capitalize(field
.getFieldName()
.getSymbolName())),
dateTimeFormat);
}
}
}
}
else {
LOGGER.warning("It is recommended to use @DateTimeFormat(style=\"M-\") on "
+ field.getFieldType().getFullyQualifiedTypeName()
+ "."
+ field.getFieldName()
+ " to use automatic date conversion in Spring MVC");
}
}
return Collections.unmodifiableMap(dates);
}
public List<JavaTypeMetadataDetails> getDependentApplicationTypeMetadata(
final JavaType javaType, final MemberDetails memberDetails,
final String metadataIdentificationString) {
Validate.notNull(javaType, "Java type required");
Validate.notNull(memberDetails, "Member details required");
final List<JavaTypeMetadataDetails> dependentTypes = new ArrayList<JavaTypeMetadataDetails>();
for (final MethodMetadata method : memberDetails.getMethods()) {
final JavaType type = method.getReturnType();
if (BeanInfoUtils.isAccessorMethod(method)
&& isApplicationType(type)) {
final FieldMetadata field = BeanInfoUtils
.getFieldForJavaBeanMethod(memberDetails, method);
if (field != null
&& MemberFindingUtils.getAnnotationOfType(
field.getAnnotations(), NOT_NULL) != null) {
final MemberDetails typeMemberDetails = getMemberDetails(type);
if (getJavaTypePersistenceMetadataDetails(type,
typeMemberDetails, metadataIdentificationString) != null) {
dependentTypes
.add(getJavaTypeMetadataDetails(type,
typeMemberDetails,
metadataIdentificationString));
}
}
}
}
return Collections.unmodifiableList(dependentTypes);
}
public Set<FinderMetadataDetails> getDynamicFinderMethodsAndFields(
final JavaType formBackingType,
final MemberDetails formBackingTypeDetails,
final String metadataIdentificationString) {
Validate.notNull(formBackingType, "Java type required");
Validate.notNull(formBackingTypeDetails, "Member details required");
final ClassOrInterfaceTypeDetails javaTypeDetails = typeLocationService
.getTypeDetails(formBackingType);
Validate.notNull(formBackingType,
"Class or interface type details isn't available for type '"
+ formBackingType + "'");
final LogicalPath logicalPath = PhysicalTypeIdentifier
.getPath(javaTypeDetails.getDeclaredByMetadataId());
final String finderMetadataKey = FinderMetadata.createIdentifier(
formBackingType, logicalPath);
registerDependency(finderMetadataKey, metadataIdentificationString);
final FinderMetadata finderMetadata = (FinderMetadata) metadataService
.get(finderMetadataKey);
if (finderMetadata == null) {
return null;
}
final SortedSet<FinderMetadataDetails> finderMetadataDetails = new TreeSet<FinderMetadataDetails>();
for (final MethodMetadata method : finderMetadata
.getAllDynamicFinders()) {
final List<JavaSymbolName> parameterNames = method
.getParameterNames();
final List<JavaType> parameterTypes = AnnotatedJavaType
.convertFromAnnotatedJavaTypes(method.getParameterTypes());
final List<FieldMetadata> fields = new ArrayList<FieldMetadata>();
for (int i = 0; i < parameterTypes.size(); i++) {
JavaSymbolName fieldName = null;
if (parameterNames.get(i).getSymbolName().startsWith("max")
|| parameterNames.get(i).getSymbolName()
.startsWith("min")) {
fieldName = new JavaSymbolName(
Introspector.decapitalize(StringUtils
.capitalize(parameterNames.get(i)
.getSymbolName().substring(3))));
}
else {
fieldName = parameterNames.get(i);
}
final FieldMetadata field = BeanInfoUtils
.getFieldForPropertyName(formBackingTypeDetails,
fieldName);
if (field != null) {
final FieldMetadataBuilder fieldMd = new FieldMetadataBuilder(
field);
fieldMd.setFieldName(parameterNames.get(i));
fields.add(fieldMd.build());
}
}
final FinderMetadataDetails details = new FinderMetadataDetails(
method.getMethodName().getSymbolName(), method, fields);
finderMetadataDetails.add(details);
}
return Collections.unmodifiableSortedSet(finderMetadataDetails);
}
public FieldMetadata getIdentifierField(final JavaType javaType) {
return CollectionUtils.firstElementOf(persistenceMemberLocator
.getIdentifierFields(javaType));
}
public JavaTypeMetadataDetails getJavaTypeMetadataDetails(
final JavaType javaType, final MemberDetails memberDetails,
final String metadataIdentificationString) {
Validate.notNull(javaType, "Java type required");
registerDependency(
memberDetails.getDetails()
.get(memberDetails.getDetails().size() - 1)
.getDeclaredByMetadataId(),
metadataIdentificationString);
return new JavaTypeMetadataDetails(
javaType,
getPlural(javaType, metadataIdentificationString),
isEnumType(javaType),
isApplicationType(javaType),
getJavaTypePersistenceMetadataDetails(javaType, memberDetails,
metadataIdentificationString),
getControllerPathForType(javaType, metadataIdentificationString));
}
public JavaTypePersistenceMetadataDetails getJavaTypePersistenceMetadataDetails(
final JavaType javaType, final MemberDetails memberDetails,
final String metadataIdentificationString) {
Validate.notNull(javaType, "Java type required");
Validate.notNull(memberDetails, "Member details required");
Validate.notBlank(metadataIdentificationString, "Metadata id required");
final MethodMetadata idAccessor = memberDetails
.getMostConcreteMethodWithTag(IDENTIFIER_ACCESSOR_METHOD);
if (idAccessor == null) {
return null;
}
final FieldMetadata idField = CollectionUtils
.firstElementOf(persistenceMemberLocator
.getIdentifierFields(javaType));
if (idField == null) {
return null;
}
final JavaType idType = persistenceMemberLocator
.getIdentifierType(javaType);
if (idType == null) {
return null;
}
registerDependency(idAccessor.getDeclaredByMetadataId(),
metadataIdentificationString);
registerDependency(idField.getDeclaredByMetadataId(),
metadataIdentificationString);
final MethodParameter entityParameter = new MethodParameter(javaType,
JavaSymbolName.getReservedWordSafeName(javaType));
final MethodParameter idParameter = new MethodParameter(idType, idField
.getFieldName().getSymbolName());
final MethodMetadata versionAccessor = memberDetails
.getMostConcreteMethodWithTag(VERSION_ACCESSOR_METHOD);
final MemberTypeAdditions persistMethod = layerService
.getMemberTypeAdditions(metadataIdentificationString,
PERSIST_METHOD.name(), javaType, idType,
LAYER_POSITION, entityParameter);
final MemberTypeAdditions removeMethod = layerService
.getMemberTypeAdditions(metadataIdentificationString,
REMOVE_METHOD.name(), javaType, idType, LAYER_POSITION,
entityParameter);
final MemberTypeAdditions mergeMethod = layerService
.getMemberTypeAdditions(metadataIdentificationString,
MERGE_METHOD.name(), javaType, idType, LAYER_POSITION,
entityParameter);
final MemberTypeAdditions findAllMethod = layerService
.getMemberTypeAdditions(metadataIdentificationString,
FIND_ALL_METHOD.name(), javaType, idType,
LAYER_POSITION);
final MemberTypeAdditions findMethod = layerService
.getMemberTypeAdditions(metadataIdentificationString,
FIND_METHOD.name(), javaType, idType, LAYER_POSITION,
idParameter);
final MemberTypeAdditions countMethod = layerService
.getMemberTypeAdditions(metadataIdentificationString,
COUNT_ALL_METHOD.name(), javaType, idType,
LAYER_POSITION);
final MemberTypeAdditions findEntriesMethod = layerService
.getMemberTypeAdditions(metadataIdentificationString,
FIND_ENTRIES_METHOD.name(), javaType, idType,
LAYER_POSITION, FIRST_RESULT_PARAMETER,
MAX_RESULTS_PARAMETER);
final List<String> dynamicFinderNames = memberDetails
.getDynamicFinderNames();
return new JavaTypePersistenceMetadataDetails(idType, idField,
idAccessor, versionAccessor, persistMethod, mergeMethod,
removeMethod, findAllMethod, findMethod, countMethod,
findEntriesMethod, dynamicFinderNames, isRooIdentifier(
javaType, memberDetails),
persistenceMemberLocator.getEmbeddedIdentifierFields(javaType));
}
public MemberDetails getMemberDetails(final JavaType javaType) {
final ClassOrInterfaceTypeDetails cid = typeLocationService
.getTypeDetails(javaType);
Validate.notNull(
cid,
"Unable to obtain physical type metadata for type "
+ javaType.getFullyQualifiedTypeName());
return memberDetailsScanner.getMemberDetails(
WebMetadataServiceImpl.class.getName(), cid);
}
private String getPlural(final JavaType javaType,
final String metadataIdentificationString) {
Validate.notNull(javaType, "Java type required");
Validate.notNull(metadataService, "Metadata service required");
final ClassOrInterfaceTypeDetails javaTypeDetails = typeLocationService
.getTypeDetails(javaType);
Validate.notNull(javaType,
"Class or interface type details isn't available for type '"
+ javaType + "'");
final LogicalPath logicalPath = PhysicalTypeIdentifier
.getPath(javaTypeDetails.getDeclaredByMetadataId());
final String pluralMetadataKey = PluralMetadata.createIdentifier(
javaType, logicalPath);
final PluralMetadata pluralMetadata = (PluralMetadata) metadataService
.get(pluralMetadataKey);
if (pluralMetadata != null) {
registerDependency(pluralMetadata.getId(),
metadataIdentificationString);
final String plural = pluralMetadata.getPlural();
if (plural.equalsIgnoreCase(javaType.getSimpleTypeName())) {
return plural + "Items";
}
else {
return plural;
}
}
return javaType.getSimpleTypeName() + "s";
}
public SortedMap<JavaType, JavaTypeMetadataDetails> getRelatedApplicationTypeMetadata(
final JavaType baseType, final MemberDetails baseTypeDetails,
final String metadataIdentificationString) {
Validate.notNull(baseType, "Java type required");
Validate.notNull(baseTypeDetails, "Member details required");
Validate.isTrue(isApplicationType(baseType), "The type " + baseType
+ " does not belong to this application");
final SortedMap<JavaType, JavaTypeMetadataDetails> specialTypes = new TreeMap<JavaType, JavaTypeMetadataDetails>();
specialTypes.put(
baseType,
getJavaTypeMetadataDetails(baseType, baseTypeDetails,
metadataIdentificationString));
for (final JavaType fieldType : baseTypeDetails
.getPersistentFieldTypes(baseType, persistenceMemberLocator)) {
if (isApplicationType(fieldType)) {
final MemberDetails fieldTypeDetails = getMemberDetails(fieldType);
specialTypes.put(
fieldType,
getJavaTypeMetadataDetails(fieldType, fieldTypeDetails,
metadataIdentificationString));
}
}
return specialTypes;
}
public List<FieldMetadata> getScaffoldEligibleFieldMetadata(
final JavaType javaType, final MemberDetails memberDetails,
final String metadataIdentificationString) {
Validate.notNull(javaType, "Java type required");
Validate.notNull(memberDetails, "Member details required");
final MethodMetadata identifierAccessor = persistenceMemberLocator
.getIdentifierAccessor(javaType);
final MethodMetadata versionAccessor = persistenceMemberLocator
.getVersionAccessor(javaType);
final Map<JavaSymbolName, FieldMetadata> fields = new LinkedHashMap<JavaSymbolName, FieldMetadata>();
final List<MethodMetadata> methods = memberDetails.getMethods();
for (final MethodMetadata method : methods) {
// Only interested in accessors
if (!BeanInfoUtils.isAccessorMethod(method)
|| method.hasSameName(identifierAccessor, versionAccessor)) {
continue;
}
final FieldMetadata field = BeanInfoUtils
.getFieldForJavaBeanMethod(memberDetails, method);
if (field == null
|| !BeanInfoUtils.hasAccessorAndMutator(field,
memberDetails)) {
continue;
}
final JavaSymbolName fieldName = field.getFieldName();
registerDependency(method.getDeclaredByMetadataId(),
metadataIdentificationString);
if (!fields.containsKey(fieldName)) {
fields.put(fieldName, field);
}
}
return Collections.unmodifiableList(new ArrayList<FieldMetadata>(fields
.values()));
}
public boolean isApplicationType(final JavaType javaType) {
return typeLocationService.isInProject(javaType);
}
private boolean isEnumType(final JavaType javaType) {
Validate.notNull(javaType, "Java type required");
Validate.notNull(metadataService, "Metadata service required");
final ClassOrInterfaceTypeDetails javaTypeDetails = typeLocationService
.getTypeDetails(javaType);
if (javaTypeDetails != null) {
if (javaTypeDetails.getPhysicalTypeCategory().equals(
PhysicalTypeCategory.ENUMERATION)) {
return true;
}
}
return false;
}
public boolean isRooIdentifier(final JavaType javaType,
final MemberDetails memberDetails) {
Validate.notNull(javaType, "Java type required");
Validate.notNull(memberDetails, "Member details required");
return MemberFindingUtils.getMemberHoldingTypeDetailsWithTag(
memberDetails, IDENTIFIER_TYPE).size() > 0;
}
private void registerDependency(final String upstreamDependency,
final String downStreamDependency) {
if (metadataDependencyRegistry != null
&& StringUtils.isNotBlank(upstreamDependency)
&& StringUtils.isNotBlank(downStreamDependency)
&& !upstreamDependency.equals(downStreamDependency)
&& !MetadataIdentificationUtils.getMetadataClass(
downStreamDependency).equals(
MetadataIdentificationUtils
.getMetadataClass(upstreamDependency))) {
metadataDependencyRegistry.registerDependency(upstreamDependency,
downStreamDependency);
}
}
}