Return-Path: Delivered-To: apmail-xml-cocoon-cvs-archive@xml.apache.org Received: (qmail 44199 invoked by uid 500); 15 Jan 2003 13:17:43 -0000 Mailing-List: contact cocoon-cvs-help@xml.apache.org; run by ezmlm Precedence: bulk Reply-To: cocoon-dev@xml.apache.org list-help: list-unsubscribe: list-post: Delivered-To: mailing list cocoon-cvs@xml.apache.org Received: (qmail 44190 invoked by uid 500); 15 Jan 2003 13:17:43 -0000 Delivered-To: apmail-xml-cocoon2-cvs@apache.org Date: 15 Jan 2003 13:17:42 -0000 Message-ID: <20030115131742.11755.qmail@icarus.apache.org> From: cziegeler@apache.org To: xml-cocoon2-cvs@apache.org Subject: cvs commit: xml-cocoon2/src/java/org/apache/cocoon/components/xmlform Form.java FormListener.java X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N cziegeler 2003/01/15 05:17:41 Modified: src/java/org/apache/cocoon/components/validation ZValidationTest.java SchemaFactory.java Validator.java ZTestBean.java Violation.java ZNestedBean.java src/java/org/apache/cocoon/components/validation/schematron Report.java Phase.java ValidationResult.java SchematronValidator.java Rule.java Pattern.java Assert.java SchematronSchema.java SchematronFactory.java ActivePattern.java src/java/org/apache/cocoon/components/xmlform Form.java FormListener.java Log: At least applying *some* of our coding guidelines Revision Changes Path 1.5 +68 -65 xml-cocoon2/src/java/org/apache/cocoon/components/validation/ZValidationTest.java Index: ZValidationTest.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/validation/ZValidationTest.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- ZValidationTest.java 15 Jan 2003 11:52:32 -0000 1.4 +++ ZValidationTest.java 15 Jan 2003 13:17:40 -0000 1.5 @@ -68,69 +68,72 @@ * Second is the validation phase to use * */ -public class ZValidationTest -{ - - /** - * Method main - */ - public static void main(String args[]) - throws Exception - { - System.out.println("\n=== Java based Schematron validation ==="); - - if (args.length < 1) { - System.err.println("Usage: java Schematron " + - "[phase] "); - return; - } - - // use custom schema - File file = new File( args[0] ); - if ( !file.exists () ) throw new Exception("Error: schema file not found !"); - InputStream istrm = new FileInputStream ( file ); - InputSource is = new InputSource ( istrm ); - SchemaFactory schf = SchemaFactory.lookup( SchemaFactory.NAMESPACE_SCHEMATRON ); - Schema sch = schf.compileSchema( is ); - Validator validator = sch.newValidator(); - - // set preprocessor parameters - if (args.length > 1) - validator.setProperty("phase", new String(args[1])); - - ZTestBean tbean = new ZTestBean(); - - // measure validation speed - long time = System.currentTimeMillis (); - int i = 0; - List violations = null; - for (; i < 100; i++) - { - // perform validation - violations = validator.validate( tbean ); - } - time = System.currentTimeMillis () - time; - System.out.println( "\nValidation performance:"); - System.out.println( " validate() executed " + i + " times for a total of " + time + " ms"); - System.out.println( "Avarage validation time: " + (time/i) + " ms " ); - - // everything ok? - if (violations == null) - { - System.out.println("\nValidation ok, no messages generated"); - } - else { - System.out.println("Validation encountered errors. Messages :"); - Iterator viter = violations.iterator(); - while (viter.hasNext ()) - { - Violation v = (Violation) viter.next(); - System.out.println("Validity violation path: " + v.getPath() + ", message: " + v.getMessage() ); - } - } - - System.out.println("\n=== Schematron validation done ==="); - } - - +public class ZValidationTest { + + /** + * Method main + */ + public static void main(String args[]) throws Exception { + System.out.println("\n=== Java based Schematron validation ==="); + + if (args.length < 1) { + System.err.println( + "Usage: java Schematron " + "[phase] "); + return; + } + + // use custom schema + File file = new File(args[0]); + if (!file.exists()) + throw new Exception("Error: schema file not found !"); + InputStream istrm = new FileInputStream(file); + InputSource is = new InputSource(istrm); + SchemaFactory schf = + SchemaFactory.lookup(SchemaFactory.NAMESPACE_SCHEMATRON); + Schema sch = schf.compileSchema(is); + Validator validator = sch.newValidator(); + + // set preprocessor parameters + if (args.length > 1) + validator.setProperty("phase", new String(args[1])); + + ZTestBean tbean = new ZTestBean(); + + // measure validation speed + long time = System.currentTimeMillis(); + int i = 0; + List violations = null; + for (; i < 100; i++) { + // perform validation + violations = validator.validate(tbean); + } + time = System.currentTimeMillis() - time; + System.out.println("\nValidation performance:"); + System.out.println( + " validate() executed " + + i + + " times for a total of " + + time + + " ms"); + System.out.println("Avarage validation time: " + (time / i) + " ms "); + + // everything ok? + if (violations == null) { + System.out.println("\nValidation ok, no messages generated"); + } else { + System.out.println("Validation encountered errors. Messages :"); + Iterator viter = violations.iterator(); + while (viter.hasNext()) { + Violation v = (Violation) viter.next(); + System.out.println( + "Validity violation path: " + + v.getPath() + + ", message: " + + v.getMessage()); + } + } + + System.out.println("\n=== Schematron validation done ==="); + } + } 1.4 +40 -36 xml-cocoon2/src/java/org/apache/cocoon/components/validation/SchemaFactory.java Index: SchemaFactory.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/validation/SchemaFactory.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- SchemaFactory.java 15 Jan 2003 11:52:32 -0000 1.3 +++ SchemaFactory.java 15 Jan 2003 13:17:40 -0000 1.4 @@ -61,43 +61,47 @@ */ public abstract class SchemaFactory { - public static String NAMESPACE_SCHEMATRON = "http://www.ascc.net/xml/schematron"; - - /** Creates a new instance of ValidatorFactory */ - public SchemaFactory () - { - } - - /** - * This method creates an instance of a ValidatorFactory - * using the JDK 1.3 META-INF/services mechanism. - * The idea is borrowed from JARV - * http://iso-relax.sourceforge.net/apiDoc/org/iso_relax/verifier/VerifierFactory.html - * - * @param ns the namespace of the schema language - * @return ValidatorFactory - * @throws InstantiationException when a factory could not be created - */ - public static SchemaFactory lookup(java.lang.String ns) - throws InstantiationException - { - // currently hardcoded implementation for Schematron - // until another schema validator is implemented - /* @todo create SchematronValidatorFactory */ - if ( ns.equals ( NAMESPACE_SCHEMATRON ) ) - return new org.apache.cocoon.components.validation.schematron.SchematronFactory(); - return null; - } + public static String NAMESPACE_SCHEMATRON = + "http://www.ascc.net/xml/schematron"; + /** Creates a new instance of ValidatorFactory */ + public SchemaFactory() { + } - /** - * Loads and compiles a Schema instance - * - * @param InputSource the SAX input source containing the Schema document - * @return Schema the compiled schema instance - * @throws InstantiationException when the Schema could not be loaded or compiled - */ - public abstract Schema compileSchema(InputSource is) - throws InstantiationException; + /** + * This method creates an instance of a ValidatorFactory + * using the JDK 1.3 META-INF/services mechanism. + * The idea is borrowed from JARV + * http://iso-relax.sourceforge.net/apiDoc/org/iso_relax/verifier/VerifierFactory.html + * + * @param ns the namespace of the schema language + * @return ValidatorFactory + * @throws InstantiationException when a factory could not be created + */ + public static SchemaFactory lookup(String ns) + throws InstantiationException { + // currently hardcoded implementation for Schematron + // until another schema validator is implemented + /* @todo create SchematronValidatorFactory */ + if (ns.equals(NAMESPACE_SCHEMATRON)) + return new org + .apache + .cocoon + .components + .validation + .schematron + .SchematronFactory(); + return null; + } + + /** + * Loads and compiles a Schema instance + * + * @param InputSource the SAX input source containing the Schema document + * @return Schema the compiled schema instance + * @throws InstantiationException when the Schema could not be loaded or compiled + */ + public abstract Schema compileSchema(InputSource is) + throws InstantiationException; } 1.4 +7 -8 xml-cocoon2/src/java/org/apache/cocoon/components/validation/Validator.java Index: Validator.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/validation/Validator.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- Validator.java 15 Jan 2003 11:52:32 -0000 1.3 +++ Validator.java 15 Jan 2003 13:17:40 -0000 1.4 @@ -58,8 +58,7 @@ * * @author ivelin@apache.org */ -public interface Validator -{ +public interface Validator { /** * Validates an instance against a schema and returns a set of errors. @@ -68,7 +67,7 @@ * * @param instance The instance can be either a DOM node or a JavaBean. * @return SortedSet of ValidityViolation(s). The set is sorted by -ValidityViolation.getPath() + * ValidityViolation.getPath() * * @throws RuntimeException if the validation process fails * Should not happen in a normal environment. @@ -80,23 +79,23 @@ * The concept is borrowed from the Schematron schema * Not all schemas support partial validation */ - public String PROPERTY_PHASE = "http://xml.apache.org/cocoon/validator/phase"; + String PROPERTY_PHASE = "http://xml.apache.org/cocoon/validator/phase"; /** * @param property name * @param value property value * @throws IllegalArgumentException when the property is not supported */ - public void setProperty(java.lang.String property, java.lang.Object value) - throws java.lang.IllegalArgumentException; + void setProperty(String property, Object value) + throws IllegalArgumentException; /** * @param property name * @return the property value * @throws IllegalArgumentException when the property is not supported */ - public java.lang.Object getProperty(java.lang.String property) - throws java.lang.IllegalArgumentException; + Object getProperty(String property) + throws IllegalArgumentException; 1.4 +56 -59 xml-cocoon2/src/java/org/apache/cocoon/components/validation/ZTestBean.java Index: ZTestBean.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/validation/ZTestBean.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- ZTestBean.java 15 Jan 2003 11:52:32 -0000 1.3 +++ ZTestBean.java 15 Jan 2003 13:17:40 -0000 1.4 @@ -52,63 +52,60 @@ import java.util.ArrayList; - /** - * just a test bean - */ +/** + * just a test bean + */ public class ZTestBean { - private String name = "dog"; - private String scope = "galaxy"; - private int count = 0; - private ArrayList preferences = new ArrayList(); - private ZNestedBean personal = new ZNestedBean(); - - public ZTestBean (){ - preferences.add("likeVodka"); - preferences.add("likeSkiing"); - } - - public ZTestBean (String newName, String newScope){ - this(); - name= newName; - scope=newScope; - } - - public String getName() { - return name; - } - public void setName(String newName) { - name = newName; - } - - public void setScope(String newScope) { - scope = newScope; - } - - public String getScope() { - return scope; - } - - public ArrayList getPreferences() - { - return preferences; - } - - public ZNestedBean getPersonalInfo() - { - return personal; - } - - public void setPersonalInfo( ZNestedBean newPersonal ) - { - personal = newPersonal; - } - - public int getCount() { - return count; - } - - public void incrementCount() { - count++; - } - - } + private String name = "dog"; + private String scope = "galaxy"; + private int count = 0; + private ArrayList preferences = new ArrayList(); + private ZNestedBean personal = new ZNestedBean(); + + public ZTestBean() { + preferences.add("likeVodka"); + preferences.add("likeSkiing"); + } + + public ZTestBean(String newName, String newScope) { + this(); + name = newName; + scope = newScope; + } + + public String getName() { + return name; + } + public void setName(String newName) { + name = newName; + } + + public void setScope(String newScope) { + scope = newScope; + } + + public String getScope() { + return scope; + } + + public ArrayList getPreferences() { + return preferences; + } + + public ZNestedBean getPersonalInfo() { + return personal; + } + + public void setPersonalInfo(ZNestedBean newPersonal) { + personal = newPersonal; + } + + public int getCount() { + return count; + } + + public void incrementCount() { + count++; + } + +} 1.4 +76 -81 xml-cocoon2/src/java/org/apache/cocoon/components/validation/Violation.java Index: Violation.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/validation/Violation.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- Violation.java 15 Jan 2003 11:52:32 -0000 1.3 +++ Violation.java 15 Jan 2003 13:17:40 -0000 1.4 @@ -57,85 +57,80 @@ * * @author ivelin@apache.org */ -public class Violation implements Comparable -{ - - /** - * @return the XPath location of the Violation - */ - public String getPath() - { - return xpath_; - } - - /** - * set the XPath location of the Violation - */ - public void setPath( String xpath ) - { - xpath_ = xpath; - } - - - /** - * @return the error message - */ - public String getMessage () - { - return message_; - } - - /** - * set the error message - */ - public void setMessage ( String message ) - { - message_ = message; - } - - public boolean equals(Object obj) - { - if (obj == null) return false; - if (obj == this) return true; - if ( !(obj instanceof Violation) ) - throw new java.lang.IllegalArgumentException( "Can only compare to a Violation object" ); - Violation v = (Violation) obj; - if - ( - getPath().equals ( v.getPath() ) - && - getMessage().equals ( v.getMessage() ) - ) - return true; - else return false; - } - - public int hashCode() - { - return (getPath().hashCode () ^ getMessage().hashCode()); - } - - public int compareTo(Object obj) - { - if (obj == null) return 1; - if (obj == this) return 0; - if ( !(obj instanceof Violation) ) - throw new java.lang.IllegalArgumentException( "Can only compare to a Violation object" ); - Violation v = (Violation) obj; - int primaryResult = getPath().compareTo ( v.getPath () ); - if (primaryResult != 0) return primaryResult; - else - { - if (getMessage () == null) - { - if (v.getMessage() == null) return 0; - else return -1; - } - else return (getMessage().compareTo( v.getMessage () ) ); - } - } - - private String xpath_; - private String message_; - +public class Violation implements Comparable { + + /** + * @return the XPath location of the Violation + */ + public String getPath() { + return xpath_; + } + + /** + * set the XPath location of the Violation + */ + public void setPath(String xpath) { + xpath_ = xpath; + } + + /** + * @return the error message + */ + public String getMessage() { + return message_; + } + + /** + * set the error message + */ + public void setMessage(String message) { + message_ = message; + } + + public boolean equals(Object obj) { + if (obj == null) + return false; + if (obj == this) + return true; + if (!(obj instanceof Violation)) + throw new java.lang.IllegalArgumentException( + "Can only compare to a Violation object"); + Violation v = (Violation) obj; + if (getPath().equals(v.getPath()) + && getMessage().equals(v.getMessage())) + return true; + else + return false; + } + + public int hashCode() { + return (getPath().hashCode() ^ getMessage().hashCode()); + } + + public int compareTo(Object obj) { + if (obj == null) + return 1; + if (obj == this) + return 0; + if (!(obj instanceof Violation)) + throw new java.lang.IllegalArgumentException( + "Can only compare to a Violation object"); + Violation v = (Violation) obj; + int primaryResult = getPath().compareTo(v.getPath()); + if (primaryResult != 0) + return primaryResult; + else { + if (getMessage() == null) { + if (v.getMessage() == null) + return 0; + else + return -1; + } else + return (getMessage().compareTo(v.getMessage())); + } + } + + private String xpath_; + private String message_; + } 1.3 +14 -17 xml-cocoon2/src/java/org/apache/cocoon/components/validation/ZNestedBean.java Index: ZNestedBean.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/validation/ZNestedBean.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- ZNestedBean.java 15 Jan 2003 11:52:32 -0000 1.2 +++ ZNestedBean.java 15 Jan 2003 13:17:40 -0000 1.3 @@ -50,20 +50,17 @@ */ package org.apache.cocoon.components.validation; - /** - * just a test bean - */ - public class ZNestedBean - { - private String kind = "mammal"; - - public void setKind(String newKind) - { - kind = newKind; - } - - public String getKind() - { - return kind; - } - } +/** + * just a test bean + */ +public class ZNestedBean { + private String kind = "mammal"; + + public void setKind(String newKind) { + kind = newKind; + } + + public String getKind() { + return kind; + } +} 1.3 +1 -2 xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/Report.java Index: Report.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/Report.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- Report.java 15 Jan 2003 11:52:32 -0000 1.2 +++ Report.java 15 Jan 2003 13:17:40 -0000 1.3 @@ -62,6 +62,5 @@ * * @author Ivelin Ivanov, ivelin@acm.org, ivelin@iname.com */ -public class Report extends Assert -{ +public class Report extends Assert { } 1.4 +41 -49 xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/Phase.java Index: Phase.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/Phase.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- Phase.java 15 Jan 2003 11:52:32 -0000 1.3 +++ Phase.java 15 Jan 2003 13:17:40 -0000 1.4 @@ -54,7 +54,6 @@ import java.util.Collection; import java.util.List; - /** * Represents a Schematron phase element * @@ -68,52 +67,45 @@ * * @author Ivelin Ivanov, ivelin@acm.org, ivelin@iname.com */ -public class Phase -{ - - private String id_; - private ArrayList active_ = new ArrayList (); - - - /** - * Returns the id of the phase - */ - public String getId() - { - return id_; - } - - /** - * Sets the id of the phase - */ - public void setId( String newId ) - { - id_ = newId; - } - - /** - * Returns the list of active patterns - */ - public List getActive() - { - return active_; - } - - /** - * Sets the list of active patterns - */ - public void setActive(Collection newActivePatterns) - { - active_ = new ArrayList(); - active_.addAll ( newActivePatterns ); - } - - /** - * Add a pattern to the list of active patterns - */ - public void addActive(ActivePattern p) - { - active_.add ( p ); - } - +public class Phase { + + private String id_; + private ArrayList active_ = new ArrayList(); + + /** + * Returns the id of the phase + */ + public String getId() { + return id_; + } + + /** + * Sets the id of the phase + */ + public void setId(String newId) { + id_ = newId; + } + + /** + * Returns the list of active patterns + */ + public List getActive() { + return active_; + } + + /** + * Sets the list of active patterns + */ + public void setActive(Collection newActivePatterns) { + active_ = new ArrayList(); + active_.addAll(newActivePatterns); + } + + /** + * Add a pattern to the list of active patterns + */ + public void addActive(ActivePattern p) { + active_.add(p); + } + } 1.6 +83 -93 xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/ValidationResult.java Index: ValidationResult.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/ValidationResult.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- ValidationResult.java 15 Jan 2003 11:52:32 -0000 1.5 +++ ValidationResult.java 15 Jan 2003 13:17:40 -0000 1.6 @@ -67,97 +67,87 @@ * * @author Ivelin Ivanov, ivelin@acm.org, ivelin@iname.com */ -public class ValidationResult -{ - - private ArrayList patterns_ = new ArrayList(); - - - /** - * Returns a list of the patterns which - * contain rules that failed during validation - */ - public List getPattern() - { - return patterns_; - } - - /** - * Sets the list of the patterns which - * contain rules that failed during validation - */ - public void setPattern(Collection newPatterns) - { - patterns_ = new ArrayList(); - patterns_.addAll ( newPatterns ); - } - - /** - * Add a pattern to the list - */ - public void addPattern(Pattern p) - { - patterns_.add ( p ); - } - - public boolean isEmpty () - { - return patterns_.isEmpty (); - } - - /** - * adds all errors to a sorted list - * Key is XPath of each error location - * - * @todo implement this method !!! - * @return SortedSet - */ - public List toList() - { - - if ( isEmpty() ) return null; - - List violations = new LinkedList(); - - Iterator piter = getPattern().iterator(); - while (piter.hasNext ()) - { - Pattern pattern = (Pattern)piter.next (); - // System.out.println("Pattern name: " + pattern.getName() + ", id: " + pattern.getId() ); - Iterator ruleIter = pattern.getRule().iterator(); - while (ruleIter.hasNext ()) - { - Rule rule = (Rule)ruleIter.next (); - // System.out.println(" Rule name: " + rule.getContext() ); - - Iterator assertIter = rule.getAssert().iterator(); - while (assertIter.hasNext ()) - { - Assert assertion = (Assert)assertIter.next (); - - // add the next assert to the violations set - Violation v = new Violation(); - v.setPath( rule.getContext() ); - v.setMessage( assertion.getMessage() ); - violations.add( v ); - // System.out.println(" Assert test: " + assertion.getTest() + ", message: " + assertion.getMessage() ); - } - - Iterator reportIter = rule.getReport().iterator(); - while (reportIter.hasNext ()) - { - Report report = (Report)reportIter.next (); - - // add the next report to the violations set - Violation v = new Violation(); - v.setPath( rule.getContext() ); - v.setMessage( report.getMessage() ); - violations.add( v ); - // System.out.println(" Report test: " + report.getTest() + ", message: " + report.getMessage() ); - } - } - } - return violations; - } - +public class ValidationResult { + + private ArrayList patterns_ = new ArrayList(); + + /** + * Returns a list of the patterns which + * contain rules that failed during validation + */ + public List getPattern() { + return patterns_; + } + + /** + * Sets the list of the patterns which + * contain rules that failed during validation + */ + public void setPattern(Collection newPatterns) { + patterns_ = new ArrayList(); + patterns_.addAll(newPatterns); + } + + /** + * Add a pattern to the list + */ + public void addPattern(Pattern p) { + patterns_.add(p); + } + + public boolean isEmpty() { + return patterns_.isEmpty(); + } + + /** + * adds all errors to a sorted list + * Key is XPath of each error location + * + * @todo implement this method !!! + * @return SortedSet + */ + public List toList() { + + if (isEmpty()) + return null; + + List violations = new LinkedList(); + + Iterator piter = getPattern().iterator(); + while (piter.hasNext()) { + Pattern pattern = (Pattern) piter.next(); + // System.out.println("Pattern name: " + pattern.getName() + ", id: " + pattern.getId() ); + Iterator ruleIter = pattern.getRule().iterator(); + while (ruleIter.hasNext()) { + Rule rule = (Rule) ruleIter.next(); + // System.out.println(" Rule name: " + rule.getContext() ); + + Iterator assertIter = rule.getAssert().iterator(); + while (assertIter.hasNext()) { + Assert assertion = (Assert) assertIter.next(); + + // add the next assert to the violations set + Violation v = new Violation(); + v.setPath(rule.getContext()); + v.setMessage(assertion.getMessage()); + violations.add(v); + // System.out.println(" Assert test: " + assertion.getTest() + ", message: " + assertion.getMessage() ); + } + + Iterator reportIter = rule.getReport().iterator(); + while (reportIter.hasNext()) { + Report report = (Report) reportIter.next(); + + // add the next report to the violations set + Violation v = new Violation(); + v.setPath(rule.getContext()); + v.setMessage(report.getMessage()); + violations.add(v); + // System.out.println(" Report test: " + report.getTest() + ", message: " + report.getMessage() ); + } + } + } + return violations; + } + } 1.7 +289 -319 xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/SchematronValidator.java Index: SchematronValidator.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/SchematronValidator.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- SchematronValidator.java 15 Jan 2003 11:52:32 -0000 1.6 +++ SchematronValidator.java 15 Jan 2003 13:17:40 -0000 1.7 @@ -73,324 +73,294 @@ * * @author Ivelin Ivanov, ivelin@acm.org, ivelin@iname.com */ -public class SchematronValidator implements Validator -{ +public class SchematronValidator implements Validator { + + /** The schema instance for this Validator + * It is initialized once when a new Validator instance + * is created and used multiple times for validating + * different JavaBeans/DOM objects against the schema + */ + private SchematronSchema schema_; + + /** + * lookup map, with phase id keys. + * Used for efficiency when validating by phase + */ + private Map phaseMap_ = new HashMap(); + + /** + * the schema name space prefix used in the schema document + */ + private String schemaPrefix_; + + /** + * the default schema name space prefix + */ + private String defaultSchemaPrefix_ = "sch"; + + /* + * Schematron Phase property + */ + private String phaseProperty_ = null; + + /* + * private logger + */ + private Logger logger = setupLogger(); + + // + // Constructors + // + + /** + * Constructs a new Validator object for a given Schematron schema. + * + * @param schema + * The Schematron schema + */ + public SchematronValidator(SchematronSchema schema) { + schema_ = schema; + preparePhaseMap(); + } + + // + // helper methods for the constructors + // + + /** + * initialize logger + */ + protected Logger setupLogger() { + Logger logger = Hierarchy.getDefaultHierarchy().getLoggerFor("XmlForm"); + logger.setPriority(Priority.ERROR); + return logger; + } + + protected void preparePhaseMap() { + Map patternMap = new HashMap(); + + Iterator ptiter = schema_.getPattern().iterator(); + while (ptiter.hasNext()) { + Pattern pattern = (Pattern) ptiter.next(); + patternMap.put(pattern.getId(), pattern); + } + + Iterator phiter = schema_.getPhase().iterator(); + while (phiter.hasNext()) { + Phase phase = (Phase) phiter.next(); + List activePatterns = new ArrayList(); + phaseMap_.put(phase.getId(), activePatterns); + + Iterator activeIter = phase.getActive().iterator(); + while (activeIter.hasNext()) { + ActivePattern active = (ActivePattern) activeIter.next(); + activePatterns.add(patternMap.get(active.getPattern())); + } + } + + } + + // + // public methods + // + + /** + * Performs validation of the passed JavaBean or DOM object. + * + * This method tries to find the "phase" attribute + * and runs the active patterns for the phase. + * If phase not found, the method will try to match all patterns + * + * + * @param jbean The JavaBean or DOM object to be validated. + * @param props Properties which control different aspects of the + * validation process. This method only looks for the phase property. + * Another implementation may use other. + * + * @return A Result object which represents the result + * of the validation. + */ + public List validate(Object jbean) { + List patterns = null; + if (phaseProperty_ != null) { + patterns = getPatternsForPhase(phaseProperty_); + logger.debug(" Validating for phase: " + phaseProperty_); + } else { + patterns = schema_.getPattern(); + logger.debug(" Validating all patterns. No phase provided "); + } + + ValidationResult vres = new ValidationResult(); + + if (patterns != null) { + // create the JXPathContext + // which will be used to validate each rule + JXPathContext jxpContext = JXPathContext.newContext(jbean); + + Iterator iter = patterns.iterator(); + while (iter.hasNext()) { + Pattern resultPattern = + evalPattern(jxpContext, (Pattern) iter.next()); + // if the resultPattern is null, + // then it passed successfully + if (resultPattern != null) + vres.addPattern(resultPattern); + } + } + + return vres.toList(); + } + + /** + * return the list of patterns listed + * as elements of + * + * @param phase name of the phase + * @return List of patterns + */ + protected List getPatternsForPhase(String phase) { + return (List) phaseMap_.get(phase); + } + + /** + * Returns pattern with rules which failed during validation. + * The context attribute of each rule in the result pattern + * contains the exact location of the failed element + * unlike the context attribute of the original pattern which + * is an XSLT production pattern + * + * @param jxpContext The JXPathContext being validated + * @param pattern The production schema pattern to be evaluated + * @return pattern with rules wich failed during validation. + */ + protected Pattern evalPattern(JXPathContext jxpContext, Pattern pattern) { + // copy attributes + Pattern resultPattern = new Pattern(); + resultPattern.setName(pattern.getName()); + resultPattern.setId(pattern.getId()); + + // evaluate rules + Iterator iter = pattern.getRule().iterator(); + while (iter.hasNext()) { + List failedRules = evalRule(jxpContext, (Rule) iter.next()); + // if there were failed rules + // add them to the list of other failed rules + if (failedRules.size() > 0) { + failedRules.addAll(resultPattern.getRule()); + resultPattern.setRule(failedRules); + } + } + + // if there are no failed rules return null + if (resultPattern.getRule().size() == 0) + return null; + else + return resultPattern; + } + + /** + * Returns rules with asserts or reports which failed during validation. + * The context attribute of each rule in the result pattern + * contains the exact location of the failed element + * unlike the context attribute of the original pattern which + * is an XSLT production pattern + * + * @param jxpContext The JXPath context being validated + * @param rule The original pattern rule to be evaluated + * @return pattern with rules wich failed during validation. + */ + protected List evalRule(JXPathContext jxpContext, Rule rule) { + List failedRules = new ArrayList(); + + Iterator pointerIter = jxpContext.iteratePointers(rule.getContext()); + while (pointerIter.hasNext()) { + + Pointer ptr = (Pointer) pointerIter.next(); + + // prepare result Rule + Rule nextFailedRule = new Rule(); + nextFailedRule.setContext(ptr.asPath()); + + // switch to the context of the rule + JXPathContext localJxpContext = + JXPathContext.newContext(jxpContext, ptr.getValue()); + + // evaluate asserts + Iterator assertIter = rule.getAssert().iterator(); + while (assertIter.hasNext()) { + Assert assertion = (Assert) assertIter.next(); + // if an assert test fails, then it should be added + // to the result + boolean passed = evalTest(localJxpContext, assertion.getTest()); + if (!passed) { + nextFailedRule.addAssert(assertion); + } + } + + // evaluate reports + Iterator reportIter = rule.getReport().iterator(); + while (reportIter.hasNext()) { + Report report = (Report) reportIter.next(); + // if a report test passes, then it should be added + // to the result + boolean passed = evalTest(localJxpContext, report.getTest()); + if (passed) { + nextFailedRule.addReport(report); + } + } + + // if the nextFailedRule is non empty, + // then add it to the list of failed rules + if (nextFailedRule.getAssert().size() > 0 + || nextFailedRule.getReport().size() > 0) { + failedRules.add(nextFailedRule); + } + } + + return failedRules; + } + + /** + * Test an XPath expression in a context + * + * @param jxpContext The JXPath context being validated + * @param String The XPath expression + * @return boolean result of evaluation + */ + protected boolean evalTest(JXPathContext jxpContext, String test) { + Boolean passed = (Boolean) jxpContext.getValue(test, Boolean.class); + return passed.booleanValue(); + } + + /** + * @param property name + * @return the property value + * @throws IllegalArgumentException when the property is not supported + */ + public Object getProperty(String property) + throws IllegalArgumentException { + if (property.equals(Validator.PROPERTY_PHASE)) + return phaseProperty_; + else + throw new IllegalArgumentException( + " Property " + property + " is not supported"); + } + + /** + * @param property name + * @param value property value + * @throws IllegalArgumentException when the property is not supported + */ + public void setProperty(String property, Object value) + throws IllegalArgumentException { + if (property.equals(Validator.PROPERTY_PHASE) + && (value == null || (value instanceof String))) { + phaseProperty_ = (String) value; + } else + throw new IllegalArgumentException( + " Property " + + property + + " is not supported or value is invalid"); + } - - /** The schema instance for this Validator - * It is initialized once when a new Validator instance - * is created and used multiple times for validating - * different JavaBeans/DOM objects against the schema - */ - private SchematronSchema schema_; - - /** - * lookup map, with phase id keys. - * Used for efficiency when validating by phase - */ - private Map phaseMap_ = new HashMap(); - - - /** - * the schema name space prefix used in the schema document - */ - private String schemaPrefix_; - - /** - * the default schema name space prefix - */ - private String defaultSchemaPrefix_ = "sch"; - - /* - * Schematron Phase property - */ - private String phaseProperty_ = null; - - - /* - * private logger - */ - private Logger logger = setupLogger(); - - - - // - // Constructors - // - - - /** - * Constructs a new Validator object for a given Schematron schema. - * - * @param schema - * The Schematron schema - */ - public SchematronValidator (SchematronSchema schema) - { - schema_ = schema; - preparePhaseMap(); - } - - - - - // - // helper methods for the constructors - // - - /** - * initialize logger - */ - protected Logger setupLogger() - { - Logger logger = Hierarchy.getDefaultHierarchy().getLoggerFor("XmlForm"); - logger.setPriority( Priority.ERROR ); - return logger; - } - - - protected void preparePhaseMap() - { - Map patternMap = new HashMap(); - - Iterator ptiter = schema_.getPattern().iterator(); - while (ptiter.hasNext()) - { - Pattern pattern = (Pattern) ptiter.next(); - patternMap.put( pattern.getId(), pattern ); - } - - Iterator phiter = schema_.getPhase().iterator(); - while (phiter.hasNext()) - { - Phase phase = (Phase) phiter.next(); - List activePatterns = new ArrayList(); - phaseMap_.put( phase.getId(), activePatterns ); - - Iterator activeIter = phase.getActive().iterator(); - while (activeIter.hasNext()) - { - ActivePattern active = (ActivePattern) activeIter.next(); - activePatterns.add( patternMap.get( active.getPattern() ) ); - } - } - - - } - - // - // public methods - // - - - - - /** - * Performs validation of the passed JavaBean or DOM object. - * - * This method tries to find the "phase" attribute - * and runs the active patterns for the phase. - * If phase not found, the method will try to match all patterns - * - * - * @param jbean The JavaBean or DOM object to be validated. - * @param props Properties which control different aspects of the - * validation process. This method only looks for the phase property. - * Another implementation may use other. - * - * @return A Result object which represents the result - * of the validation. - */ - public List validate( Object jbean ) - { - List patterns = null; - if (phaseProperty_ != null) - { - patterns = getPatternsForPhase( phaseProperty_ ); - logger.debug(" Validating for phase: " + phaseProperty_); - } - else - { - patterns = schema_.getPattern(); - logger.debug(" Validating all patterns. No phase provided "); - } - - ValidationResult vres = new ValidationResult(); - - if (patterns != null) - { - // create the JXPathContext - // which will be used to validate each rule - JXPathContext jxpContext = JXPathContext.newContext( jbean ); - - Iterator iter = patterns.iterator (); - while (iter.hasNext ()) - { - Pattern resultPattern = evalPattern( jxpContext, (Pattern) iter.next()); - // if the resultPattern is null, - // then it passed successfully - if ( resultPattern != null) vres.addPattern( resultPattern ); - } - } - - return vres.toList(); - } - - /** - * return the list of patterns listed - * as elements of - * - * @param phase name of the phase - * @return List of patterns - */ - protected List getPatternsForPhase( String phase ) - { - return (List) phaseMap_.get( phase ); - } - - /** - * Returns pattern with rules which failed during validation. - * The context attribute of each rule in the result pattern - * contains the exact location of the failed element - * unlike the context attribute of the original pattern which - * is an XSLT production pattern - * - * @param jxpContext The JXPathContext being validated - * @param pattern The production schema pattern to be evaluated - * @return pattern with rules wich failed during validation. - */ - protected Pattern evalPattern( JXPathContext jxpContext, Pattern pattern) - { - // copy attributes - Pattern resultPattern = new Pattern(); - resultPattern.setName( pattern.getName() ); - resultPattern.setId( pattern.getId() ); - - // evaluate rules - Iterator iter = pattern.getRule().iterator(); - while (iter.hasNext()) - { - List failedRules = evalRule(jxpContext, (Rule) iter.next () ); - // if there were failed rules - // add them to the list of other failed rules - if (failedRules.size () > 0) - { - failedRules.addAll ( resultPattern.getRule() ); - resultPattern.setRule ( failedRules ); - } - } - - // if there are no failed rules return null - if (resultPattern.getRule().size() == 0) return null; - else return resultPattern; - } - - - /** - * Returns rules with asserts or reports which failed during validation. - * The context attribute of each rule in the result pattern - * contains the exact location of the failed element - * unlike the context attribute of the original pattern which - * is an XSLT production pattern - * - * @param jxpContext The JXPath context being validated - * @param rule The original pattern rule to be evaluated - * @return pattern with rules wich failed during validation. - */ - protected List evalRule( JXPathContext jxpContext, Rule rule ) - { - List failedRules = new ArrayList(); - - Iterator pointerIter = jxpContext.iteratePointers( rule.getContext() ); - while ( pointerIter.hasNext() ) - { - - Pointer ptr = (Pointer) pointerIter.next (); - - // prepare result Rule - Rule nextFailedRule = new Rule(); - nextFailedRule.setContext( ptr.asPath() ); - - // switch to the context of the rule - JXPathContext localJxpContext = JXPathContext.newContext( jxpContext, ptr.getValue() ); - - // evaluate asserts - Iterator assertIter = rule.getAssert().iterator(); - while (assertIter.hasNext()) - { - Assert assertion = (Assert) assertIter.next(); - // if an assert test fails, then it should be added - // to the result - boolean passed = evalTest( localJxpContext, assertion.getTest() ); - if (!passed) - { - nextFailedRule.addAssert ( assertion ); - } - } - - // evaluate reports - Iterator reportIter = rule.getReport().iterator(); - while (reportIter.hasNext()) - { - Report report = (Report) reportIter.next(); - // if a report test passes, then it should be added - // to the result - boolean passed = evalTest( localJxpContext, report.getTest() ); - if (passed) - { - nextFailedRule.addReport ( report ); - } - } - - // if the nextFailedRule is non empty, - // then add it to the list of failed rules - if (nextFailedRule.getAssert().size() > 0 || nextFailedRule.getReport().size() > 0) - { - failedRules.add( nextFailedRule ); - } - } - - return failedRules; - } - - - /** - * Test an XPath expression in a context - * - * @param jxpContext The JXPath context being validated - * @param String The XPath expression - * @return boolean result of evaluation - */ - protected boolean evalTest( JXPathContext jxpContext, String test ) - { - Boolean passed = (Boolean) jxpContext.getValue( test, Boolean.class); - return passed.booleanValue (); - } - - /** - * @param property name - * @return the property value - * @throws IllegalArgumentException when the property is not supported - */ - public java.lang.Object getProperty (java.lang.String property) throws java.lang.IllegalArgumentException - { - if (property.equals ( Validator.PROPERTY_PHASE ) ) return phaseProperty_; - else throw new IllegalArgumentException(" Property " + property + " is not supported"); - } - - /** - * @param property name - * @param value property value - * @throws IllegalArgumentException when the property is not supported - */ - public void setProperty (java.lang.String property, java.lang.Object value) throws java.lang.IllegalArgumentException - { - if ( property.equals ( Validator.PROPERTY_PHASE ) && ( value == null || (value instanceof String)) ) - { - phaseProperty_ = (String) value; - } - else - throw new IllegalArgumentException(" Property " + property + " is not supported or value is invalid"); - } - } 1.4 +63 -76 xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/Rule.java Index: Rule.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/Rule.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- Rule.java 15 Jan 2003 11:52:32 -0000 1.3 +++ Rule.java 15 Jan 2003 13:17:40 -0000 1.4 @@ -67,81 +67,68 @@ * * @author Ivelin Ivanov, ivelin@acm.org, ivelin@iname.com */ -public class Rule -{ +public class Rule { + + private String context_; + private ArrayList asserts_ = new ArrayList(); + private ArrayList reports_ = new ArrayList(); + + /** + * Returns the context of the pattern + */ + public String getContext() { + return context_; + } + + /** + * Sets the context of the pattern + */ + public void setContext(String newContext) { + context_ = newContext; + } + + /** + * Returns the list of the assertion rules + */ + public List getAssert() { + return asserts_; + } + + /** + * Sets the the list of the assertion rules + */ + public void setAssert(Collection newAsserts) { + asserts_ = new ArrayList(); + asserts_.addAll(newAsserts); + } + + /** + * Add an assert rule + */ + public void addAssert(Assert a) { + asserts_.add(a); + } + + /** + * Returns the list of the report rules + */ + public List getReport() { + return reports_; + } + + /** + * Sets the list of the report rules + */ + public void setReport(Collection newReports) { + reports_ = new ArrayList(); + reports_.addAll(newReports); + } + + /** + * Add a report rule + */ + public void addReport(Report r) { + reports_.add(r); + } - private String context_; - private ArrayList asserts_ = new ArrayList (); - private ArrayList reports_ = new ArrayList (); - - - - /** - * Returns the context of the pattern - */ - public String getContext() - { - return context_; - } - - /** - * Sets the context of the pattern - */ - public void setContext( String newContext ) - { - context_ = newContext; - } - - /** - * Returns the list of the assertion rules - */ - public List getAssert() - { - return asserts_; - } - - /** - * Sets the the list of the assertion rules - */ - public void setAssert(Collection newAsserts) - { - asserts_ = new ArrayList(); - asserts_.addAll ( newAsserts ); - } - - /** - * Add an assert rule - */ - public void addAssert(Assert a) - { - asserts_.add ( a ); - } - - - /** - * Returns the list of the report rules - */ - public List getReport() - { - return reports_; - } - - /** - * Sets the list of the report rules - */ - public void setReport(Collection newReports) - { - reports_ = new ArrayList(); - reports_.addAll ( newReports ); - } - - /** - * Add a report rule - */ - public void addReport(Report r) - { - reports_.add ( r ); - } - - } 1.4 +56 -67 xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/Pattern.java Index: Pattern.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/Pattern.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- Pattern.java 15 Jan 2003 11:52:32 -0000 1.3 +++ Pattern.java 15 Jan 2003 13:17:40 -0000 1.4 @@ -54,76 +54,65 @@ import java.util.Collection; import java.util.List; - /** * Represents a Schematron pattern * * @author Ivelin Ivanov, ivelin@acm.org, ivelin@iname.com */ -public class Pattern -{ - - private String name_; - private String id_; - private ArrayList rules_ = new ArrayList (); - - - /** - * Returns the id of the pattern - */ - public String getId() - { - return id_; - } - - /** - * Sets the id of the pattern - */ - public void setId( String newId ) - { - id_ = newId; - } - - /** - * Returns the name of the pattern - */ - public String getName() - { - return name_; - } - - /** - * Sets the name of the pattern - */ - public void setName( String newName ) - { - name_ = newName; - } - - /** - * Returns the list of rules - */ - public List getRule() - { - return rules_; - } - - /** - * Sets the list of rules - */ - public void setRule(Collection newRules) - { - rules_ = new ArrayList(); - rules_.addAll ( newRules ); - } - - /** - * Add a rule to the list - */ - public void addRule(Rule r) - { - rules_.add ( r ); - } - - +public class Pattern { + + private String name_; + private String id_; + private ArrayList rules_ = new ArrayList(); + + /** + * Returns the id of the pattern + */ + public String getId() { + return id_; + } + + /** + * Sets the id of the pattern + */ + public void setId(String newId) { + id_ = newId; + } + + /** + * Returns the name of the pattern + */ + public String getName() { + return name_; + } + + /** + * Sets the name of the pattern + */ + public void setName(String newName) { + name_ = newName; + } + + /** + * Returns the list of rules + */ + public List getRule() { + return rules_; + } + + /** + * Sets the list of rules + */ + public void setRule(Collection newRules) { + rules_ = new ArrayList(); + rules_.addAll(newRules); + } + + /** + * Add a rule to the list + */ + public void addRule(Rule r) { + rules_.add(r); + } + } 1.3 +48 -57 xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/Assert.java Index: Assert.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/Assert.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- Assert.java 15 Jan 2003 11:52:32 -0000 1.2 +++ Assert.java 15 Jan 2003 13:17:40 -0000 1.3 @@ -58,61 +58,52 @@ * * @author Ivelin Ivanov, ivelin@acm.org, ivelin@iname.com */ -public class Assert -{ - - private String test_; - private String message_; - private String diagnostics_; - - /** - * Returns the test attribute - */ - public String getTest() - { - return test_; - } - - /** - * Sets the test attribute - */ - public void setTest( String newTest ) - { - test_ = newTest; - } - - /** - * Returns the message for to the element - */ - public String getMessage() - { - return message_; - } - - /** - * Sets the message for to the element - */ - public void setMessage( String newMessage ) - { - message_ = newMessage; - } - - - /** - * Returns the diagnostics list - */ - public String getDiagnostics() - { - return diagnostics_; - } - - /** - * Sets the diagnostics list - */ - public void setDiagnostics( String newDiagnostics ) - { - diagnostics_ = newDiagnostics; - } - - +public class Assert { + + private String test_; + private String message_; + private String diagnostics_; + + /** + * Returns the test attribute + */ + public String getTest() { + return test_; + } + + /** + * Sets the test attribute + */ + public void setTest(String newTest) { + test_ = newTest; + } + + /** + * Returns the message for to the element + */ + public String getMessage() { + return message_; + } + + /** + * Sets the message for to the element + */ + public void setMessage(String newMessage) { + message_ = newMessage; + } + + /** + * Returns the diagnostics list + */ + public String getDiagnostics() { + return diagnostics_; + } + + /** + * Sets the diagnostics list + */ + public void setDiagnostics(String newDiagnostics) { + diagnostics_ = newDiagnostics; + } + } 1.4 +69 -81 xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/SchematronSchema.java Index: SchematronSchema.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/SchematronSchema.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- SchematronSchema.java 15 Jan 2003 11:52:32 -0000 1.3 +++ SchematronSchema.java 15 Jan 2003 13:17:40 -0000 1.4 @@ -57,7 +57,6 @@ import java.util.Collection; import java.util.List; - /** * Represents a Schematron Schema * @@ -66,85 +65,74 @@ * * @author Ivelin Ivanov, ivelin@acm.org, ivelin@iname.com */ -public class SchematronSchema implements Schema -{ - - private String title_; - private ArrayList patterns_ = new ArrayList(); - private ArrayList phases_ = new ArrayList(); - - /** - * Returns the message for to the element - */ - public String getTitle() - { - return title_; - } - - /** - * Sets the message for to the element - */ - public void setTitle( String newTitle ) - { - title_ = newTitle; - } - - /** - * Returns a list of the patterns which - * contain messages that failed during validation - */ - public List getPattern() - { - return patterns_; - } - - /** - * Sets the list of the patterns which - * contain messages that failed during validation - */ - public void setPattern(Collection newPatterns) - { - patterns_ = new ArrayList(); - patterns_.addAll ( newPatterns ); - } - - /** - * Add a pattern to the list - */ - public void addPattern(Pattern p) - { - patterns_.add ( p ); - } - - - /** - * Returns the list of schema phases - */ - public List getPhase() - { - return phases_; - } - - /** - * Sets the list of schema phases - */ - public void setPhase(Collection newPhases) - { - phases_ = new ArrayList(); - phases_.addAll ( newPhases ); - } - - /** - * Add a pattern to the list - */ - public void addPhase(Phase p) - { - phases_.add ( p ); - } - - public Validator newValidator () throws InstantiationException - { - return new SchematronValidator( this ); - } +public class SchematronSchema implements Schema { + + private String title_; + private ArrayList patterns_ = new ArrayList(); + private ArrayList phases_ = new ArrayList(); + + /** + * Returns the message for to the element + */ + public String getTitle() { + return title_; + } + + /** + * Sets the message for to the element + */ + public void setTitle(String newTitle) { + title_ = newTitle; + } + + /** + * Returns a list of the patterns which + * contain messages that failed during validation + */ + public List getPattern() { + return patterns_; + } + + /** + * Sets the list of the patterns which + * contain messages that failed during validation + */ + public void setPattern(Collection newPatterns) { + patterns_ = new ArrayList(); + patterns_.addAll(newPatterns); + } + + /** + * Add a pattern to the list + */ + public void addPattern(Pattern p) { + patterns_.add(p); + } + + /** + * Returns the list of schema phases + */ + public List getPhase() { + return phases_; + } + + /** + * Sets the list of schema phases + */ + public void setPhase(Collection newPhases) { + phases_ = new ArrayList(); + phases_.addAll(newPhases); + } + + /** + * Add a pattern to the list + */ + public void addPhase(Phase p) { + phases_.add(p); + } + + public Validator newValidator() throws InstantiationException { + return new SchematronValidator(this); + } } 1.11 +385 -357 xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/SchematronFactory.java Index: SchematronFactory.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/SchematronFactory.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- SchematronFactory.java 15 Jan 2003 11:52:32 -0000 1.10 +++ SchematronFactory.java 15 Jan 2003 13:17:40 -0000 1.11 @@ -64,7 +64,6 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; - /** * A helper class which builds a SchematronSchema instance object * from a DOM source @@ -72,362 +71,391 @@ * @author Ivelin Ivanov, ivelin@acm.org, ivelin@iname.com * @author Michael Ratliff, mratliff@collegenet.com , May 2002 */ -public class SchematronFactory extends SchemaFactory -{ - - /** - * the schema name space prefix used in the schema document - */ - private String schemaPrefix_; - - /** - * the default schema name space prefix - */ - private String defaultSchemaPrefix_ = "sch"; - - /* - * private logger - */ - private Logger logger = setupLogger(); - - - // - // Constructors - // - - /** - * initialize logger - */ - protected Logger setupLogger() - { - Logger logger = Hierarchy.getDefaultHierarchy().getLoggerFor("XmlForm"); - logger.setPriority( Priority.ERROR ); - return logger; - } - - /** - * Builds a new Schema instance from - * the given XML InputSource - * - * @param schemaSrc - * the Schema document XML InputSource - */ - public Schema compileSchema(InputSource schemaSrc) - throws InstantiationException - { - SchematronSchema schema = null; - try { - - // load Schema file into a DOM document - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance (); - DocumentBuilder dbld = dbf.newDocumentBuilder (); - Document document = dbld.parse( schemaSrc ); - - schema = buildSchema( document ); - - } catch (Exception e) { - logger.error("!!! Failed loading Schematron schema", e); - throw new CascadingRuntimeException(" !!! Failed loading Schematron schema", e); - } - return schema; - } // build - - - /** - * Build Schematron schema object from a DOM document - * @param doc DOM document containing the schema - * - */ - protected SchematronSchema buildSchema( Document doc ) - { - SchematronSchema schema = new SchematronSchema(); - boolean errors = false; - - doc.getNamespaceURI (); - doc.getPrefix (); - - // Initialize the JXPath context - Element root = doc.createElement ( "root" ); - Element schemaElement = doc.getDocumentElement (); - schemaPrefix_ = schemaElement.getPrefix (); - root.appendChild ( schemaElement ); - JXPathContext jxpContext = JXPathContext.newContext ( root ); - jxpContext.setLenient(false); - - // Bind sch:schema element - - // schema title - String title = (String) jxpContext.getValue ( "/schema/title", String.class ); - schema.setTitle( title ); - logger.debug( "Schema title: " + schema.getTitle()); - - bindPatterns( schema, jxpContext ); - bindPhases( schema, jxpContext ); - - return schema; - } - - /** - * populates the patterns elements from the dom tree - * - * @param schema the schema instance - * @param jxpContext - */ - protected void bindPatterns( SchematronSchema schema, JXPathContext jxpContext) - { - // ensure that mandatory elements which are not found - // will result in Exception - jxpContext.setLenient(false); - - // schema patterns - int ptCount = ((Integer) jxpContext.getValue ( "count(/schema/pattern)", Integer.class )).intValue(); - logger.debug( "\nNumber of patterns: " + ptCount); - for (int i = 1; i <= ptCount; i++) - { - logger.debug( "Pattern# : " + i); - Pattern pattern = new Pattern(); - String ptprefix = "/schema/pattern[" + i + "]"; - - String name = (String) jxpContext.getValue ( ptprefix + "/@name", String.class ); - pattern.setName( name ); - logger.debug( "Pattern name : " + pattern.getName()); - - String id = (String) jxpContext.getValue ( ptprefix + "/@id", String.class ); - pattern.setId( id ); - logger.debug( "Pattern id : " + pattern.getId() ); - - bindRules( pattern, ptprefix, jxpContext ); - - schema.addPattern( pattern ); - } - } - - - /** - * populates the rules elements for a pattern - * from the dom tree - * - * @param pattern - * @param pathPrefix pattern path prefix - * @param jxpContext JXPathContext - */ - protected void bindRules( Pattern pattern, String pathPrefix, JXPathContext jxpContext) - { - // ensure that mandatory elements which are not found - // will result in Exception - jxpContext.setLenient(false); - - // schema rules - int ruleCount = ((Integer) jxpContext.getValue ( "count(" + pathPrefix + "/rule)", Integer.class )).intValue(); - logger.debug( "\nNumber of rules: " + ruleCount); - for (int i = 1; i <= ruleCount; i++) - { - logger.debug( "Rule# : " + i); - Rule rule = new Rule(); - String rulePrefix = pathPrefix + "/rule[" + i + "]"; - - String context = (String) jxpContext.getValue ( rulePrefix + "/@context", String.class ); - rule.setContext( context ); - logger.debug( "Rule context : " + rule.getContext()); - - bindAsserts( rule, rulePrefix, jxpContext ); - - // Patch to make reports work in schematron - // Note change to name of bindRerports [sic] function - bindReports( rule, rulePrefix, jxpContext ); - - pattern.addRule( rule ); - } - } - - - /** - * populates the assert elements for a rule - * from the dom tree - * - * @param rule - * @param pathPrefix rule path prefix - * @param jxpContext JXPathContext - */ - protected void bindAsserts( Rule rule, String pathPrefix, JXPathContext jxpContext) - { - // ensure that mandatory elements which are not found - // will result in Exception - jxpContext.setLenient(false); - - // schema reports - int elementCount = ((Integer) jxpContext.getValue ( "count(" + pathPrefix + "/assert)", Integer.class )).intValue(); - logger.debug( "\nNumber of asserts: " + elementCount); - for (int i = 1; i <= elementCount; i++) - { - logger.debug( "Assert# : " + i); - Assert assertion = new Assert(); - String assertPrefix = pathPrefix + "/assert[" + i + "]"; - - String test = (String) jxpContext.getValue ( assertPrefix + "/@test", String.class ); - assertion.setTest( test ); - logger.debug( "Assert test : " + assertion.getTest()); - - - // since diagnostics is a non-mandatory element - // we will try to get its value in a lenient mode - jxpContext.setLenient(true); - String diagnostics = (String) jxpContext.getValue ( assertPrefix + "/@diagnostics", String.class ); - assertion.setDiagnostics( diagnostics ); - logger.debug( "Assert diagnostics : " + assertion.getDiagnostics()); - jxpContext.setLenient(false); - - - // now read the report message - // @todo: The current implementation does not - // read xml tags used within the assert message. - // Solution is to use JXPath NodePointer to get - // to the DOM node and then convert it to a String. - // e.g. - // NodePointer nptr = (NodePointer) jxpContext.locateValue( assertPrefix ); - // Node msgNode = (Node) nptr.getNodeValue(); - // convery DOMNode to String - - String message = (String) jxpContext.getValue ( assertPrefix, String.class ); - assertion.setMessage( message ); - logger.debug( "Assert message : " + assertion.getMessage()); - - rule.addAssert( assertion ); - } - } - - - /** - * populates the report elements for a rule - * from the dom tree - * - * @param rule - * @param pathPrefix rule path prefix - * @param jxpContext JXPathContext - */ - - protected void bindReports( Rule rule, String pathPrefix, JXPathContext jxpContext) - { - // ensure that mandatory elements which are not found - // will result in Exception - jxpContext.setLenient(false); - - // schema reports - int elementCount = ((Integer) jxpContext.getValue ( "count(" + pathPrefix + "/report)", Integer.class )).intValue(); - logger.debug( "\nNumber of reports: " + elementCount); - for (int i = 1; i <= elementCount; i++) - { - logger.debug( "Report# : " + i); - Report report = new Report(); - String assertPrefix = pathPrefix + "/report[" + i + "]"; - - String test = (String) jxpContext.getValue ( assertPrefix + "/@test", String.class ); - report.setTest( test ); - logger.debug( "Report test : " + report.getTest()); - - // since diagnostics is a non-mandatory element - // we will try to get its value in a lenient mode - jxpContext.setLenient(true); - String diagnostics = (String) jxpContext.getValue ( assertPrefix + "/@diagnostics", String.class ); - report.setDiagnostics( diagnostics ); - logger.debug( "Report diagnostics : " + report.getDiagnostics()); - jxpContext.setLenient(false); - - String message = (String) jxpContext.getValue ( assertPrefix, String.class ); - report.setMessage( message ); - logger.debug( "Report message : " + report.getMessage()); - - rule.addReport( report ); - } - } - - - /** - * populates the phases elements from the dom tree - * - * @param schema the schema instance - * @param jxpContext - */ - protected void bindPhases( SchematronSchema schema, JXPathContext jxpContext) - { - // ensure that mandatory elements which are not found - // will result in Exception - jxpContext.setLenient(false); - - // schema phases - int phaseCount = ((Integer) jxpContext.getValue ( "count(/schema/phase)", Integer.class )).intValue(); - logger.debug( "\nNumber of phases: " + phaseCount); - - for (int i = 1; i <= phaseCount; i++) - { - logger.debug( "phase# : " + i); - Phase phase = new Phase(); - String phprefix = "/schema/phase[" + i + "]"; - - String id = (String) jxpContext.getValue ( phprefix + "/@id", String.class ); - phase.setId( id ); - logger.debug( "phase id : " + phase.getId()); - - bindPhaseActivePatterns( phase, phprefix, jxpContext ); - - schema.addPhase( phase ); - } - } - - - protected void bindPhaseActivePatterns( Phase phase, String pathPrefix, JXPathContext jxpContext) - { - // ensure that mandatory elements which are not found - // will result in Exception - jxpContext.setLenient(false); - - // phase active patterns - int elementCount = ((Integer) jxpContext.getValue ( "count(" + pathPrefix + "/active)", Integer.class )).intValue(); - logger.debug( "Number of active patterns: " + elementCount); - for (int i = 1; i <= elementCount; i++) - { - logger.debug( "active pattern # : " + i); - ActivePattern activePattern = new ActivePattern(); - String assertPrefix = pathPrefix + "/active[" + i + "]"; - - String pt = (String) jxpContext.getValue ( assertPrefix + "/@pattern", String.class ); - activePattern.setPattern( pt ); - logger.debug( "Phase active pattern : " + activePattern.getPattern()); - - phase.addActive( activePattern ); - } - } - - - - - /* - * Replace all occurances of sch: with the actual Schema prefix used in the document - * - * @todo fix this implementaion. There are problems with DOM. - * Returns null instead of the actual namespace prefix (e.g. "sch") as expected. - */ - protected String fixns( String path ) - { - // Ironicly, at the time I am writing this - // JDK 1.4 is offering String.replaceAll(regex, str) - // I don't use it however for backward compatibility - StringBuffer strbuf = new StringBuffer( path ); - int i = 0; - int j = 0; - String dprefix = defaultSchemaPrefix_ + ":"; - int dplen = dprefix.length(); - while ( ( j = path.indexOf ( dprefix, i ) ) >= 0 ) - { - strbuf.append ( path.substring ( i, j ) ); - strbuf.append ( schemaPrefix_ ); - strbuf.append ( ':' ); - i = j + dplen; - } - strbuf.append( path.substring ( i ) ); - return strbuf.toString (); - } +public class SchematronFactory extends SchemaFactory { + /** + * the schema name space prefix used in the schema document + */ + private String schemaPrefix_; + + /** + * the default schema name space prefix + */ + private String defaultSchemaPrefix_ = "sch"; + + /* + * private logger + */ + private Logger logger = setupLogger(); + + // + // Constructors + // + + /** + * initialize logger + */ + protected Logger setupLogger() { + Logger logger = Hierarchy.getDefaultHierarchy().getLoggerFor("XmlForm"); + logger.setPriority(Priority.ERROR); + return logger; + } + + /** + * Builds a new Schema instance from + * the given XML InputSource + * + * @param schemaSrc + * the Schema document XML InputSource + */ + public Schema compileSchema(InputSource schemaSrc) + throws InstantiationException { + SchematronSchema schema = null; + try { + + // load Schema file into a DOM document + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder dbld = dbf.newDocumentBuilder(); + Document document = dbld.parse(schemaSrc); + + schema = buildSchema(document); + + } catch (Exception e) { + logger.error("!!! Failed loading Schematron schema", e); + throw new CascadingRuntimeException( + " !!! Failed loading Schematron schema", + e); + } + return schema; + } // build + + /** + * Build Schematron schema object from a DOM document + * @param doc DOM document containing the schema + * + */ + protected SchematronSchema buildSchema(Document doc) { + SchematronSchema schema = new SchematronSchema(); + boolean errors = false; + + doc.getNamespaceURI(); + doc.getPrefix(); + + // Initialize the JXPath context + Element root = doc.createElement("root"); + Element schemaElement = doc.getDocumentElement(); + schemaPrefix_ = schemaElement.getPrefix(); + root.appendChild(schemaElement); + JXPathContext jxpContext = JXPathContext.newContext(root); + jxpContext.setLenient(false); + + // Bind sch:schema element + + // schema title + String title = + (String) jxpContext.getValue("/schema/title", String.class); + schema.setTitle(title); + logger.debug("Schema title: " + schema.getTitle()); + + bindPatterns(schema, jxpContext); + bindPhases(schema, jxpContext); + + return schema; + } + + /** + * populates the patterns elements from the dom tree + * + * @param schema the schema instance + * @param jxpContext + */ + protected void bindPatterns( + SchematronSchema schema, + JXPathContext jxpContext) { + // ensure that mandatory elements which are not found + // will result in Exception + jxpContext.setLenient(false); + + // schema patterns + int ptCount = + ((Integer) jxpContext + .getValue("count(/schema/pattern)", Integer.class)) + .intValue(); + logger.debug("\nNumber of patterns: " + ptCount); + for (int i = 1; i <= ptCount; i++) { + logger.debug("Pattern# : " + i); + Pattern pattern = new Pattern(); + String ptprefix = "/schema/pattern[" + i + "]"; + + String name = + (String) jxpContext.getValue(ptprefix + "/@name", String.class); + pattern.setName(name); + logger.debug("Pattern name : " + pattern.getName()); + + String id = + (String) jxpContext.getValue(ptprefix + "/@id", String.class); + pattern.setId(id); + logger.debug("Pattern id : " + pattern.getId()); + + bindRules(pattern, ptprefix, jxpContext); + + schema.addPattern(pattern); + } + } + + /** + * populates the rules elements for a pattern + * from the dom tree + * + * @param pattern + * @param pathPrefix pattern path prefix + * @param jxpContext JXPathContext + */ + protected void bindRules( + Pattern pattern, + String pathPrefix, + JXPathContext jxpContext) { + // ensure that mandatory elements which are not found + // will result in Exception + jxpContext.setLenient(false); + + // schema rules + int ruleCount = + ((Integer) jxpContext + .getValue("count(" + pathPrefix + "/rule)", Integer.class)) + .intValue(); + logger.debug("\nNumber of rules: " + ruleCount); + for (int i = 1; i <= ruleCount; i++) { + logger.debug("Rule# : " + i); + Rule rule = new Rule(); + String rulePrefix = pathPrefix + "/rule[" + i + "]"; + + String context = + (String) jxpContext.getValue( + rulePrefix + "/@context", + String.class); + rule.setContext(context); + logger.debug("Rule context : " + rule.getContext()); + + bindAsserts(rule, rulePrefix, jxpContext); + + // Patch to make reports work in schematron + // Note change to name of bindRerports [sic] function + bindReports(rule, rulePrefix, jxpContext); + + pattern.addRule(rule); + } + } + + /** + * populates the assert elements for a rule + * from the dom tree + * + * @param rule + * @param pathPrefix rule path prefix + * @param jxpContext JXPathContext + */ + protected void bindAsserts( + Rule rule, + String pathPrefix, + JXPathContext jxpContext) { + // ensure that mandatory elements which are not found + // will result in Exception + jxpContext.setLenient(false); + + // schema reports + int elementCount = + ((Integer) jxpContext + .getValue("count(" + pathPrefix + "/assert)", Integer.class)) + .intValue(); + logger.debug("\nNumber of asserts: " + elementCount); + for (int i = 1; i <= elementCount; i++) { + logger.debug("Assert# : " + i); + Assert assertion = new Assert(); + String assertPrefix = pathPrefix + "/assert[" + i + "]"; + + String test = + (String) jxpContext.getValue( + assertPrefix + "/@test", + String.class); + assertion.setTest(test); + logger.debug("Assert test : " + assertion.getTest()); + + // since diagnostics is a non-mandatory element + // we will try to get its value in a lenient mode + jxpContext.setLenient(true); + String diagnostics = + (String) jxpContext.getValue( + assertPrefix + "/@diagnostics", + String.class); + assertion.setDiagnostics(diagnostics); + logger.debug("Assert diagnostics : " + assertion.getDiagnostics()); + jxpContext.setLenient(false); + + // now read the report message + // @todo: The current implementation does not + // read xml tags used within the assert message. + // Solution is to use JXPath NodePointer to get + // to the DOM node and then convert it to a String. + // e.g. + // NodePointer nptr = (NodePointer) jxpContext.locateValue( assertPrefix ); + // Node msgNode = (Node) nptr.getNodeValue(); + // convery DOMNode to String + + String message = + (String) jxpContext.getValue(assertPrefix, String.class); + assertion.setMessage(message); + logger.debug("Assert message : " + assertion.getMessage()); + + rule.addAssert(assertion); + } + } + + /** + * populates the report elements for a rule + * from the dom tree + * + * @param rule + * @param pathPrefix rule path prefix + * @param jxpContext JXPathContext + */ + + protected void bindReports( + Rule rule, + String pathPrefix, + JXPathContext jxpContext) { + // ensure that mandatory elements which are not found + // will result in Exception + jxpContext.setLenient(false); + + // schema reports + int elementCount = + ((Integer) jxpContext + .getValue("count(" + pathPrefix + "/report)", Integer.class)) + .intValue(); + logger.debug("\nNumber of reports: " + elementCount); + for (int i = 1; i <= elementCount; i++) { + logger.debug("Report# : " + i); + Report report = new Report(); + String assertPrefix = pathPrefix + "/report[" + i + "]"; + + String test = + (String) jxpContext.getValue( + assertPrefix + "/@test", + String.class); + report.setTest(test); + logger.debug("Report test : " + report.getTest()); + + // since diagnostics is a non-mandatory element + // we will try to get its value in a lenient mode + jxpContext.setLenient(true); + String diagnostics = + (String) jxpContext.getValue( + assertPrefix + "/@diagnostics", + String.class); + report.setDiagnostics(diagnostics); + logger.debug("Report diagnostics : " + report.getDiagnostics()); + jxpContext.setLenient(false); + + String message = + (String) jxpContext.getValue(assertPrefix, String.class); + report.setMessage(message); + logger.debug("Report message : " + report.getMessage()); + + rule.addReport(report); + } + } + + /** + * populates the phases elements from the dom tree + * + * @param schema the schema instance + * @param jxpContext + */ + protected void bindPhases( + SchematronSchema schema, + JXPathContext jxpContext) { + // ensure that mandatory elements which are not found + // will result in Exception + jxpContext.setLenient(false); + + // schema phases + int phaseCount = + ((Integer) jxpContext + .getValue("count(/schema/phase)", Integer.class)) + .intValue(); + logger.debug("\nNumber of phases: " + phaseCount); + + for (int i = 1; i <= phaseCount; i++) { + logger.debug("phase# : " + i); + Phase phase = new Phase(); + String phprefix = "/schema/phase[" + i + "]"; + + String id = + (String) jxpContext.getValue(phprefix + "/@id", String.class); + phase.setId(id); + logger.debug("phase id : " + phase.getId()); + + bindPhaseActivePatterns(phase, phprefix, jxpContext); + + schema.addPhase(phase); + } + } + + protected void bindPhaseActivePatterns( + Phase phase, + String pathPrefix, + JXPathContext jxpContext) { + // ensure that mandatory elements which are not found + // will result in Exception + jxpContext.setLenient(false); + + // phase active patterns + int elementCount = + ((Integer) jxpContext + .getValue("count(" + pathPrefix + "/active)", Integer.class)) + .intValue(); + logger.debug("Number of active patterns: " + elementCount); + for (int i = 1; i <= elementCount; i++) { + logger.debug("active pattern # : " + i); + ActivePattern activePattern = new ActivePattern(); + String assertPrefix = pathPrefix + "/active[" + i + "]"; + + String pt = + (String) jxpContext.getValue( + assertPrefix + "/@pattern", + String.class); + activePattern.setPattern(pt); + logger.debug( + "Phase active pattern : " + activePattern.getPattern()); + + phase.addActive(activePattern); + } + } + + /* + * Replace all occurances of sch: with the actual Schema prefix used in the document + * + * @todo fix this implementaion. There are problems with DOM. + * Returns null instead of the actual namespace prefix (e.g. "sch") as expected. + */ + protected String fixns(String path) { + // Ironicly, at the time I am writing this + // JDK 1.4 is offering String.replaceAll(regex, str) + // I don't use it however for backward compatibility + StringBuffer strbuf = new StringBuffer(path); + int i = 0; + int j = 0; + String dprefix = defaultSchemaPrefix_ + ":"; + int dplen = dprefix.length(); + while ((j = path.indexOf(dprefix, i)) >= 0) { + strbuf.append(path.substring(i, j)); + strbuf.append(schemaPrefix_); + strbuf.append(':'); + i = j + dplen; + } + strbuf.append(path.substring(i)); + return strbuf.toString(); + } } - 1.4 +17 -21 xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/ActivePattern.java Index: ActivePattern.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/validation/schematron/ActivePattern.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- ActivePattern.java 15 Jan 2003 11:52:32 -0000 1.3 +++ ActivePattern.java 15 Jan 2003 13:17:40 -0000 1.4 @@ -56,26 +56,22 @@ * * @author Ivelin Ivanov, ivelin@acm.org, ivelin@iname.com */ -public class ActivePattern -{ - - private String pattern_; - +public class ActivePattern { + + private String pattern_; + + /** + * Returns the active pattern name + */ + public String getPattern() { + return pattern_; + } + + /** + * Sets the active pattern name + */ + public void setPattern(String pattern) { + pattern_ = pattern; + } - /** - * Returns the active pattern name - */ - public String getPattern() - { - return pattern_; - } - - /** - * Sets the active pattern name - */ - public void setPattern( String pattern ) - { - pattern_ = pattern; - } - } 1.13 +774 -871 xml-cocoon2/src/java/org/apache/cocoon/components/xmlform/Form.java Index: Form.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/xmlform/Form.java,v retrieving revision 1.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- Form.java 27 Oct 2002 07:23:18 -0000 1.12 +++ Form.java 15 Jan 2003 13:17:41 -0000 1.13 @@ -1,65 +1,53 @@ -/* - * $Header$ - * $Revision$ - * $Date$ - * - * ==================================================================== - * The Apache Software License, Version 1.1 - * - * - * Copyright (c) 1999-2001 The Apache Software Foundation. All rights - * reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, if - * any, must include the following acknowlegement: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowlegement may appear in the software itself, - * if and wherever such third-party acknowlegements normally appear. - * - * 4. The names "The Jakarta Project", "Commons", and "Apache Software - * Foundation" must not be used to endorse or promote products derived - * from this software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache" - * nor may "Apache" appear in their names without prior written - * permission of the Apache Group. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation and was - * originally based on software copyright (c) 2001, Plotnix, Inc, - * . - * For more information on the Apache Software Foundation, please see - * . - */ +/* + + ============================================================================ + The Apache Software License, Version 1.1 + ============================================================================ + + Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modifica- + tion, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. The end-user documentation included with the redistribution, if any, must + include the following acknowledgment: "This product includes software + developed by the Apache Software Foundation (http://www.apache.org/)." + Alternately, this acknowledgment may appear in the software itself, if + and wherever such third-party acknowledgments normally appear. + + 4. The names "Apache Cocoon" and "Apache Software Foundation" must not be + used to endorse or promote products derived from this software without + prior written permission. For written permission, please contact + apache@apache.org. + + 5. Products derived from this software may not be called "Apache", nor may + "Apache" appear in their name, without prior written permission of the + Apache Software Foundation. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + This software consists of voluntary contributions made by many individuals + on behalf of the Apache Software Foundation and was originally created by + Stefano Mazzocchi . For more information on the Apache + Software Foundation, please see . +*/ package org.apache.cocoon.components.xmlform; import java.util.ArrayList; @@ -103,815 +91,730 @@ * @version $Revision$ $Date$ */ -public class Form -{ +public class Form { - public static String SCOPE_REQUEST = "request"; - public static String SCOPE_SESSION = "session"; + public static String SCOPE_REQUEST = "request"; + public static String SCOPE_SESSION = "session"; - public static String FORM_VIEW_PARAM = "cocoon-xmlform-view"; - - public static String VIOLATION_MESSAGE_DATA_FORMAT_ERROR - = "Invalid data format"; - - /** - * an XMLForm is only usable when it has an id and an underlying model - */ - public Form( String id, Object model ) - { - - if ( (id == null) || (model == null) ) - throw new java.lang.IllegalStateException( "Form cannot be created with null id or null model " ); - setId ( id ); - setModel( model ); - } - - - - public String getId() - { - return id_; - } - - public void setId( String newId ) - { - id_ = newId; - } - - - public Object getModel() - { - return model_; - } - - public void setModel( Object newModel ) - { - model_ = newModel; - jxcontext_ = JXPathContext.newContext( model_ ); - jxcontext_.setLenient( false ); - } - - - public Validator getValidator() - { - return validator_; - } - - public void setValidator( Validator newValidator ) - { - validator_ = newValidator; - } - - - public List getViolations() - { - return violations_; - } - - - /** - * - * This method allows custom validations to be added - * after population and after a call to validate - * (either automatic or explicit). - * Usually used from within the perform method of - * a concrete XMLFormAction. - * - * @param newViolations - * - */ - public void addViolations( List newViolations ) - { - - if (violations_ != null) violations_.addAll( newViolations ); - else violations_ = newViolations; - updateViolationsAsSortedSet(); - - } - - - public SortedSet getViolationsAsSortedSet() - { - return violationsAsSortedSet_; - } - - public void clearViolations() - { - violations_ = null; - violationsAsSortedSet_ = null; - } - - - /** - * Encapsulates access to the model - * - * @param xpath to the model attribute - * @param value to be set - */ - public void setValue(String xpath, Object value) - { - if ( model_ == null) - throw new IllegalStateException( "Form model not set" ); - jxcontext_.setValue(xpath, value); - } - - - public void setValue(String xpath, Object[] values) - { - -// // Dmitri Plotnikov's patch -// -// // if there are multiple values to set -// // (like in the selectMany case), -// // iterate over the array and set individual values -// if ( values.length > 1 ) -// { -// Iterator iter = jxcontext_.iteratePointers(xpath); -// for (int i = 0; i < values.length; i++ ) -// { -// Pointer ptr = (Pointer)iter.next(); -// ptr.setValue(values[i]); -// } -// } -// else -// { -// // This is supposed to do the right thing -// jxcontext_.setValue(xpath, values); -// } -// - - Pointer pointer = jxcontext_.getPointer( xpath ); - Object property = pointer.getValue(); - // if there are multiple values to set - // (like in the selectMany case), - // iterate over the array and set individual values - - // when the instance property is array - if ( property != null && property.getClass().isArray() ) - { - Class componentType = property.getClass ().getComponentType (); - property = java.lang.reflect.Array.newInstance ( componentType, values.length ); - java.lang.System.arraycopy( - values, 0, - property, 0, - values.length ); - pointer.setValue( property ); - } - else if (property instanceof Collection) - { - Collection cl = (Collection) property; - cl.clear(); - cl.addAll ( java.util.Arrays.asList ( values ) ); - } - // otherwise set the value of the first element - // (and the only) from the values array - else - { - pointer.setValue( values[0] ); - } - } - - - /** - * Encapsulates access to the model - * - * @param xpath of the model attribute - * - * @throws RuntimeException if the xpath value - * has invalid XPath syntax or it doesn't point - * to an attribute of the model - * - */ - public Object getValue(String xpath) - { - - if (model_ == null) - throw new IllegalStateException( "Form model not set" ); - Pointer pointer = jxcontext_.getPointer( xpath ); - Object property = pointer.getValue(); - if ( property != null) - { - // handle DOM elements - if (property instanceof Element) - { - String textPath = pointer.asPath() + "/text()"; - property = getValue( textPath ); - } - else if (property instanceof Text) - { - Text node = (Text) property; - property = node.getData(); - } - } - return property; - } - - - /** - * Resolves a nodeset selector - * into a list of concrete node locations - * @param xpath the nodeset selector - * - * @return a Set of XPath strings pointing to - * each nodeset satisfying the nodeset selector - * - * @todo the Collection return type should be replaced with a Set. - * LinkedHashSet implementation should be used. All resolved - * nodes are unique in the resulting set, therefore Set is more appropriate. - * Since LinkedHashSet is only available in JDK 1.4 or later, it is not - * appropriate to make the change immediately. - * - * - */ - public Collection locate( String xpathSelector ) - { - if (model_ == null) - throw new IllegalStateException( "Form model not set" ); - List nodeset = new LinkedList(); - Iterator iter = jxcontext_.iteratePointers( xpathSelector ); - while ( iter.hasNext() ) - { - Pointer nextPointer = (Pointer) iter.next(); - nodeset.add ( nextPointer.asPath() ); - } - return nodeset; - } - - - - /** - * Performs complete validation - * of the form model - */ - public boolean validate() - { - return validate( null ); - } - - - /** - * - * @param the validation phase - * - * @return - * if validation finishes without any violations, - * return true otherwise return false and save all violations - * - */ - public boolean validate( String phase ) - { - if ( validator_ == null ) return true; - - validator_.setProperty( Validator.PROPERTY_PHASE, phase ); - List vs = validator_.validate( model_ ); - - if ( violations_ != null) - { - violations_.addAll( vs ); - } - else - { - if ( vs != null && !vs.isEmpty () ) violations_ = vs; - } - - if (violations_ == null) return true; - else - { - updateViolationsAsSortedSet(); - return false; - } - } - - - - /** - *

- * Populates an HTML Form POST into the XMLForm model (JavaBean or DOM node). - * - * Expects that all request parameter names are XPath expressions - * to attributes of the model. - * For each request parameter, finds and assigns its value to the - * JavaBean property corresponding to the parameter's name - * - * - * @todo provide a more sophisticated examples with checkboxes, multi choice, - * radio button, text area, file upload, etc. - *

- */ - public void populate( Map sitemapObjectModel ) - { - // clean violations_ set - clearViolations(); - - - // let listeners know that - // population is about to start - reset(); - - // data format violations - // gathered during population - // For example when - // a request parameter value is "saymyname" - // while the request parameter name points to an int attribute - List pviolations = new ArrayList(); - - Map filteredParameters = getFilteredRequestParameters( sitemapObjectModel ); - Iterator iter = filteredParameters.entrySet().iterator(); - while (iter.hasNext()) - { - Map.Entry entry = (Map.Entry) iter.next(); - - String path = (String) entry.getKey(); - - // filter custom request parameter - // not refering to the model - if ( filterRequestParameter( path ) ) continue; - - Object[] values = (Object[]) entry.getValue(); - - try - { - setValue( path, values ); - } - catch (JXPathException ex) - { - Violation v = new Violation(); - v.setPath( path ); - String message = VIOLATION_MESSAGE_DATA_FORMAT_ERROR; - v.setMessage( message ); - pviolations.add( v ); - } - } // while - - // validate form model - autoValidate( sitemapObjectModel ); - - // merge violation sets - if ( violations_ != null) - { - violations_.addAll( pviolations ); - } - else - { - if ( !pviolations.isEmpty () ) violations_ = pviolations; - } - if ( violations_ != null) - { - updateViolationsAsSortedSet(); - } - - } - - - /** - * - * Filters request parameters which are not references to model properties. - * Sets default values for parameters which were expected in the request, - * but did not arrive (e.g. check boxes). - * - * @return filtered request parameters - * - */ - protected Map getFilteredRequestParameters( Map sitemapObjectModel ) - { - - Request request = getRequest( sitemapObjectModel ); - - Map filteredParameters = new HashMap(); - - // first filter out request parameters which do not refer to model properties - Enumeration enum = request.getParameterNames (); - while (enum.hasMoreElements ()) - { - String path = (String) enum.nextElement (); - - // filter custom request parameter - // not refering to the model - if ( filterRequestParameter( path ) ) continue; - - Object[] values = request.getParameterValues ( path ); - - filteredParameters.put( path, values ); - } - - // now, find expected parameters which did not arrive - // and set default values for them - String viewName = getFormView( sitemapObjectModel ); - Map expectedReferences = getFormViewState( viewName ).getModelReferenceMap(); - - Iterator iter = expectedReferences.entrySet().iterator(); - while ( iter.hasNext() ) - { - Map.Entry entry = (Map.Entry)iter.next(); - String propertyReference = ( String )entry.getKey(); - - // check if the expected parameter actually arrived in the request - if ( filteredParameters.get( propertyReference ) == null ) - { - // Since it is not there, try to provide a default value - String inputType = ( String )entry.getValue(); - - Object defaultValue = null; - if ( inputType.equals( XMLFormTransformer.TAG_SELECTBOOLEAN ) ) - { - // false for boolean type (usually, single check-box) - defaultValue = new Object[] { Boolean.FALSE }; - } - else if ( inputType.equals( XMLFormTransformer.TAG_SELECTMANY )) - { - // empty array for select many (usually, multi check-box) - defaultValue = new Object[0]; - } - else - { - // for all the rest, use a blank value and hope for the best - defaultValue = new Object[] {""}; - } - - filteredParameters.put( propertyReference, defaultValue ); - - } - - } // iterate over expectedReferences.entrySet() - - return filteredParameters; - - } // getFilteredRequestParameters - - /** create a SortedSet view of the violations collection - * for convenience of processors down the pipeline - * protected void updateViolationsAsSortedSet() - */ - protected void updateViolationsAsSortedSet() - { - violationsAsSortedSet_ = new TreeSet( violations_ ); - } - - /** - * - * Convenience method invoked after populate() - * By default it performs Form model validation. - * - *
- * - If default validation is not necessary - * setAutoValidate( false ) should be used - * - *
- * If the validation - * criteria needs to be different, subclasses can override - * this method to change the behaviour. - * - */ - protected void autoValidate( Map sitemapObjectModel ) - { - if (!autoValidateEnabled_) return; - // perform validation for the phase - // which matches the name of the current form view - // if one is available - String formView = getFormView( sitemapObjectModel ); - if ( formView != null) - { - validate( formView ); - } - } - - - /** - * filters custom request parameter - * not refering to the model - * - * @todo implement default filtering - * for standard Cocoon parameters - * like cocoon-action[-suffix] - * - */ - protected boolean filterRequestParameter( String name ) - { - // filter standard cocoon-* parameters - if ( filterDefaultRequestParameter( name ) ) return true; - - // then consult with FormListeners - Set ls = new HashSet(); - ls.addAll( Collections.synchronizedSet ( formListeners_ ) ); - Iterator iter = ls.iterator (); - while (iter.hasNext()) - { - FormListener fl = (FormListener) iter.next(); - // if any of the listeners wants this parameter filtered - // then filter it (return true) - if ( fl.filterRequestParameter( this, name ) ) return true; - } - // if none of the listeners wants this parameter filtered - // then don't filter it - return false; - } - - - /** - * Filters the standard cocoon request parameters. - * If default filtering needs to be different, - * subclasses can override this method. - * It is invoked before all listeners are asked to filter the parameter - */ - protected boolean filterDefaultRequestParameter( String paramName ) - { - if ( paramName.startsWith ( Constants.ACTION_PARAM_PREFIX ) - || paramName.startsWith ( Constants.VIEW_PARAM ) - ) - return true; - if ( paramName.equals ( FORM_VIEW_PARAM ) ) - return true; - else return false; - } - - - /** - * Try to extract from the request - * and return the current form view - */ - public String getFormView( Map sitemapObjectModel ) - { - Request request = getRequest( sitemapObjectModel ); - return (String) getRequest( sitemapObjectModel ).getParameter ( Form.FORM_VIEW_PARAM ); - } - - - /** - * - * This method is called before - * the form is populated with request parameters. - * - * Semanticly similar to that of the - * ActionForm.reset() in Struts - * - * Can be used for clearing checkbox fields, - * because the browser will not send them when - * not checked. - * - * Calls reset on all FormListeners - * - */ - protected void reset() - { - // notify FormListeners - Set ls = new HashSet(); - ls.addAll( Collections.synchronizedSet ( formListeners_ ) ); - Iterator iter = ls.iterator (); - while (iter.hasNext()) - { - FormListener fl = (FormListener) iter.next(); - fl.reset( this ); - } - return; - } - - - /** - * Loads a form from the request or session - * - * @param objectMap - * @param id the form id - */ - public static Form lookup ( Map sitemapObjectModel, String id ) - { - Request request = getRequest( sitemapObjectModel ); - Form form = (Form) request.getAttribute( id ); - if (form != null) return form; - else - { - Session session = request.getSession( false ); - if (session != null) form = (Form) session.getAttribute( id ); - return form; - } - } - - - /** - * Removes a form from the request and session. - * This method will remove the attribute bindings - * correspoding to the form id from both request - * and session to ensure that a subsequent - * Form.lookup will not succeed. - * - * @param objectMap - * @param id the form id - */ - public static void remove ( Map sitemapObjectModel, String id ) - { - Request request =getRequest( sitemapObjectModel ); - request.removeAttribute( id ); - - Session session = request.getSession( false ); - if (session != null) session.removeAttribute( id ); - } - - - /** - * Saves the form in the request or session - * - * @param objectMap - * @param isSessionScope if true the form will be bound in the session, otherwise request - */ - public void save ( Map sitemapObjectModel, String scope ) - { - Request request =getRequest( sitemapObjectModel ); - - if ( lookup( sitemapObjectModel, id_ ) != null ) - throw new java.lang.IllegalStateException( "Form [id=" + id_ + "] already bound in request or session " ); - - if (SCOPE_REQUEST.equals ( scope ) ) - { - request.setAttribute( id_, this ); - } - else // session scope - { - Session session = request.getSession( true ); - session.setAttribute( id_, this ); - } - - } - - - /** - * Add another FormListener - * - */ - public synchronized void addFormListener( FormListener formListener ) - { - formListeners_.add( formListener ); - } - - /** - * Add another FormListener - * - */ - public synchronized void removeFormListener( FormListener formListener ) - { - formListeners_.remove( formListener ); - } - - protected final static Request getRequest( Map sitemapObjectModel ) - { - return (Request)sitemapObjectModel.get(ObjectModelHelper.REQUEST_OBJECT); - } - - - public void setAutoValidate( boolean newAVFlag) - { - autoValidateEnabled_ = newAVFlag; - } - - - /** - *
  -   * When the transformer renders a form view,
  -   * it lets the form wrapper know about each referenced model property.
  -   * This allows a precise tracking and can be used for multiple reasons:
  -   *   1) Verify that the client does not temper with the input fields as specified by the 
  -   *      form view author
  -   *   2) Allow default values to be used for properties which were expected to be send by the client,
  -   *      but for some reason were not. A typical example is a check box. When unchecked, the browser
  -   *      does not send any request parameter, leaving it to the server to handle the situation.
  -   *      This proves to be a very error prone problem when solved on a case by case basis.
  -   *      By having a list of expected property references, the model populator can detect
  -   *      a checkbox which was not send and set the property value to false.
  -   * 
  -   * NOTE: This added functionality is ONLY useful for SESSION scope forms.
  -   * Request scope forms are constructed anew for every request and therefore
  -   * cannot benefit from this extra feature.
  -   * With the high performance CPUs and cheap memory used in today's servers,
  -   * session scope forms are a safe choice.
  -   * 
  -   * 
- * - */ - public void saveExpectedModelReferenceForView( String currentFormView, String ref, String inputType ) - { - // if the form view is null, we are not interested in saving any references - if (currentFormView == null) return; - - FormViewState formViewState = getFormViewState( currentFormView ); - formViewState.addModelReferenceAndInputType( ref, inputType ); - } - - /** - * When the transformer starts rendering a new form element - * It needs to reset previously saved references for another - * transformation of the same view. - */ - public void clearSavedModelReferences( String currentFormView ) - { - FormViewState formViewState = getFormViewState( currentFormView ); - formViewState.clear(); - } - - - /** - * We keep a map of ViewState objects which store - * all references to model properties in a particular form view - * which were rendered by the - * XMLFormTansformer in the most recent transformation. - */ - protected FormViewState getFormViewState( String viewName ) - { - FormViewState formViewState = ( FormViewState ) viewStateMap_.get( viewName ); - if (formViewState == null) - { - formViewState = new FormViewState( viewName ); - viewStateMap_.put( viewName, formViewState ); - } - return formViewState; - } - - - - - /** - * Internal class used for keeping state information - * during the life cycle of a form. - * - * Used only for session scoped forms - * - */ - class FormViewState - { - - - FormViewState( String viewName ) - { - viewName_ = viewName; - } - - /** - * - * @return Map of (String modelPropertyReference, String inputType) pairs - * - */ - Map getModelReferenceMap() - { - return modelReferences_; - } - - void addModelReferenceAndInputType( String modelPropertyReference, String inputType) - { - modelReferences_.put( modelPropertyReference, inputType ); - } - - void clear() - { - modelReferences_.clear(); - } - - private Map modelReferences_ = new HashMap(); - - private String viewName_; - - } - - - /** the set of violations the model commited during validation */ - private List violations_ = null; - - /** another view of the violations_ collection */ - private SortedSet violationsAsSortedSet_ = null; - - /** flag allowing control over automatic validation on populate() */ - private boolean autoValidateEnabled_ = true; - - /** The data model this form encapsulates */ - private Object model_ = null; - - /** The list of FormListeners */ - private Set formListeners_ = new HashSet(); - - /** - * The unique identifier for this form. Used when form is stored in request - * or session for reference by other components - * - * @todo a centralized form registry would be helpful to prevent from id collision - */ - private String id_ = null; - - /** - * The JXPath context associated with the model - * Used to traverse the model with XPath expressions - */ - private JXPathContext jxcontext_ = null; - - - /** - * Used to validate the content of the model - * at various phases - * - */ - private Validator validator_ = null; - - /** - * Keeps a state information for - * each form view that has been processed - * - */ - private Map viewStateMap_ = new HashMap(); - -} + public static String FORM_VIEW_PARAM = "cocoon-xmlform-view"; + + public static String VIOLATION_MESSAGE_DATA_FORMAT_ERROR = + "Invalid data format"; + + /** + * an XMLForm is only usable when it has an id and an underlying model + */ + public Form(String id, Object model) { + + if ((id == null) || (model == null)) + throw new java.lang.IllegalStateException( + "Form cannot be created with null id or null model "); + setId(id); + setModel(model); + } + + public String getId() { + return id_; + } + + public void setId(String newId) { + id_ = newId; + } + + public Object getModel() { + return model_; + } + + public void setModel(Object newModel) { + model_ = newModel; + jxcontext_ = JXPathContext.newContext(model_); + jxcontext_.setLenient(false); + } + + public Validator getValidator() { + return validator_; + } + + public void setValidator(Validator newValidator) { + validator_ = newValidator; + } + + public List getViolations() { + return violations_; + } + + /** + * + * This method allows custom validations to be added + * after population and after a call to validate + * (either automatic or explicit). + * Usually used from within the perform method of + * a concrete XMLFormAction. + * + * @param newViolations + * + */ + public void addViolations(List newViolations) { + + if (violations_ != null) + violations_.addAll(newViolations); + else + violations_ = newViolations; + updateViolationsAsSortedSet(); + + } + + public SortedSet getViolationsAsSortedSet() { + return violationsAsSortedSet_; + } + + public void clearViolations() { + violations_ = null; + violationsAsSortedSet_ = null; + } + + /** + * Encapsulates access to the model + * + * @param xpath to the model attribute + * @param value to be set + */ + public void setValue(String xpath, Object value) { + if (model_ == null) + throw new IllegalStateException("Form model not set"); + jxcontext_.setValue(xpath, value); + } + + public void setValue(String xpath, Object[] values) { + + // // Dmitri Plotnikov's patch + // + // // if there are multiple values to set + // // (like in the selectMany case), + // // iterate over the array and set individual values + // if ( values.length > 1 ) + // { + // Iterator iter = jxcontext_.iteratePointers(xpath); + // for (int i = 0; i < values.length; i++ ) + // { + // Pointer ptr = (Pointer)iter.next(); + // ptr.setValue(values[i]); + // } + // } + // else + // { + // // This is supposed to do the right thing + // jxcontext_.setValue(xpath, values); + // } + // + + Pointer pointer = jxcontext_.getPointer(xpath); + Object property = pointer.getValue(); + // if there are multiple values to set + // (like in the selectMany case), + // iterate over the array and set individual values + + // when the instance property is array + if (property != null && property.getClass().isArray()) { + Class componentType = property.getClass().getComponentType(); + property = + java.lang.reflect.Array.newInstance( + componentType, + values.length); + java.lang.System.arraycopy(values, 0, property, 0, values.length); + pointer.setValue(property); + } else if (property instanceof Collection) { + Collection cl = (Collection) property; + cl.clear(); + cl.addAll(java.util.Arrays.asList(values)); + } + // otherwise set the value of the first element + // (and the only) from the values array + else { + pointer.setValue(values[0]); + } + } + + /** + * Encapsulates access to the model + * + * @param xpath of the model attribute + * + * @throws RuntimeException if the xpath value + * has invalid XPath syntax or it doesn't point + * to an attribute of the model + * + */ + public Object getValue(String xpath) { + + if (model_ == null) + throw new IllegalStateException("Form model not set"); + Pointer pointer = jxcontext_.getPointer(xpath); + Object property = pointer.getValue(); + if (property != null) { + // handle DOM elements + if (property instanceof Element) { + String textPath = pointer.asPath() + "/text()"; + property = getValue(textPath); + } else if (property instanceof Text) { + Text node = (Text) property; + property = node.getData(); + } + } + return property; + } + + /** + * Resolves a nodeset selector + * into a list of concrete node locations + * @param xpath the nodeset selector + * + * @return a Set of XPath strings pointing to + * each nodeset satisfying the nodeset selector + * + * @todo the Collection return type should be replaced with a Set. + * LinkedHashSet implementation should be used. All resolved + * nodes are unique in the resulting set, therefore Set is more appropriate. + * Since LinkedHashSet is only available in JDK 1.4 or later, it is not + * appropriate to make the change immediately. + * + * + */ + public Collection locate(String xpathSelector) { + if (model_ == null) + throw new IllegalStateException("Form model not set"); + List nodeset = new LinkedList(); + Iterator iter = jxcontext_.iteratePointers(xpathSelector); + while (iter.hasNext()) { + Pointer nextPointer = (Pointer) iter.next(); + nodeset.add(nextPointer.asPath()); + } + return nodeset; + } + + /** + * Performs complete validation + * of the form model + */ + public boolean validate() { + return validate(null); + } + + /** + * + * @param the validation phase + * + * @return + * if validation finishes without any violations, + * return true otherwise return false and save all violations + * + */ + public boolean validate(String phase) { + if (validator_ == null) + return true; + + validator_.setProperty(Validator.PROPERTY_PHASE, phase); + List vs = validator_.validate(model_); + + if (violations_ != null) { + violations_.addAll(vs); + } else { + if (vs != null && !vs.isEmpty()) + violations_ = vs; + } + + if (violations_ == null) + return true; + else { + updateViolationsAsSortedSet(); + return false; + } + } + + /** + *

+ * Populates an HTML Form POST into the XMLForm model (JavaBean or DOM node). + * + * Expects that all request parameter names are XPath expressions + * to attributes of the model. + * For each request parameter, finds and assigns its value to the + * JavaBean property corresponding to the parameter's name + * + * + * @todo provide a more sophisticated examples with checkboxes, multi choice, + * radio button, text area, file upload, etc. + *

+ */ + public void populate(Map sitemapObjectModel) { + // clean violations_ set + clearViolations(); + + // let listeners know that + // population is about to start + reset(); + + // data format violations + // gathered during population + // For example when + // a request parameter value is "saymyname" + // while the request parameter name points to an int attribute + List pviolations = new ArrayList(); + + Map filteredParameters = + getFilteredRequestParameters(sitemapObjectModel); + Iterator iter = filteredParameters.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry) iter.next(); + + String path = (String) entry.getKey(); + + // filter custom request parameter + // not refering to the model + if (filterRequestParameter(path)) + continue; + + Object[] values = (Object[]) entry.getValue(); + + try { + setValue(path, values); + } catch (JXPathException ex) { + Violation v = new Violation(); + v.setPath(path); + String message = VIOLATION_MESSAGE_DATA_FORMAT_ERROR; + v.setMessage(message); + pviolations.add(v); + } + } // while + + // validate form model + autoValidate(sitemapObjectModel); + + // merge violation sets + if (violations_ != null) { + violations_.addAll(pviolations); + } else { + if (!pviolations.isEmpty()) + violations_ = pviolations; + } + if (violations_ != null) { + updateViolationsAsSortedSet(); + } + + } + + /** + * + * Filters request parameters which are not references to model properties. + * Sets default values for parameters which were expected in the request, + * but did not arrive (e.g. check boxes). + * + * @return filtered request parameters + * + */ + protected Map getFilteredRequestParameters(Map sitemapObjectModel) { + + Request request = getRequest(sitemapObjectModel); + + Map filteredParameters = new HashMap(); + + // first filter out request parameters which do not refer to model properties + Enumeration enum = request.getParameterNames(); + while (enum.hasMoreElements()) { + String path = (String) enum.nextElement(); + + // filter custom request parameter + // not refering to the model + if (filterRequestParameter(path)) + continue; + + Object[] values = request.getParameterValues(path); + + filteredParameters.put(path, values); + } + + // now, find expected parameters which did not arrive + // and set default values for them + String viewName = getFormView(sitemapObjectModel); + Map expectedReferences = + getFormViewState(viewName).getModelReferenceMap(); + + Iterator iter = expectedReferences.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry) iter.next(); + String propertyReference = (String) entry.getKey(); + + // check if the expected parameter actually arrived in the request + if (filteredParameters.get(propertyReference) == null) { + // Since it is not there, try to provide a default value + String inputType = (String) entry.getValue(); + + Object defaultValue = null; + if (inputType.equals(XMLFormTransformer.TAG_SELECTBOOLEAN)) { + // false for boolean type (usually, single check-box) + defaultValue = new Object[] { Boolean.FALSE }; + } else if ( + inputType.equals(XMLFormTransformer.TAG_SELECTMANY)) { + // empty array for select many (usually, multi check-box) + defaultValue = new Object[0]; + } else { + // for all the rest, use a blank value and hope for the best + defaultValue = new Object[] { "" }; + } + + filteredParameters.put(propertyReference, defaultValue); + + } + + } // iterate over expectedReferences.entrySet() + + return filteredParameters; + + } // getFilteredRequestParameters + + /** create a SortedSet view of the violations collection + * for convenience of processors down the pipeline + * protected void updateViolationsAsSortedSet() + */ + protected void updateViolationsAsSortedSet() { + violationsAsSortedSet_ = new TreeSet(violations_); + } + + /** + * + * Convenience method invoked after populate() + * By default it performs Form model validation. + * + *
+ * - If default validation is not necessary + * setAutoValidate( false ) should be used + * + *
+ * If the validation + * criteria needs to be different, subclasses can override + * this method to change the behaviour. + * + */ + protected void autoValidate(Map sitemapObjectModel) { + if (!autoValidateEnabled_) + return; + // perform validation for the phase + // which matches the name of the current form view + // if one is available + String formView = getFormView(sitemapObjectModel); + if (formView != null) { + validate(formView); + } + } + + /** + * filters custom request parameter + * not refering to the model + * + * @todo implement default filtering + * for standard Cocoon parameters + * like cocoon-action[-suffix] + * + */ + protected boolean filterRequestParameter(String name) { + // filter standard cocoon-* parameters + if (filterDefaultRequestParameter(name)) + return true; + + // then consult with FormListeners + Set ls = new HashSet(); + ls.addAll(Collections.synchronizedSet(formListeners_)); + Iterator iter = ls.iterator(); + while (iter.hasNext()) { + FormListener fl = (FormListener) iter.next(); + // if any of the listeners wants this parameter filtered + // then filter it (return true) + if (fl.filterRequestParameter(this, name)) + return true; + } + // if none of the listeners wants this parameter filtered + // then don't filter it + return false; + } + + /** + * Filters the standard cocoon request parameters. + * If default filtering needs to be different, + * subclasses can override this method. + * It is invoked before all listeners are asked to filter the parameter + */ + protected boolean filterDefaultRequestParameter(String paramName) { + if (paramName.startsWith(Constants.ACTION_PARAM_PREFIX) + || paramName.startsWith(Constants.VIEW_PARAM)) + return true; + if (paramName.equals(FORM_VIEW_PARAM)) + return true; + else + return false; + } + + /** + * Try to extract from the request + * and return the current form view + */ + public String getFormView(Map sitemapObjectModel) { + Request request = getRequest(sitemapObjectModel); + return (String) getRequest(sitemapObjectModel).getParameter( + Form.FORM_VIEW_PARAM); + } + + /** + * + * This method is called before + * the form is populated with request parameters. + * + * Semanticly similar to that of the + * ActionForm.reset() in Struts + * + * Can be used for clearing checkbox fields, + * because the browser will not send them when + * not checked. + * + * Calls reset on all FormListeners + * + */ + protected void reset() { + // notify FormListeners + Set ls = new HashSet(); + ls.addAll(Collections.synchronizedSet(formListeners_)); + Iterator iter = ls.iterator(); + while (iter.hasNext()) { + FormListener fl = (FormListener) iter.next(); + fl.reset(this); + } + return; + } + + /** + * Loads a form from the request or session + * + * @param objectMap + * @param id the form id + */ + public static Form lookup(Map sitemapObjectModel, String id) { + Request request = getRequest(sitemapObjectModel); + Form form = (Form) request.getAttribute(id); + if (form != null) + return form; + else { + Session session = request.getSession(false); + if (session != null) + form = (Form) session.getAttribute(id); + return form; + } + } + + /** + * Removes a form from the request and session. + * This method will remove the attribute bindings + * correspoding to the form id from both request + * and session to ensure that a subsequent + * Form.lookup will not succeed. + * + * @param objectMap + * @param id the form id + */ + public static void remove(Map sitemapObjectModel, String id) { + Request request = getRequest(sitemapObjectModel); + request.removeAttribute(id); + + Session session = request.getSession(false); + if (session != null) + session.removeAttribute(id); + } + + /** + * Saves the form in the request or session + * + * @param objectMap + * @param isSessionScope if true the form will be bound in the session, otherwise request + */ + public void save(Map sitemapObjectModel, String scope) { + Request request = getRequest(sitemapObjectModel); + + if (lookup(sitemapObjectModel, id_) != null) + throw new java.lang.IllegalStateException( + "Form [id=" + id_ + "] already bound in request or session "); + + if (SCOPE_REQUEST.equals(scope)) { + request.setAttribute(id_, this); + } else // session scope + { + Session session = request.getSession(true); + session.setAttribute(id_, this); + } + + } + + /** + * Add another FormListener + * + */ + public synchronized void addFormListener(FormListener formListener) { + formListeners_.add(formListener); + } + + /** + * Add another FormListener + * + */ + public synchronized void removeFormListener(FormListener formListener) { + formListeners_.remove(formListener); + } + + protected final static Request getRequest(Map sitemapObjectModel) { + return (Request) sitemapObjectModel.get( + ObjectModelHelper.REQUEST_OBJECT); + } + + public void setAutoValidate(boolean newAVFlag) { + autoValidateEnabled_ = newAVFlag; + } + + /** + *
  +	 * When the transformer renders a form view,
  +	 * it lets the form wrapper know about each referenced model property.
  +	 * This allows a precise tracking and can be used for multiple reasons:
  +	 *   1) Verify that the client does not temper with the input fields as specified by the 
  +	 *      form view author
  +	 *   2) Allow default values to be used for properties which were expected to be send by the client,
  +	 *      but for some reason were not. A typical example is a check box. When unchecked, the browser
  +	 *      does not send any request parameter, leaving it to the server to handle the situation.
  +	 *      This proves to be a very error prone problem when solved on a case by case basis.
  +	 *      By having a list of expected property references, the model populator can detect
  +	 *      a checkbox which was not send and set the property value to false.
  +	 * 
  +	 * NOTE: This added functionality is ONLY useful for SESSION scope forms.
  +	 * Request scope forms are constructed anew for every request and therefore
  +	 * cannot benefit from this extra feature.
  +	 * With the high performance CPUs and cheap memory used in today's servers,
  +	 * session scope forms are a safe choice.
  +	 * 
  +	 * 
+ * + */ + public void saveExpectedModelReferenceForView( + String currentFormView, + String ref, + String inputType) { + // if the form view is null, we are not interested in saving any references + if (currentFormView == null) + return; + + FormViewState formViewState = getFormViewState(currentFormView); + formViewState.addModelReferenceAndInputType(ref, inputType); + } + + /** + * When the transformer starts rendering a new form element + * It needs to reset previously saved references for another + * transformation of the same view. + */ + public void clearSavedModelReferences(String currentFormView) { + FormViewState formViewState = getFormViewState(currentFormView); + formViewState.clear(); + } + + /** + * We keep a map of ViewState objects which store + * all references to model properties in a particular form view + * which were rendered by the + * XMLFormTansformer in the most recent transformation. + */ + protected FormViewState getFormViewState(String viewName) { + FormViewState formViewState = + (FormViewState) viewStateMap_.get(viewName); + if (formViewState == null) { + formViewState = new FormViewState(viewName); + viewStateMap_.put(viewName, formViewState); + } + return formViewState; + } + + /** + * Internal class used for keeping state information + * during the life cycle of a form. + * + * Used only for session scoped forms + * + */ + class FormViewState { + + FormViewState(String viewName) { + viewName_ = viewName; + } + + /** + * + * @return Map of (String modelPropertyReference, String inputType) pairs + * + */ + Map getModelReferenceMap() { + return modelReferences_; + } + + void addModelReferenceAndInputType( + String modelPropertyReference, + String inputType) { + modelReferences_.put(modelPropertyReference, inputType); + } + + void clear() { + modelReferences_.clear(); + } + + private Map modelReferences_ = new HashMap(); + + private String viewName_; + + } + + /** the set of violations the model commited during validation */ + private List violations_ = null; + + /** another view of the violations_ collection */ + private SortedSet violationsAsSortedSet_ = null; + + /** flag allowing control over automatic validation on populate() */ + private boolean autoValidateEnabled_ = true; + + /** The data model this form encapsulates */ + private Object model_ = null; + + /** The list of FormListeners */ + private Set formListeners_ = new HashSet(); + + /** + * The unique identifier for this form. Used when form is stored in request + * or session for reference by other components + * + * @todo a centralized form registry would be helpful to prevent from id collision + */ + private String id_ = null; + + /** + * The JXPath context associated with the model + * Used to traverse the model with XPath expressions + */ + private JXPathContext jxcontext_ = null; + + /** + * Used to validate the content of the model + * at various phases + * + */ + private Validator validator_ = null; + + /** + * Keeps a state information for + * each form view that has been processed + * + */ + private Map viewStateMap_ = new HashMap(); +} 1.2 +73 -86 xml-cocoon2/src/java/org/apache/cocoon/components/xmlform/FormListener.java Index: FormListener.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/xmlform/FormListener.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- FormListener.java 20 May 2002 07:19:25 -0000 1.1 +++ FormListener.java 15 Jan 2003 13:17:41 -0000 1.2 @@ -1,65 +1,53 @@ -/* - * $Header$ - * $Revision$ - * $Date$ - * - * ==================================================================== - * The Apache Software License, Version 1.1 - * - * - * Copyright (c) 1999-2001 The Apache Software Foundation. All rights - * reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, if - * any, must include the following acknowlegement: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowlegement may appear in the software itself, - * if and wherever such third-party acknowlegements normally appear. - * - * 4. The names "The Jakarta Project", "Commons", and "Apache Software - * Foundation" must not be used to endorse or promote products derived - * from this software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache" - * nor may "Apache" appear in their names without prior written - * permission of the Apache Group. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation and was - * originally based on software copyright (c) 2001, Plotnix, Inc, - * . - * For more information on the Apache Software Foundation, please see - * . - */ +/* + + ============================================================================ + The Apache Software License, Version 1.1 + ============================================================================ + + Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modifica- + tion, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. The end-user documentation included with the redistribution, if any, must + include the following acknowledgment: "This product includes software + developed by the Apache Software Foundation (http://www.apache.org/)." + Alternately, this acknowledgment may appear in the software itself, if + and wherever such third-party acknowledgments normally appear. + + 4. The names "Apache Cocoon" and "Apache Software Foundation" must not be + used to endorse or promote products derived from this software without + prior written permission. For written permission, please contact + apache@apache.org. + + 5. Products derived from this software may not be called "Apache", nor may + "Apache" appear in their name, without prior written permission of the + Apache Software Foundation. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + This software consists of voluntary contributions made by many individuals + on behalf of the Apache Software Foundation and was originally created by + Stefano Mazzocchi . For more information on the Apache + Software Foundation, please see . +*/ package org.apache.cocoon.components.xmlform; /** @@ -73,31 +61,30 @@ * @version $Revision$ $Date$ */ -public interface FormListener -{ +public interface FormListener { - /** - * This method is called before - * the form is populated with request parameters. - * - * Semanticly similar to that of the - * ActionForm.reset() in Struts - * - * Can be used for clearing checkbox fields, - * because the browser will not send them when - * not checked. - * - * This method does nothing by default - * Subclasses should override it to implement custom logic - * - */ - public void reset( Form form ); - - /** - * filters custom request parameter - * not refering to the model - */ - public boolean filterRequestParameter( Form form, String parameterName ); + /** + * This method is called before + * the form is populated with request parameters. + * + * Semanticly similar to that of the + * ActionForm.reset() in Struts + * + * Can be used for clearing checkbox fields, + * because the browser will not send them when + * not checked. + * + * This method does nothing by default + * Subclasses should override it to implement custom logic + * + */ + void reset(Form form); + + /** + * filters custom request parameter + * not refering to the model + */ + boolean filterRequestParameter(Form form, String parameterName); } ---------------------------------------------------------------------- In case of troubles, e-mail: webmaster@xml.apache.org To unsubscribe, e-mail: cocoon-cvs-unsubscribe@xml.apache.org For additional commands, e-mail: cocoon-cvs-help@xml.apache.org