1
2
3
4
5
6
7
8 package net.sf.jour.config.impl.runtime;
9
10 import java.util.HashMap;
11 import java.util.HashSet;
12 import java.util.Iterator;
13 import java.util.Map;
14
15 import javax.xml.bind.ValidationEvent;
16 import javax.xml.bind.ValidationEventHandler;
17 import javax.xml.bind.helpers.NotIdentifiableEventImpl;
18 import javax.xml.bind.helpers.ValidationEventImpl;
19 import javax.xml.bind.helpers.ValidationEventLocatorImpl;
20
21 import org.xml.sax.SAXException;
22
23 import com.sun.xml.bind.ProxyGroup;
24 import com.sun.xml.bind.serializer.AbortSerializationException;
25 import com.sun.xml.bind.validator.Messages;
26
27 /***
28 * Maintains information that needs to be stored across
29 * validations of multiple objects.
30 *
31 * Specifically, this object is responsible for:
32 *
33 * <ol>
34 * <li>detecting a cycle in a content tree by keeping track of
35 * objects that were validated.
36 *
37 * <li>keeping an instance of NamespaceContextImpl, which is
38 * shared by all MSVValidators.
39 *
40 * <li>keeping a reference to {@link ValidationErrorHandler}.
41 * MSVValidators should use this error handler to report any error.
42 * </ol>
43 */
44 class ValidationContext
45 {
46 final DefaultJAXBContextImpl jaxbContext;
47 /***
48 * @param validateID
49 * if true, ID/IDREF validation will be performed.
50 */
51 ValidationContext( DefaultJAXBContextImpl _context, ValidationEventHandler _eventHandler, boolean validateID ) {
52 this.jaxbContext = _context;
53 this.eventHandler = _eventHandler;
54 this.validateID = validateID;
55 }
56
57
58
59
60
61
62
63
64
65 /*** Set of all validated objects. Used to detect a cycle. */
66 private final HashSet validatedObjects = new HashSet();
67
68 /***
69 * Validates the sub-tree rooted at <code>vo</code> and reports
70 * any errors/warnings to the error handler.
71 */
72 public void validate( ValidatableObject vo ) throws SAXException {
73 if( validatedObjects.add(ProxyGroup.unwrap(vo)) ) {
74
75 MSVValidator.validate(jaxbContext,this,vo);
76 } else {
77
78 reportEvent( vo, Messages.format( Messages.CYCLE_DETECTED ) );
79 }
80 }
81
82
83
84
85
86
87
88
89 /*** namespace context. */
90 private final NamespaceContextImpl nsContext = new NamespaceContextImpl(null);
91
92 public NamespaceContextImpl getNamespaceContext() { return nsContext; }
93
94
95
96
97
98
99
100 /*** ID/IDREF validation is done only when this flag is true. */
101 private final boolean validateID;
102
103 private final HashSet IDs = new HashSet();
104 private final HashMap IDREFs = new HashMap();
105
106 public String onID( XMLSerializable owner, String value ) throws SAXException {
107
108 if(!validateID) return value;
109
110 if(!IDs.add(value)) {
111
112
113
114 reportEvent(jaxbContext.getGrammarInfo().castToValidatableObject(owner),
115 Messages.format(Messages.DUPLICATE_ID,value));
116 }
117
118 return value;
119 }
120 public String onIDREF( XMLSerializable referer, String value ) throws SAXException {
121 if(!validateID) return value;
122
123 if(IDs.contains(value))
124 return value;
125
126
127 IDREFs.put(value,referer);
128
129 return value;
130 }
131 /*** Tests if all IDREFs have corresponding IDs. */
132 protected void reconcileIDs() throws SAXException {
133 if(!validateID) return;
134
135 for (Iterator itr = IDREFs.entrySet().iterator(); itr.hasNext();) {
136 Map.Entry e = (Map.Entry) itr.next();
137
138 if(IDs.contains(e.getKey()))
139 continue;
140
141
142 ValidatableObject source = (ValidatableObject)e.getValue();
143 reportEvent(
144 source,
145 new NotIdentifiableEventImpl(
146 ValidationEvent.ERROR,
147 Messages.format( Messages.ID_NOT_FOUND, e.getKey() ),
148 new ValidationEventLocatorImpl( source ) ) );
149 }
150
151 IDREFs.clear();
152 }
153
154
155
156
157
158
159
160 private final ValidationEventHandler eventHandler;
161
162 /***
163 * Reports an error to the application.
164 */
165 public void reportEvent(ValidatableObject source, String formattedMessage) throws AbortSerializationException {
166 reportEvent(
167 source,
168 new ValidationEventImpl( ValidationEvent.ERROR,
169 formattedMessage,
170 new ValidationEventLocatorImpl(source) ) );
171 }
172
173 /***
174 * Reports an error to the client.
175 * This version should be used when an exception is thrown from sub-modules.
176 */
177 public void reportEvent(ValidatableObject source, Exception nestedException ) throws AbortSerializationException {
178 reportEvent(
179 source,
180 new ValidationEventImpl( ValidationEvent.ERROR,
181 nestedException.toString(),
182 new ValidationEventLocatorImpl(source),
183 nestedException ) );
184 }
185
186 public void reportEvent( ValidatableObject source, ValidationEvent event ) throws AbortSerializationException {
187 boolean r;
188
189 try {
190 r = eventHandler.handleEvent( event );
191 } catch( RuntimeException re ) {
192
193
194 r = false;
195 }
196
197 if(!r) {
198
199 throw new AbortSerializationException( event.getMessage() );
200 }
201 }
202
203
204
205 }