// ============================================================================
//
// Copyright (C) 2006-2016 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================
package org.talend.mdm.repository.core.validate.datamodel.validator.impl;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.collections.map.MultiKeyMap;
import org.apache.log4j.Logger;
import org.talend.mdm.commmon.metadata.*;
import org.talend.mdm.commmon.metadata.validation.ValidationFactory;
import org.talend.mdm.commmon.metadata.validation.ValidationRule;
import org.talend.mdm.repository.core.validate.datamodel.IChecker;
import org.talend.mdm.repository.core.validate.datamodel.validator.ModelValidationMessage;
import org.talend.mdm.repository.core.validate.datamodel.validator.rule.IComponentValidationRule;
import org.w3c.dom.Element;
public class DataModelChecker implements IChecker<ModelValidationMessage> {
static Logger log = Logger.getLogger(DataModelChecker.class);
public static String getDataModelName(String fileName) {
Pattern pattern = Pattern.compile("(\\w*?)_(\\d*?)\\.(\\d*?)\\.xsd"); //$NON-NLS-1$
Matcher matcher = pattern.matcher(fileName);
if (matcher.find()) {
return matcher.group(1);
}
return fileName;
}
@Override
public List<ModelValidationMessage> toCheck(File file) {
if (!file.exists()) {
throw new IllegalArgumentException("File '" + file + "' does not exist.");
}
if (!file.canRead()) {
throw new IllegalArgumentException("File '" + file + "' exists but cannot be read.");
}
ValidationHandlerAdapter validationHandler = new ValidationHandlerAdapter(getDataModelName(file.getName()));
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
MetadataRepository repository = new MetadataRepository();
repository.load(inputStream, validationHandler);
} catch (FileNotFoundException e) {
throw new RuntimeException("Could not open file '" + file + "'.", e);
} catch (RuntimeException e) {
validationHandler.error(TypeMetadataAdapter.INSTANCE, e.getMessage(), null, -1, -1, ValidationError.UNCAUGHT_ERROR);
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
return validationHandler.getMessages();
}
private static class ValidationHandlerAdapter implements ValidationHandler {
public static final String ANONYMOUS_TYPE_NAME = "<Anonymous>"; //$NON-NLS-1$
private final String dataModelName;
private final Map<ValidationError, MultiKeyMap> errors = new HashMap<ValidationError, MultiKeyMap>();
private int errorCount;
public ValidationHandlerAdapter(String dataModelName) {
this.dataModelName = dataModelName;
}
private static String getTypeName(TypeMetadata type) {
String name = type.getName();
if (name.startsWith(MetadataRepository.ANONYMOUS_PREFIX)) {
name = ANONYMOUS_TYPE_NAME;
}
return name;
}
private static int getValue(Integer integer, int defaultValue) {
if (integer == null) {
return defaultValue;
} else {
return integer;
}
}
private static String getEntityName(FieldMetadata field) {
try {
ComplexTypeMetadata containingType = field.getContainingType().getEntity();
String name = containingType.getName();
if (name.startsWith(MetadataRepository.ANONYMOUS_PREFIX)) {
name = ANONYMOUS_TYPE_NAME;
}
return name;
} catch (Exception e) {
return ""; //$NON-NLS-1$
}
}
@Override
public void fatal(TypeMetadata type, String message, Element element, Integer lineNumber, Integer columnNumber,
ValidationError error) {
error(type, message, element, getValue(lineNumber, -1), getValue(columnNumber, -1), error);
}
@Override
public void error(TypeMetadata type, String message, Element element, Integer lineNumber, Integer columnNumber,
ValidationError error) {
if (error != ValidationError.XML_SCHEMA) {
int group = type.isInstantiable() ? IComponentValidationRule.MSG_GROUP_ENTITY
: IComponentValidationRule.MSG_GROUP_TYPE;
ModelValidationMessage validationMessage = new ModelValidationMessage(IComponentValidationRule.SEV_ERROR,
message,
"key", // TODO
dataModelName, getValue(lineNumber, -1), getValue(columnNumber, -1), group, element, getTypeName(type),
getTypeName(type), getTypeName(type));
addMessage(getValue(lineNumber, -1), getValue(columnNumber, -1), error, validationMessage);
errorCount++;
}
}
private void addMessage(int lineNumber, int columnNumber, ValidationError error, ModelValidationMessage validationMessage) {
MultiKeyMap errorsByType = errors.get(error);
if (errorsByType == null) {
errorsByType = new MultiKeyMap();
errors.put(error, errorsByType);
}
errorsByType.put(getValue(lineNumber, -1), getValue(columnNumber, -1), validationMessage);
}
@Override
public void warning(TypeMetadata type, String message, Element element, Integer lineNumber, Integer columnNumber,
ValidationError error) {
int group = type.isInstantiable() ? IComponentValidationRule.MSG_GROUP_ENTITY
: IComponentValidationRule.MSG_GROUP_TYPE;
ModelValidationMessage validationMessage = new ModelValidationMessage(IComponentValidationRule.SEV_WARNING,
message,
"key", // TODO
dataModelName, getValue(lineNumber, -1), getValue(columnNumber, -1), group, element, getTypeName(type),
getTypeName(type), getTypeName(type));
addMessage(getValue(lineNumber, -1), getValue(columnNumber, -1), error, validationMessage);
}
@Override
public void fatal(FieldMetadata field, String message, Element element, Integer lineNumber, Integer columnNumber,
ValidationError error) {
error(field, message, element, getValue(lineNumber, -1), getValue(columnNumber, -1), error);
}
@Override
public void error(FieldMetadata field, String message, Element element, Integer lineNumber, Integer columnNumber,
ValidationError error) {
if (error != ValidationError.XML_SCHEMA) {
int group;
try {
ComplexTypeMetadata containingType = field.getContainingType().getEntity();
group = containingType.isInstantiable() ? IComponentValidationRule.MSG_GROUP_ENTITY
: IComponentValidationRule.MSG_GROUP_TYPE;
} catch (Exception e) {
group = IComponentValidationRule.MSG_GROUP_ENTITY;
}
ModelValidationMessage validationMessage = new ModelValidationMessage(IComponentValidationRule.SEV_ERROR,
message,
"key", // TODO
dataModelName, getValue(lineNumber, -1), getValue(columnNumber, -1), group, element,
getEntityName(field), getEntityName(field), field.getPath());
addMessage(getValue(lineNumber, -1), getValue(columnNumber, -1), error, validationMessage);
errorCount++;
}
}
@Override
public void warning(FieldMetadata field, String message, Element element, Integer lineNumber, Integer columnNumber,
ValidationError error) {
int group = field.getContainingType().isInstantiable() ? IComponentValidationRule.MSG_GROUP_ENTITY
: IComponentValidationRule.MSG_GROUP_TYPE;
ModelValidationMessage validationMessage = new ModelValidationMessage(IComponentValidationRule.SEV_WARNING,
message,
"key", // TODO
dataModelName, getValue(lineNumber, -1), getValue(columnNumber, -1), group, element, getEntityName(field),
getEntityName(field), field.getPath());
addMessage(getValue(lineNumber, -1), getValue(columnNumber, -1), error, validationMessage);
}
public List<ModelValidationMessage> getMessages() {
List<ModelValidationMessage> messages = new LinkedList<ModelValidationMessage>();
for (Map.Entry<ValidationError, MultiKeyMap> error : errors.entrySet()) {
messages.addAll(error.getValue().values());
}
return messages;
}
@Override
public void end() {
}
@Override
public int getErrorCount() {
return errorCount;
}
}
}
class TypeMetadataAdapter implements TypeMetadata {
final static TypeMetadataAdapter INSTANCE = new TypeMetadataAdapter();
private TypeMetadataAdapter() {
}
@Override
public <T> T accept(MetadataVisitor<T> visitor) {
return null;
}
@Override
public void setData(String key, Object data) {
}
@Override
public <X> X getData(String key) {
return null;
}
@Override
public Collection<TypeMetadata> getSuperTypes() {
return null;
}
@Override
public void addSuperType(TypeMetadata superType) {
}
@Override
public String getName() {
return ""; //$NON-NLS-1$
}
@Override
public void setName(String name) {
}
@Override
public String getNamespace() {
return null;
}
@Override
public boolean isAssignableFrom(TypeMetadata type) {
return false;
}
@Override
public TypeMetadata copy() {
return null;
}
@Override
public TypeMetadata copyShallow() {
return null;
}
@Override
public TypeMetadata freeze() {
return null;
}
@Override
public boolean isInstantiable() {
return true;
}
@Override
public void setInstantiable(boolean isInstantiable) {
}
@Override
public boolean isFrozen() {
return false;
}
@Override
public void validate(ValidationHandler handler) {
}
@Override
public ValidationRule createValidationRule() {
return ValidationFactory.getRule(this);
}
}