Commits

Kevin A. Archie  committed 96c6ae2

handle any value on either side of a constraint

  • Participants
  • Parent commits 92dcb3a
  • Tags v2.1.0

Comments (0)

Files changed (12)

 ^.project$
 ^.settings$
 ~$
+src/main/antlr3/org/nrg/dcm/edit/output
       <plugin>
 	<groupId>org.antlr</groupId>
 	<artifactId>antlr3-maven-plugin</artifactId>
-	<version>3.1.3-1</version>
+	<version>3.4</version>
 	<executions>
           <execution>
             <goals>
   <groupId>org.nrg</groupId>
   <artifactId>DicomEdit</artifactId>
   <packaging>jar</packaging>
-  <version>2.0.1</version>
+  <version>2.1.0</version>
   <name>DicomEdit</name>
   <description>Implementation of a language for modifying DICOM metadata</description>
   <url>http://nrg.wustl.edu</url>
     <dependency>
       <groupId>org.antlr</groupId>
       <artifactId>antlr-runtime</artifactId>
-      <version>3.2</version>
+      <version>3.4</version>
     </dependency>
     <dependency>
     	<groupId>org.slf4j</groupId>

File src/main/antlr3/org/nrg/dcm/edit/EditDCMParser.g

 	package org.nrg.dcm.edit;
 }
 	
-script	:	(NEWLINE!* statement)* NEWLINE!* EOF!;
+script	:	NEWLINE!* EOF!
+	|	NEWLINE!* statement (NEWLINE!+ statement)* NEWLINE!* EOF!;
 
 statement
 	:	action
 	|	EXPORT ID STRING   -> ^(EXPORT ID STRING)
 	;
 	
+value	:	STRING termlist -> ^(FORMAT STRING termlist)
+	|	term
+	;
+	
 term	:	STRING
 	|	NUMBER
 	|	TAG
 	:	term (COMMA! term)*
 	;
 	
-value 	:	term
-	|	STRING termlist -> ^(FORMAT STRING termlist)
+condition
+options { backtrack = true; }
+	:	value EQUALS value -> ^(EQUALS value value)
+	|	value MATCHES value -> ^(MATCHES value value)
 	;
-	
-condition
-	:	TAG EQUALS value -> ^(EQUALS TAG value)
-	|	TAG MATCHES value -> ^(MATCHES TAG value)
-	;

File src/main/antlr3/org/nrg/dcm/edit/EditDCMTreeParser.g

 	;
 
 condition returns [ConstraintMatch cm]
-	:	^(EQUALS TAG v=value) {
-			$cm = new ValueEqualsConstraint(decodeTag($TAG), v);
+	:	^(EQUALS v1=value v2=value) {
+			$cm = new ValueEqualsConstraint(v1, v2);
 		}
-	|	^(MATCHES TAG v=value) {
-			$cm = new ValueRegexConstraint(decodeTag($TAG), v);
+	|	^(MATCHES s=value p=value) {
+			$cm = new ValueRegexConstraint(s, p);
 		}
 	;

File src/main/java/org/nrg/dcm/edit/AbstractValueConstraint.java

 /**
- * Copyright (c) 2006-2011 Washington University
+ * Copyright (c) 2006-2012 Washington University
  */
 package org.nrg.dcm.edit;
 
 import java.util.SortedSet;
 
 import org.dcm4che2.data.DicomObject;
-import org.dcm4che2.data.VR;
-import org.dcm4che2.util.StringUtils;
-import org.dcm4che2.util.TagUtils;
 
 import com.google.common.collect.ImmutableSortedSet;
 
  *
  */
 abstract class AbstractValueConstraint implements ConstraintMatch {
-    private final int tag;
-    private final Value toMatch;
+    private final Value left, right;
 
-    AbstractValueConstraint(final int tag, final Value toMatch) {
-        this.tag = tag;
-        this.toMatch = toMatch;
+    AbstractValueConstraint(final Value left, final Value right) {
+        this.left = left;
+        this.right = right;
     }
 
-    abstract protected boolean matches(String pattern, String value);
+    abstract protected boolean matches(String pattern, String value) throws ScriptEvaluationException;
 
     public SortedSet<Integer> getTags() {
-        return ImmutableSortedSet.of(tag);
+        final ImmutableSortedSet.Builder<Integer> tags = ImmutableSortedSet.naturalOrder();
+        tags.addAll(left.getTags());
+        tags.addAll(right.getTags());
+        return tags.build();
     }
 
     final public boolean matches(final DicomObject o) throws ScriptEvaluationException {
-        if (o.contains(tag)) {
-            final VR vr = o.vrOf(tag);
-            final String value;
-            if (VR.SQ == vr) { 
-                throw new RuntimeException("can't use SQ type attribute for constraint");
-            } else if (VR.UN == vr) {
-                value = o.getString(tag);
-            } else {
-                value = StringUtils.join(o.getStrings(tag), '\\');
-            }
-            return matches(toMatch.on(o), value);
-        } else
-            return false;
+        return matches(left.on(o), right.on(o));
     }
 
     public String toString(final String operation) {
-        return "Constraint: " + TagUtils.toString(tag) + " " + operation + " " + toMatch;
+        return "Constraint: " + left + " " + operation + " " + right;
     }
 }

File src/main/java/org/nrg/dcm/edit/SubstringValue.java

 /**
- * Copyright (c) 2009-2011 Washington University
+ * Copyright (c) 2009-2012 Washington University
  */
 package org.nrg.dcm.edit;
 
     public Set<Variable> getVariables() { return base.getVariables(); }
 
 
-    private String substring(final String s) {
+    private String substring(final String s) throws ScriptEvaluationException {
         if (null == s) {
             return null;
         }
         try {
             return s.substring(beginIndex, endIndex);
         } catch (IndexOutOfBoundsException e) {
-            return null;
+            throw new ScriptEvaluationException("index out of bounds", e);
         }
     }
 

File src/main/java/org/nrg/dcm/edit/ValueEqualsConstraint.java

 /**
- * Copyright (c) 2006-2009 Washington University
+ * Copyright (c) 2006-2012 Washington University
  */
 package org.nrg.dcm.edit;
 
+import java.util.Objects;
+
 
 /**
- * @author Kevin A. Archie <karchie@npg.wustl.edu>
+ * @author Kevin A. Archie <karchie@wustl.edu>
  *
  */
-class ValueEqualsConstraint extends AbstractValueConstraint implements ConstraintMatch {
-	ValueEqualsConstraint(final int tag, final Value toMatch) {
-		super(tag, toMatch);
-	}
-	
-	ValueEqualsConstraint(final Integer tag, final Value toMatch) {
-		this(tag.intValue(), toMatch);
-	}
+final class ValueEqualsConstraint extends AbstractValueConstraint implements ConstraintMatch {
+    ValueEqualsConstraint(final Value left, Value right) {
+        super(left, right);
+    }
 
-	protected boolean matches(final String pattern, final String value) {
-		return value.equals(pattern);
-	}
+    /*
+     * (non-Javadoc)
+     * @see org.nrg.dcm.edit.AbstractValueConstraint#matches(java.lang.String, java.lang.String)
+     */
+    protected boolean matches(final String left, final String right) {
+        return Objects.equals(left, right);
+    }
 
-	/*
-	 * (non-Javadoc)
-	 * @see java.lang.Object#toString()
-	 */
-	public String toString() {
-		return toString("equals");
-	}
+    /*
+     * (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        return toString("equals");
+    }
 }

File src/main/java/org/nrg/dcm/edit/ValueRegexConstraint.java

 /**
- * Copyright (c) 2009 Washington University
+ * Copyright (c) 2009,2012 Washington University
  */
 package org.nrg.dcm.edit;
 
 /**
- * @author Kevin A. Archie <karchie@npg.wustl.edu>
+ * @author Kevin A. Archie <karchie@wustl.edu>
  *
  */
 final class ValueRegexConstraint extends AbstractValueConstraint {
-	public ValueRegexConstraint(final int tag, final Value toMatch) {
-		super(tag, toMatch);
-	}
+    public ValueRegexConstraint(final Value value, final Value pattern) {
+        super(value, pattern);
+    }
 
-	public ValueRegexConstraint(final Integer tag, final Value toMatch) {
-		this(tag.intValue(), toMatch);
-	}
-	
-	/*
-	 * (non-Javadoc)
-	 * @see org.nrg.dcm.edit.ValueConstraintMatch#matches(java.lang.String, java.lang.String)
-	 */
-	protected boolean matches(final String pattern, final String value) {
-		return value.matches(pattern);
-	}
-	
-	/*
-	 * (non-Javadoc)
-	 * @see java.lang.Object#toString()
-	 */
-	public String toString() {
-		return toString("matches");
-	}
+
+    /*
+     * (non-Javadoc)
+     * @see org.nrg.dcm.edit.ValueConstraintMatch#matches(java.lang.String, java.lang.String)
+     */
+    protected boolean matches(final String value, final String pattern)
+    throws ScriptEvaluationException {
+        if (null == pattern) {
+            throw new ScriptEvaluationException("null pattern not allowed");
+        } else if (null == value) {
+            return false;
+        } else {
+            return value.matches(pattern);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        return toString("matches");
+    }
 }

File src/test/java/org/nrg/dcm/edit/ScriptApplicatorTest.java

     private static final Set<Integer> S_DELETE_TAGS = Collections.singleton(Integer.valueOf(0x00100020));
 
     private static final String S_COND_EQ = "(0020,0011) = \"5\" : (0008,103E) := \"Series Five\"\n"
-        + "(0020,0011) = \"6\" : (0008,103E) := \"Series Six\"\n"
+        + "lowercase[(0020,0011)] = \"6\" : (0008,103E) := \"Series Six\"\n"
         + "(0020,0011) = \"4\" : - (0008,103E)\n";
     private static final int[] S_COND_EQ_TAG_INTS = { 0x00200011, 0x0008103e };
     private static final Set<Integer> S_COND_EQ_TAGS = Sets.newTreeSet();

File src/test/java/org/nrg/dcm/edit/SubstringValueTest.java

+/**
+ * Copyright (c) 2012 Washington University
+ */
+package org.nrg.dcm.edit;
+
+import java.util.Map;
+
+import org.dcm4che2.data.BasicDicomObject;
+import org.dcm4che2.data.DicomObject;
+import org.dcm4che2.data.Tag;
+import org.dcm4che2.data.VR;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Kevin A. Archie <karchie@wustl.edu>
+ *
+ */
+public class SubstringValueTest extends TestCase {
+
+    /**
+     * Test method for {@link org.nrg.dcm.edit.SubstringValue#getTags()}.
+     */
+    public void testGetTags() {
+        final Value v1 = new SingleTagValue(Tag.PatientName);
+        final Value ss1 = new SubstringValue(v1, 0, 1);
+        assertEquals(ImmutableSortedSet.of(Tag.PatientName), ss1.getTags());
+    }
+
+    /**
+     * Test method for {@link org.nrg.dcm.edit.SubstringValue#getVariables()}.
+     */
+    public void testGetVariables() {
+        final Value v1 = new SingleTagValue(Tag.PatientName);
+        final Value ss1 = new SubstringValue(v1, 0, 1);
+        assertTrue(ss1.getVariables().isEmpty());
+
+        final Variable var = new ScriptReferencedVariable("foo");
+        final Value v2 = new VariableValue(var);
+        final Value ss2 = new SubstringValue(v2, 0, 1);
+        assertEquals(ImmutableSet.of(var), ss2.getVariables());
+    }
+
+    /**
+     * Test method for {@link org.nrg.dcm.edit.SubstringValue#on(org.dcm4che2.data.DicomObject)}.
+     */
+    public void testOnDicomObject() throws ScriptEvaluationException {
+        final Value v1 = new SingleTagValue(Tag.PatientName);
+        final DicomObject o = new BasicDicomObject();
+        o.putString(Tag.PatientName, VR.PN, "abcdef");
+        final Value ss = new SubstringValue(v1, 1, 4);
+        assertEquals("bcd", ss.on(o));
+        
+        o.putString(Tag.PatientName, VR.PN, "abc");
+        try {
+            ss.on(o);
+            fail("expected string index bounds exception");
+        } catch (ScriptEvaluationException ok) {}
+    }
+
+    /**
+     * Test method for {@link org.nrg.dcm.edit.SubstringValue#on(java.util.Map)}.
+     */
+    public void testOnMapOfIntegerString() throws ScriptEvaluationException {
+        final Value v1 = new SingleTagValue(Tag.PatientName);
+        final Map<Integer,String> m = ImmutableMap.of(Tag.PatientName, "abcdef");
+        final Value ss = new SubstringValue(v1, 2, 5);
+        assertEquals("cde", ss.on(m));
+        
+        try {
+            ss.on(ImmutableMap.of(Tag.PatientName, "abcd"));
+            fail("expected string index bounds exception");
+        } catch (ScriptEvaluationException ok) {}
+    }
+}

File src/test/java/org/nrg/dcm/edit/ValueEqualsConstraintTest.java

+/**
+ * Copyright (c) 2012 Washington University
+ */
+package org.nrg.dcm.edit;
+
+import org.dcm4che2.data.BasicDicomObject;
+import org.dcm4che2.data.DicomObject;
+import org.dcm4che2.data.Tag;
+import org.dcm4che2.data.VR;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Kevin A. Archie <karchie@wustl.edu>
+ *
+ */
+public class ValueEqualsConstraintTest extends TestCase {
+    /**
+     * Test method for {@link org.nrg.dcm.edit.AbstractValueConstraint#matches(org.dcm4che2.data.DicomObject)}.
+     */
+    public void testMatchesDicomObject() throws ScriptEvaluationException {
+        final DicomObject o1 = new BasicDicomObject();
+        o1.putString(Tag.StudyDescription, VR.LO, "foo");
+        
+        final DicomObject o2 = new BasicDicomObject();
+        o2.putString(Tag.StudyDescription, VR.LO, "bar");
+        
+        final Value studyDesc = new SingleTagValue(Tag.StudyDescription);
+        final ConstraintMatch m1 = new ValueEqualsConstraint(studyDesc, new ConstantValue("foo"));
+        assertTrue(m1.matches(o1));
+        assertFalse(m1.matches(o2));
+        
+        final ConstraintMatch m2 = new ValueEqualsConstraint(new ConstantValue("bar"), studyDesc);
+        assertFalse(m2.matches(o1));
+        assertTrue(m2.matches(o2));
+        
+        final Value patientName = new SingleTagValue(Tag.PatientName);
+        final Value nullVal = new ConstantValue(null);
+        
+        final ConstraintMatch m3 = new ValueEqualsConstraint(studyDesc, nullVal);
+        assertFalse(m3.matches(o1));
+        final ConstraintMatch m4 = new ValueEqualsConstraint(patientName, nullVal);
+        assertTrue(m4.matches(o1));
+        
+        final ConstraintMatch m5 = new ValueEqualsConstraint(patientName, new ConstantValue(""));
+        assertFalse(m5.matches(o1));
+    }
+}

File src/test/java/org/nrg/dcm/edit/ValueRegexConstraintTest.java

+/**
+ * Copyright (c) 2012 Washington University
+ */
+package org.nrg.dcm.edit;
+
+import org.dcm4che2.data.BasicDicomObject;
+import org.dcm4che2.data.DicomObject;
+import org.dcm4che2.data.Tag;
+import org.dcm4che2.data.VR;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Kevin A. Archie <karchie@wustl.edu>
+ *
+ */
+public class ValueRegexConstraintTest extends TestCase {
+    /**
+     * Test method for {@link org.nrg.dcm.edit.AbstractValueConstraint#matches(org.dcm4che2.data.DicomObject)}.
+     */
+    public void testMatchesDicomObject() throws ScriptEvaluationException {
+        final DicomObject o1 = new BasicDicomObject();
+        o1.putString(Tag.StudyDescription, VR.LO, "foo");
+        
+        final DicomObject o2 = new BasicDicomObject();
+        o2.putString(Tag.StudyDescription, VR.LO, "bar");
+        
+        final Value studyDesc = new SingleTagValue(Tag.StudyDescription);
+        final ConstraintMatch m1 = new ValueRegexConstraint(studyDesc, new ConstantValue("f\\wo"));
+        assertTrue(m1.matches(o1));
+        assertFalse(m1.matches(o2));
+        
+        final ConstraintMatch m3 = new ValueRegexConstraint(studyDesc, new ConstantValue("\\w+"));
+        assertTrue(m3.matches(o1));
+        assertTrue(m3.matches(o2));
+        
+        final Value nullVal = new ConstantValue(null);       
+        final ConstraintMatch m4 = new ValueRegexConstraint(nullVal, new ConstantValue(""));
+        assertFalse(m4.matches(o1));
+        
+        final Value patientName = new SingleTagValue(Tag.PatientName);
+        final ConstraintMatch m5 = new ValueRegexConstraint(patientName, new ConstantValue("\\w+"));
+        assertFalse(m5.matches(o1));
+    }
+}