DDMS Validator

This experimental tool uses the DDMSence library to validate Unclassified DDMS 2.0, 3.0, 3.1, 4.0.1, 4.1, and 5.0 records. Records can be submitted by pasting XML text or referencing a URL.

Starred fields (*) are required.




How This Works

Compilable source code for this tool is not bundled with DDMSence, because it has dependencies on the Spring Framework (v6.1.2). However, all of the pieces you need create a similar web application are shown below. A basic understanding of Spring MVC will be necessary to understand the code.

  1. A Spring controller, ValidatorControl, handles incoming requests at the URI, validator.uri. The type parameter is used to determine what sort of form should be displayed -- changing the "Record Location" drop-down selection redraws the form.
  2. package buri.urizone.web.control.ddmsence;
    
    import buri.ddmsence.ddms.IDDMSComponent;
    import buri.ddmsence.ddms.InvalidDDMSException;
    import buri.ddmsence.ddms.Resource;
    import buri.ddmsence.ddms.UnsupportedVersionException;
    import buri.ddmsence.ddms.ValidationMessage;
    import buri.ddmsence.ddms.security.ism.SecurityAttributes;
    import buri.ddmsence.util.DDMSReader;
    import buri.ddmsence.util.DDMSVersion;
    import buri.ddmsence.util.PropertyReader;
    import jakarta.servlet.http.HttpServletRequest;
    import nu.xom.Document;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.validation.BindingResult;
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.SessionAttributes;
    import org.springframework.web.bind.support.SessionStatus;
    import org.xml.sax.XMLReader;
    import org.xml.sax.helpers.XMLReaderFactory;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.LineNumberReader;
    import java.io.Reader;
    import java.io.StringReader;
    import java.net.URL;
    import java.net.URLConnection;
    import java.util.Date;
    import java.util.HashSet;
    import java.util.Set;
    
    /**
     * Controller class for validating DDMS Records
     *
     * @author Brian Uri!
     */
    @Controller
    @SessionAttributes({ "record" })
    public class ValidatorControl extends AbstractControl {
    
    	/**
    	 * Entry point for creating a new form
    	 */
    	@RequestMapping(value = "/validator.uri", method = RequestMethod.GET)
    	public String newForm(
    		@RequestParam(value = "type", required = false, defaultValue = ValidatorRecord.DEFAULT_TYPE) String type,
    		Model model) {
    		model.addAttribute("record", new ValidatorRecord(type));
    		return ("validator");
    	}
    
    	/**
    	 * Entry point for validating the form contents
    	 */
    	@RequestMapping(value = "/validator.uri", method = RequestMethod.POST)
    	public String validate(@ModelAttribute("record") ValidatorRecord record, BindingResult result,
    		SessionStatus status, Model model, HttpServletRequest request) {
    		String stringRepresentation = null;
    		try {
    			if (ValidatorRecord.TYPE_TEXT.equals(record.getType())) {
    				stringRepresentation = record.getStringRecord();
    			}
    			else if (ValidatorRecord.TYPE_URL.equals(record.getType())) {
    				String fullUrl = "http://" + record.getUrl();
    				try {
    					URL url = new URL(fullUrl);
    					URLConnection uc = url.openConnection();
    					stringRepresentation = readStream(new BufferedReader(new InputStreamReader(uc.getInputStream())));
    				}
    				catch (IOException e) {
    					throw new IOException("Could not connect to URL: " + fullUrl);
    				}
    			}
    			model.addAttribute("xml", stringRepresentation);
    
    			DDMSVersion version = guessVersion(stringRepresentation);
    			PropertyReader.setProperty("output.json.prettyPrint", "true");
    			PropertyReader.setProperty("output.indexLevel", "1");
    			Resource resource = new DDMSReader(version).getDDMSResource(stringRepresentation);
    			if (isUnclassified(resource)) {
    				model.addAttribute("warnings", resource.getValidationWarnings());
    				model.addAttribute("html", resource.toHTML());
    				model.addAttribute("text", resource.toText());
    				model.addAttribute("json", resource.toJSON());
    			}
    			else {
    				model.addAttribute("xml", null);
    				throw new InvalidDDMSException("This tool can only be used on Unclassified data.");
    			}
    		}
    		catch (InvalidDDMSException e) {
    			ValidationMessage message = ValidationMessage.newError(e.getMessage(), e.getLocator());
    			model.addAttribute("error", message);
    		}
    		catch (Exception e) {
    			ValidationMessage message = ValidationMessage.newError(e.getMessage(), null);
    			model.addAttribute("error", message);
    		}
    		return ("validatorResult");
    	}
    
    	/**
    	 * Helper method to attempt to guess which version of DDMS to use, based
    	 * upon the namespace URI of the root element, via a non-validating builder.
    	 *
    	 * @param potentialResource a String containing the resource
    	 * @return the version
    	 * @throws UnsupportedVersionException if the version could not be guessed.
    	 * @throws InvalidDDMSException if the file could not be parsed.
    	 */
    	private DDMSVersion guessVersion(String potentialResource) throws InvalidDDMSException {
    		try {
    			XMLReader reader = XMLReaderFactory.createXMLReader(PropertyReader.getProperty("xml.reader.class"));
    			nu.xom.Builder builder = new nu.xom.Builder(reader, false);
    			Document doc = builder.build(new StringReader(potentialResource));
    			String namespace = doc.getRootElement().getNamespaceURI();
    			return (DDMSVersion.getVersionForNamespace(namespace));
    		}
    		catch (Exception e) {
    			throw new InvalidDDMSException("Could not create a valid element from potential resource: "
    				+ e.getMessage());
    		}
    	}
    
    	/**
    	 * Converts the contents of a stream into a String
    	 *
    	 * @param streamReader the reader around the original input stream
    	 * @return a String
    	 * @throws IOException
    	 */
    	private String readStream(Reader streamReader) throws IOException {
    		LineNumberReader reader = new LineNumberReader(streamReader);
    		StringBuffer buffer = new StringBuffer();
    		String currentLine = reader.readLine();
    		while (currentLine != null) {
    			buffer.append(currentLine).append("\n");
    			currentLine = reader.readLine();
    		}
    		return (buffer.toString());
    	}
    
    	/**
    	 * Prevents classified data from being validated here.
    	 *
    	 * @param resource the DDMS Resource
    	 */
    	private boolean isUnclassified(Resource resource) throws InvalidDDMSException {
    		Set<SecurityAttributes> allAttributes = new HashSet<SecurityAttributes>();
    		allAttributes.add(resource.getSecurityAttributes());
    		for (IDDMSComponent component : resource.getTopLevelComponents()) {
    			if (component.getSecurityAttributes() != null)
    				allAttributes.add(component.getSecurityAttributes());
    		}
    		for (SecurityAttributes attr : allAttributes) {
    			if (!"U".equals(attr.getClassification()) && !"".equals(attr.getClassification()))
    				return (false);
    		}
    		return (true);
    	}
    }
  3. The ValidatorControl starts by creating a new form bean, ValidatorRecord, in the newForm() method. This is a simple data class which supports the form you see on this page.
  4. package buri.urizone.web.control.ddmsence;
    
    import buri.ddmsence.util.Util;
    
    /**
     * Form bean for online DDMS validation
     *
     * @author Brian Uri!
     */
    public class ValidatorRecord {
    
    	public static final String TYPE_TEXT = "text";
    	public static final String TYPE_URL = "url";
    	public static final String DEFAULT_TYPE = TYPE_TEXT;
    
    	private String _type;
    	private String _stringRecord;
    	private String _url;
    
    	/**
    	 * Constructor
    	 *
    	 * @param type the type of record being submitted.
    	 */
    	public ValidatorRecord(String type) {
    		if (Util.isEmpty(type))
    			type = DEFAULT_TYPE;
    		_type = type;
    	}
    
    	/**
    	 * Accessor for the string version of the record.
    	 */
    	public String getStringRecord() {
    		return _stringRecord;
    	}
    
    	/**
    	 * Accessor for the string version of the record.
    	 */
    	public void setStringRecord(String stringRecord) {
    		_stringRecord = stringRecord;
    	}
    
    	/**
    	 * Accessor for the type (url, text)
    	 */
    	public String getType() {
    		return _type;
    	}
    
    	/**
    	 * Accessor for the url
    	 */
    	public String getUrl() {
    		return _url;
    	}
    
    	/**
    	 * Accessor for the url
    	 */
    	public void setUrl(String url) {
    		_url = url;
    	}
    }
    
  5. The initial form view is rendered. This is the page you are currently viewing. The JSP file also contains the JavaScript code used for client-side validation (with jQuery).
  6. Once the form has been filled in and submitted, the validate() method of the ValidatorControl is called. This method checks to see whether the DDMS Resource is coming in as text or a URL. URLs are loaded and converted into text.
  7. The DDMSReader method, getDDMSResource() attempts to build the entire DDMS Resource. It will fail immediately with an InvalidDDMSException if the Resource is invalid.
  8. If the constructor succeeds, the Resource is proven to be valid, although there may still be warnings. The Map containing errors or warnings, model, is then used to render the Validation Results page.

Back to Top
Back to Documentation