package gov.nist.registry.common2.registry.validation;
import gov.nist.registry.common2.exception.MetadataException;
import gov.nist.registry.common2.exception.XdsInternalException;
import gov.nist.registry.common2.registry.Classification;
import gov.nist.registry.common2.registry.Metadata;
import gov.nist.registry.common2.registry.MetadataSupport;
import gov.nist.registry.common2.registry.RegistryErrorList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import org.apache.axiom.om.OMElement;
import org.openhealthtools.openexchange.actorconfig.net.CodeSet;
import org.openhealthtools.openexchange.actorconfig.net.IConnectionDescription;
import org.openhealthtools.openexchange.patient.data.Identifier;
import org.openhealthtools.openexchange.utils.Pair;
//this gets invoked from both Validator.java and directly from Repository. Should optimize the implementation so that codes.xml
//gets cached in memory.
public class CodeValidation {
Metadata m;
RegistryErrorList rel;
boolean is_submit;
boolean xds_b;
IConnectionDescription connection;
List<Identifier> assigning_authorities;
HashMap<String, String> mime_map; // mime => ext
HashMap<String, String> ext_map; // ext => mime
public CodeValidation(Metadata m, boolean is_submit, boolean xds_b,
RegistryErrorList rel, IConnectionDescription connection)
throws XdsInternalException {
this.m = m;
this.rel = rel;
this.is_submit = is_submit;
this.xds_b = xds_b;
this.connection = connection;
loadCodes();
}
// this is used for easy access to mime lookup
public CodeValidation(IConnectionDescription connection) throws XdsInternalException {
this.connection = connection;
loadCodes();
}
void loadCodes() throws XdsInternalException {
assigning_authorities = new ArrayList<Identifier>();
Identifier aa = connection.getIdentifier("AssigningAuthority");
this.assigning_authorities.add(aa);
build_mime_map();
}
public boolean isValidMimeType(String mime_type) {
return mime_map.containsKey(mime_type);
}
public Collection<String> getKnownFileExtensions() {
return ext_map.keySet();
}
public String getMimeTypeForExt(String ext) {
return ext_map.get(ext);
}
public String getExtForMimeType(String mime_type) {
return mime_map.get(mime_type);
}
private void build_mime_map() throws XdsInternalException {
CodeSet mimeTypeCodeSet = connection.getCodeSet("mimeType");
if (mimeTypeCodeSet == null) throw new XdsInternalException("CodeValidation.java: Configuration Error: Cannot find mime type table");
mime_map = new HashMap<String, String>();
ext_map = new HashMap<String, String>();
Set<Pair> codes = mimeTypeCodeSet.getCodeSetKeys();
for (Pair code : codes) {
String ext = mimeTypeCodeSet.getExt((String)code._first, (String)code._second);
if (ext == null) throw new XdsInternalException("CodeValidation.java: Configuration Error: Cannot find ext for mime type:" + (String)code._first );
mime_map.put((String)code._first, ext);
ext_map.put(ext, (String)code._first);
}
}
public List<Identifier> getAssigningAuthorities() {
return assigning_authorities;
}
public void run() throws MetadataException, XdsInternalException {
List<String> all_object_ids = m.getObjectIds(m.getAllObjects());
for (String obj_id : all_object_ids) {
List<OMElement> classifications = m.getClassifications(obj_id);
for (OMElement cl_ele : classifications) {
Classification cl = new Classification(cl_ele);
validate(cl);
validateAssocClassifications(cl);
}
}
for (OMElement doc_ele : m.getExtrinsicObjects()) {
String mime_type = doc_ele.getAttributeValue(MetadataSupport.mime_type_qname);
if ( !isValidMimeType(mime_type)) {
err("Mime type, " + mime_type + ", is not available in this Affinity Domain");
} else {
val("Mime type " + mime_type, null);
}
String objectType = doc_ele.getAttributeValue(MetadataSupport.object_type_qname);
if (objectType == null) {
err("XDSDocumentEntry has no objectType attribute");
}
else if ( !objectType.equals(MetadataSupport.XDSDocumentEntry_objectType_stable_uuid) && !objectType.equals(MetadataSupport.XDSDocumentEntry_objectType_odd_uuid)) {
err("XDSDocumentEntry has incorrect objectType, found " + objectType + ", must be either "
+ MetadataSupport.XDSDocumentEntry_objectType_stable_uuid
+ " or "
+ MetadataSupport.XDSDocumentEntry_objectType_odd_uuid);
} else {
val("XDSDocumentEntry.objectType", null);
}
}
}
private String[] assocClassifications = {
"XFRM", "APND", "RPLC", "XFRM_RPLC"
};
// if classified object is an Association, only some types of Associations can
// accept an associationDocumenation classification
private void validateAssocClassifications(Classification cl)
throws MetadataException {
String classification_type = cl.getClassificationScheme();
if (classification_type == null || !classification_type.equals(MetadataSupport.XDSAssociationDocumentation_uuid))
return; // not associationDocumenation classification
String classified_object_id = cl.parent_id();
String classified_object_type = m.getObjectTypeById(classified_object_id);
if (classified_object_type == null)
return;
if ( !classified_object_type.equals("Association")) {
err("associationDocumentation Classification (" + MetadataSupport.XDSAssociationDocumentation_uuid + ") can only be used on Associations");
return;
}
String assoc_id = classified_object_id;
OMElement assoc_ele = m.getObjectById(assoc_id);
if (assoc_ele == null)
return;
String assoc_type = m.getSimpleAssocType(assoc_ele);
for (int i=0; i<assocClassifications.length; i++) {
String a = assocClassifications[i];
if (a.equals(assoc_type))
return;
}
err("Association Type " + assoc_type + " cannot have an associationDocumentation classification");
}
void validate(Classification cl) {
String classification_scheme = cl.getClassificationScheme();
if (classification_scheme == null) {
String classification_node = cl.getClassificationNode();
if (classification_node == null || classification_node.equals("")) {
err("classificationScheme missing", cl);
return ;
} else
return;
}
if (classification_scheme.equals(MetadataSupport.XDSSubmissionSet_author_uuid))
return;
if (classification_scheme.equals(MetadataSupport.XDSDocumentEntry_author_uuid))
return;
String code = cl.getCodeValue();
String coding_scheme = cl.getCodeScheme();
if (code == null) {
err("code (nodeRepresentation attribute) missing", cl);
return ;
}
if (coding_scheme == null) {
err("codingScheme (Slot codingScheme) missing", cl);
return;
}
for ( String codeType : connection.getAllCodeTypeNames()){
CodeSet codeSet = connection.getCodeSet(codeType);
if (codeSet.containsCode(code, coding_scheme))
{
val("Coding of " + coding_scheme, null);
return;
}
}
val("Coding of " + coding_scheme, " (" + code + ") Not Found");
err("The code, " + code + ", is not found in the configuration for the Affinity Domain", cl);
}
void val(String topic, String msg ) {
if (msg == null) msg = "Ok";
rel.add_validation(topic, msg, "CodeValidation.java");
}
void err(String msg, Classification cl) {
rel.add_error(MetadataSupport.XDSRegistryMetadataError, cl.identifying_string() + ": " + msg, "CodeValidation.java", null);
}
void err(String msg) {
rel.add_error(MetadataSupport.XDSRegistryMetadataError, msg, "CodeValidation.java", null);
}
}