View Javadoc
1   /*******************************************************************************
2    * Portions created by Sebastian Thomschke are copyright (c) 2005-2013 Sebastian
3    * Thomschke.
4    *
5    * All Rights Reserved. This program and the accompanying materials
6    * are made available under the terms of the Eclipse Public License v1.0
7    * which accompanies this distribution, and is available at
8    * http://www.eclipse.org/legal/epl-v10.html
9    *
10   * Contributors:
11   *     Sebastian Thomschke - initial implementation.
12   *******************************************************************************/
13  package net.sf.oval.configuration.xml;
14  
15  import java.io.BufferedInputStream;
16  import java.io.File;
17  import java.io.FileInputStream;
18  import java.io.IOException;
19  import java.io.InputStream;
20  import java.io.OutputStream;
21  import java.io.Reader;
22  import java.io.Writer;
23  import java.lang.annotation.Annotation;
24  import java.lang.reflect.Method;
25  import java.lang.reflect.ParameterizedType;
26  import java.lang.reflect.Type;
27  import java.util.ArrayList;
28  import java.util.LinkedHashSet;
29  import java.util.List;
30  import java.util.Set;
31  import java.util.regex.Pattern;
32  
33  import net.sf.oval.AbstractCheck;
34  import net.sf.oval.Check;
35  import net.sf.oval.CheckExclusion;
36  import net.sf.oval.ConstraintTarget;
37  import net.sf.oval.Validator;
38  import net.sf.oval.configuration.CheckInitializationListener;
39  import net.sf.oval.configuration.Configurer;
40  import net.sf.oval.configuration.annotation.AbstractAnnotationCheck;
41  import net.sf.oval.configuration.annotation.Constraint;
42  import net.sf.oval.configuration.pojo.POJOConfigurer;
43  import net.sf.oval.configuration.pojo.elements.ClassConfiguration;
44  import net.sf.oval.configuration.pojo.elements.ConstraintSetConfiguration;
45  import net.sf.oval.configuration.pojo.elements.ConstructorConfiguration;
46  import net.sf.oval.configuration.pojo.elements.FieldConfiguration;
47  import net.sf.oval.configuration.pojo.elements.MethodConfiguration;
48  import net.sf.oval.configuration.pojo.elements.MethodPostExecutionConfiguration;
49  import net.sf.oval.configuration.pojo.elements.MethodPreExecutionConfiguration;
50  import net.sf.oval.configuration.pojo.elements.MethodReturnValueConfiguration;
51  import net.sf.oval.configuration.pojo.elements.ObjectConfiguration;
52  import net.sf.oval.configuration.pojo.elements.ParameterConfiguration;
53  import net.sf.oval.constraint.AssertCheck;
54  import net.sf.oval.constraint.AssertConstraintSetCheck;
55  import net.sf.oval.constraint.AssertFalseCheck;
56  import net.sf.oval.constraint.AssertFieldConstraintsCheck;
57  import net.sf.oval.constraint.AssertNullCheck;
58  import net.sf.oval.constraint.AssertTrueCheck;
59  import net.sf.oval.constraint.AssertURLCheck;
60  import net.sf.oval.constraint.AssertURLCheck.URIScheme;
61  import net.sf.oval.constraint.AssertValidCheck;
62  import net.sf.oval.constraint.CheckWithCheck;
63  import net.sf.oval.constraint.CheckWithCheck.SimpleCheck;
64  import net.sf.oval.constraint.DateRangeCheck;
65  import net.sf.oval.constraint.DigitsCheck;
66  import net.sf.oval.constraint.EmailCheck;
67  import net.sf.oval.constraint.EqualToFieldCheck;
68  import net.sf.oval.constraint.FutureCheck;
69  import net.sf.oval.constraint.HasSubstringCheck;
70  import net.sf.oval.constraint.InstanceOfAnyCheck;
71  import net.sf.oval.constraint.InstanceOfCheck;
72  import net.sf.oval.constraint.LengthCheck;
73  import net.sf.oval.constraint.MatchPatternCheck;
74  import net.sf.oval.constraint.MaxCheck;
75  import net.sf.oval.constraint.MaxLengthCheck;
76  import net.sf.oval.constraint.MaxSizeCheck;
77  import net.sf.oval.constraint.MemberOfCheck;
78  import net.sf.oval.constraint.MinCheck;
79  import net.sf.oval.constraint.MinLengthCheck;
80  import net.sf.oval.constraint.MinSizeCheck;
81  import net.sf.oval.constraint.NoSelfReferenceCheck;
82  import net.sf.oval.constraint.NotBlankCheck;
83  import net.sf.oval.constraint.NotEmptyCheck;
84  import net.sf.oval.constraint.NotEqualCheck;
85  import net.sf.oval.constraint.NotEqualToFieldCheck;
86  import net.sf.oval.constraint.NotMatchPatternCheck;
87  import net.sf.oval.constraint.NotMemberOfCheck;
88  import net.sf.oval.constraint.NotNegativeCheck;
89  import net.sf.oval.constraint.NotNullCheck;
90  import net.sf.oval.constraint.PastCheck;
91  import net.sf.oval.constraint.RangeCheck;
92  import net.sf.oval.constraint.SizeCheck;
93  import net.sf.oval.constraint.ValidateWithMethodCheck;
94  import net.sf.oval.constraint.exclusion.NullableExclusion;
95  import net.sf.oval.exception.InvalidConfigurationException;
96  import net.sf.oval.guard.PostCheck;
97  import net.sf.oval.guard.PreCheck;
98  import net.sf.oval.internal.Log;
99  import net.sf.oval.internal.util.Assert;
100 import net.sf.oval.internal.util.ReflectionUtils;
101 
102 import com.thoughtworks.xstream.XStream;
103 import com.thoughtworks.xstream.converters.Converter;
104 import com.thoughtworks.xstream.converters.MarshallingContext;
105 import com.thoughtworks.xstream.converters.UnmarshallingContext;
106 import com.thoughtworks.xstream.converters.collections.CollectionConverter;
107 import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
108 import com.thoughtworks.xstream.converters.reflection.Sun14ReflectionProvider;
109 import com.thoughtworks.xstream.io.HierarchicalStreamDriver;
110 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
111 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
112 import com.thoughtworks.xstream.io.xml.DomDriver;
113 import com.thoughtworks.xstream.io.xml.StaxDriver;
114 import com.thoughtworks.xstream.io.xml.XppDriver;
115 import com.thoughtworks.xstream.mapper.Mapper;
116 
117 /**
118  * XStream (http://xstream.codehaus.org/) based XML configuration class.
119  *
120  * @author Sebastian Thomschke
121  */
122 public class XMLConfigurer implements Configurer
123 {
124 	/**
125 	 * The converter is needed to allow the rendering of Assert's expr attribute value as an XML node value and not an XML attribute
126 	 * <code>&lt;assert&gt;&lt;expr&gt;...&lt;/expr&gt;&lt;/assert&gt;</code> instead of <code>&lt;assert expr="..."&gt;</code>
127 	 * This allows users to write complex, multi-line expressions.
128 	 */
129 	protected final class AssertCheckConverter implements Converter
130 	{
131 		/**
132 		 * {@inheritDoc}
133 		 */
134 		public boolean canConvert(@SuppressWarnings("rawtypes") final Class clazz)
135 		{
136 			return clazz.equals(AssertCheck.class);
137 		}
138 
139 		/**
140 		 * {@inheritDoc}
141 		 */
142 		public void marshal(final Object value, final HierarchicalStreamWriter writer, final MarshallingContext context)
143 		{
144 			final AssertCheck assertCheck = (AssertCheck) value;
145 			writer.addAttribute("lang", assertCheck.getLang());
146 			if (!"net.sf.oval.constraint.Assert.violated".equals(assertCheck.getMessage()))
147 				writer.addAttribute("message", assertCheck.getMessage());
148 			if (!"net.sf.oval.constraint.Assert".equals(assertCheck.getErrorCode()))
149 				writer.addAttribute("errorCode", assertCheck.getErrorCode());
150 			writer.addAttribute("severity", Integer.toString(assertCheck.getSeverity()));
151 			if (assertCheck.getWhen() != null) writer.addAttribute("when", assertCheck.getWhen());
152 			writer.startNode("expr");
153 			writer.setValue(assertCheck.getExpr());
154 			writer.endNode();
155 			final String[] profiles = assertCheck.getProfiles();
156 			if (profiles != null && profiles.length > 0)
157 			{
158 				writer.startNode("profiles");
159 				for (final String profile : profiles)
160 				{
161 					writer.startNode("string");
162 					writer.setValue(profile);
163 					writer.endNode();
164 				}
165 				writer.endNode();
166 			}
167 			final ConstraintTarget[] appliesTo = assertCheck.getAppliesTo();
168 			if (appliesTo != null && appliesTo.length > 0)
169 			{
170 				writer.startNode("appliesTo");
171 				for (final ConstraintTarget ctarget : appliesTo)
172 				{
173 					writer.startNode("constraintTarget");
174 					writer.setValue(ctarget.name());
175 					writer.endNode();
176 				}
177 				writer.endNode();
178 			}
179 		}
180 
181 		/**
182 		 * {@inheritDoc}
183 		 */
184 		public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context)
185 		{
186 			final AssertCheck assertCheck = new AssertCheck();
187 			assertCheck.setLang(reader.getAttribute("lang"));
188 			assertCheck.setMessage(reader.getAttribute("message"));
189 			assertCheck.setErrorCode(reader.getAttribute("errorCode"));
190 			if (reader.getAttribute("severity") != null) assertCheck.setSeverity(Integer.parseInt(reader.getAttribute("severity")));
191 			assertCheck.setTarget(reader.getAttribute("target"));
192 			assertCheck.setWhen(reader.getAttribute("when"));
193 
194 			reader.moveDown();
195 			assertCheck.setExpr(reader.getValue());
196 			reader.moveUp();
197 			if (reader.hasMoreChildren())
198 			{
199 				reader.moveDown();
200 				if ("appliesTo".equals(reader.getNodeName()))
201 				{
202 					final List<ConstraintTarget> targets = new ArrayList<ConstraintTarget>(2);
203 					while (reader.hasMoreChildren())
204 					{
205 						reader.moveDown();
206 						if ("constraintTarget".equals(reader.getNodeName())) targets.add(ConstraintTarget.valueOf(reader.getValue()));
207 						reader.moveUp();
208 					}
209 					assertCheck.setAppliesTo(targets.toArray(new ConstraintTarget[targets.size()]));
210 				}
211 				else if ("profiles".equals(reader.getNodeName()))
212 				{
213 					final List<String> profiles = new ArrayList<String>(4);
214 					while (reader.hasMoreChildren())
215 					{
216 						reader.moveDown();
217 						if ("string".equals(reader.getNodeName())) profiles.add(reader.getValue());
218 						reader.moveUp();
219 					}
220 					assertCheck.setProfiles(profiles.toArray(new String[profiles.size()]));
221 				}
222 				reader.moveUp();
223 			}
224 			for (final CheckInitializationListener listener : listeners)
225 				listener.onCheckInitialized(assertCheck);
226 			return assertCheck;
227 		}
228 	}
229 
230 	private static final class ListConverter extends CollectionConverter
231 	{
232 		protected ListConverter(final Mapper mapper)
233 		{
234 			super(mapper);
235 		}
236 
237 		/**
238 		 * {@inheritDoc}
239 		 */
240 		@Override
241 		public boolean canConvert(@SuppressWarnings("rawtypes") final Class type)
242 		{
243 			return List.class.isAssignableFrom(type);
244 		}
245 	}
246 
247 	/**
248 	 * This reflection provider applies default values declared on constraint annotations to the corresponding check class
249 	 */
250 	protected static final class XStreamReflectionProvider extends Sun14ReflectionProvider
251 	{
252 		@SuppressWarnings("unchecked")
253 		@Override
254 		public Object newInstance(@SuppressWarnings("rawtypes") final Class type)
255 		{
256 			final Object instance = super.newInstance(type);
257 
258 			// test if a AnnotationCheck instance is requested
259 			if (instance instanceof AbstractAnnotationCheck)
260 			{
261 				// determine the constraint annotation
262 				Class<Annotation> constraintAnnotation = null;
263 				final ParameterizedType genericSuperclass = (ParameterizedType) type.getGenericSuperclass();
264 				for (final Type genericType : genericSuperclass.getActualTypeArguments())
265 				{
266 					final Class< ? > genericClass = (Class< ? >) genericType;
267 					if (genericClass.isAnnotation() && genericClass.isAnnotationPresent(Constraint.class))
268 					{
269 						constraintAnnotation = (Class<Annotation>) genericClass;
270 						break;
271 					}
272 				}
273 				// in case we could determine the constraint annotation, read the attributes and
274 				// apply the declared default values to the check instance
275 				if (constraintAnnotation != null) for (final Method m : constraintAnnotation.getMethods())
276 				{
277 					final Object defaultValue = m.getDefaultValue();
278 					if (defaultValue != null) ReflectionUtils.setViaSetter(instance, m.getName(), defaultValue);
279 				}
280 			}
281 			return instance;
282 		}
283 	}
284 
285 	private static final Log LOG = Log.getLog(Validator.class);
286 
287 	protected final Set<CheckInitializationListener> listeners = new LinkedHashSet<CheckInitializationListener>(2);
288 	private POJOConfigurer pojoConfigurer = new POJOConfigurer();
289 	private final XStream xStream;
290 
291 	/**
292 	 * creates an XMLConfigurer instance backed by a new XStream instance
293 	 * using the com.thoughtworks.xstream.io.xml.StaxDriver for XML parsing
294 	 * if the StAX API is available
295 	 * @see com.thoughtworks.xstream.io.xml.StaxDriver
296 	 */
297 	public XMLConfigurer()
298 	{
299 		final HierarchicalStreamDriver xmlDriver = //
300 		ReflectionUtils.isClassPresent("javax.xml.stream.XMLStreamReader") ? new StaxDriver() : //
301 				ReflectionUtils.isClassPresent("org.xmlpull.mxp1.MXParser") ? new XppDriver() : //
302 						new DomDriver();
303 		LOG.info("XML driver implementation: {1}", xmlDriver.getClass().getName());
304 		xStream = new XStream(new XStreamReflectionProvider(), xmlDriver);
305 		configureXStream();
306 	}
307 
308 	public XMLConfigurer(final File xmlConfigFile) throws IOException
309 	{
310 		this();
311 		fromXML(xmlConfigFile);
312 	}
313 
314 	public XMLConfigurer(final InputStream xmlConfigStream)
315 	{
316 		this();
317 		fromXML(xmlConfigStream);
318 	}
319 
320 	public XMLConfigurer(final Reader xmlConfigReader)
321 	{
322 		this();
323 		fromXML(xmlConfigReader);
324 	}
325 
326 	public XMLConfigurer(final String xmlConfigAsString)
327 	{
328 		this();
329 		fromXML(xmlConfigAsString);
330 	}
331 
332 	public boolean addCheckInitializationListener(final CheckInitializationListener listener)
333 	{
334 		Assert.argumentNotNull("listener", listener);
335 		return listeners.add(listener);
336 	}
337 
338 	private void configureXStream()
339 	{
340 		xStream.registerConverter(new ReflectionConverter(xStream.getMapper(), xStream.getReflectionProvider())
341 			{
342 				@Override
343 				public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context)
344 				{
345 					final Object instance = super.unmarshal(reader, context);
346 					if (instance instanceof Check) //
347 						for (final CheckInitializationListener listener : listeners)
348 							listener.onCheckInitialized((Check) instance);
349 					return instance;
350 				}
351 			}, XStream.PRIORITY_VERY_LOW);
352 		xStream.registerConverter(new ListConverter(xStream.getMapper()));
353 		xStream.registerConverter(new AssertCheckConverter());
354 
355 		xStream.omitField(AbstractCheck.class, "messageVariablesUpToDate");
356 
357 		xStream.useAttributeFor(Class.class);
358 		xStream.useAttributeFor(boolean.class);
359 		xStream.useAttributeFor(byte.class);
360 		xStream.useAttributeFor(char.class);
361 		xStream.useAttributeFor(double.class);
362 		xStream.useAttributeFor(float.class);
363 		xStream.useAttributeFor(int.class);
364 		xStream.useAttributeFor(long.class);
365 		xStream.useAttributeFor(Boolean.class);
366 		xStream.useAttributeFor(Byte.class);
367 		xStream.useAttributeFor(Character.class);
368 		xStream.useAttributeFor(Double.class);
369 		xStream.useAttributeFor(Float.class);
370 		xStream.useAttributeFor(Integer.class);
371 		xStream.useAttributeFor(Long.class);
372 		xStream.useAttributeFor(String.class);
373 
374 		xStream.alias("java-type", Class.class);
375 		xStream.alias("constraintTarget", ConstraintTarget.class);
376 
377 		// constraint check short forms
378 		xStream.alias("assert", AssertCheck.class);
379 		xStream.alias("assertConstraintSet", AssertConstraintSetCheck.class);
380 		xStream.alias("assertFalse", AssertFalseCheck.class);
381 		xStream.alias("assertFieldConstraints", AssertFieldConstraintsCheck.class);
382 		xStream.alias("assertNull", AssertNullCheck.class);
383 		xStream.alias("assertTrue", AssertTrueCheck.class);
384 		{
385 			xStream.alias("assertURL", AssertURLCheck.class);
386 			xStream.alias("permittedURIScheme", URIScheme.class);
387 			xStream.addImplicitCollection(AssertURLCheck.class, "permittedURISchemes", URIScheme.class);
388 		}
389 		xStream.alias("assertValid", AssertValidCheck.class);
390 		xStream.alias("checkWith", CheckWithCheck.class);
391 		xStream.alias("dateRange", DateRangeCheck.class);
392 		xStream.alias("digits", DigitsCheck.class);
393 		xStream.alias("email", EmailCheck.class);
394 		xStream.alias("equalToField", EqualToFieldCheck.class);
395 		xStream.alias("future", FutureCheck.class);
396 		xStream.alias("hasSubstring", HasSubstringCheck.class);
397 		xStream.alias("instanceOf", InstanceOfCheck.class);
398 		xStream.alias("instanceOfAny", InstanceOfAnyCheck.class);
399 		xStream.alias("length", LengthCheck.class);
400 		{
401 			xStream.alias("matchPattern", MatchPatternCheck.class);
402 			xStream.alias("pattern", Pattern.class);
403 			xStream.addImplicitCollection(MatchPatternCheck.class, "patterns", Pattern.class);
404 		}
405 		xStream.alias("max", MaxCheck.class);
406 		xStream.alias("maxLength", MaxLengthCheck.class);
407 		xStream.alias("maxSize", MaxSizeCheck.class);
408 		xStream.alias("memberOf", MemberOfCheck.class);
409 		xStream.alias("min", MinCheck.class);
410 		xStream.alias("minLength", MinLengthCheck.class);
411 		xStream.alias("minSize", MinSizeCheck.class);
412 		xStream.alias("noSelfReference", NoSelfReferenceCheck.class);
413 		xStream.alias("notBlank", NotBlankCheck.class);
414 		xStream.alias("notEmpty", NotEmptyCheck.class);
415 		xStream.alias("notEqual", NotEqualCheck.class);
416 		xStream.alias("notEqualToField", NotEqualToFieldCheck.class);
417 		{
418 			xStream.alias("notMatchPattern", NotMatchPatternCheck.class);
419 			xStream.addImplicitCollection(NotMatchPatternCheck.class, "patterns", Pattern.class);
420 		}
421 		xStream.alias("notMemberOf", NotMemberOfCheck.class);
422 		xStream.alias("notNegative", NotNegativeCheck.class);
423 		xStream.alias("notNull", NotNullCheck.class);
424 		xStream.alias("past", PastCheck.class);
425 		xStream.alias("range", RangeCheck.class);
426 		xStream.alias("simpleCheck", SimpleCheck.class);
427 		xStream.alias("size", SizeCheck.class);
428 		xStream.alias("validateWithMethod", ValidateWithMethodCheck.class);
429 
430 		// check exclusions short forms
431 		xStream.alias("nullable", NullableExclusion.class);
432 
433 		// <oval> -> net.sf.oval.configuration.POJOConfigurer
434 		xStream.alias("oval", POJOConfigurer.class);
435 		{
436 			// <constraintSet> -> net.sf.oval.configuration.elements.ConstraintSetConfiguration
437 			xStream.addImplicitCollection(POJOConfigurer.class, "constraintSetConfigurations", ConstraintSetConfiguration.class);
438 			xStream.alias("constraintSet", ConstraintSetConfiguration.class);
439 			xStream.addImplicitCollection(ConstraintSetConfiguration.class, "checks");
440 
441 			// <class> -> net.sf.oval.configuration.elements.ClassConfiguration
442 			xStream.addImplicitCollection(POJOConfigurer.class, "classConfigurations", ClassConfiguration.class);
443 			xStream.alias("class", ClassConfiguration.class);
444 			{
445 				// <object> -> net.sf.oval.configuration.elements.ObjectConfiguration
446 				xStream.aliasField("object", ClassConfiguration.class, "objectConfiguration");
447 				{
448 					xStream.addImplicitCollection(ObjectConfiguration.class, "checks");
449 				}
450 				// <field> -> net.sf.oval.configuration.elements.FieldConfiguration
451 				xStream.addImplicitCollection(ClassConfiguration.class, "fieldConfigurations", FieldConfiguration.class);
452 				xStream.alias("field", FieldConfiguration.class);
453 				xStream.addImplicitCollection(FieldConfiguration.class, "checks");
454 
455 				// <parameter> -> net.sf.oval.configuration.elements.ParameterConfiguration
456 				// used within ConstructorConfiguration and MethodConfiguration
457 				xStream.alias("parameter", ParameterConfiguration.class);
458 				xStream.addImplicitCollection(ParameterConfiguration.class, "checks", Check.class);
459 				xStream.addImplicitCollection(ParameterConfiguration.class, "checkExclusions", CheckExclusion.class);
460 
461 				// <constructor> -> net.sf.oval.configuration.elements.ConstructorConfiguration
462 				xStream.addImplicitCollection(ClassConfiguration.class, "constructorConfigurations", ConstructorConfiguration.class);
463 				xStream.alias("constructor", ConstructorConfiguration.class);
464 				{
465 					// <parameter> -> net.sf.oval.configuration.elements.ParameterConfiguration
466 					xStream.addImplicitCollection(ConstructorConfiguration.class, "parameterConfigurations", ParameterConfiguration.class);
467 				}
468 
469 				// <method> -> net.sf.oval.configuration.elements.MethodConfiguration
470 				xStream.addImplicitCollection(ClassConfiguration.class, "methodConfigurations", MethodConfiguration.class);
471 				xStream.alias("method", MethodConfiguration.class);
472 				{
473 					// <parameter> -> net.sf.oval.configuration.elements.ParameterConfiguration
474 					xStream.addImplicitCollection(MethodConfiguration.class, "parameterConfigurations", ParameterConfiguration.class);
475 
476 					// <returnValue> -> net.sf.oval.configuration.elements.MethodConfiguration.returnValueConfiguration
477 					// -> MethodReturnValueConfiguration
478 					xStream.aliasField("returnValue", MethodConfiguration.class, "returnValueConfiguration");
479 					xStream.addImplicitCollection(MethodReturnValueConfiguration.class, "checks", Check.class);
480 
481 					// <pre> -> net.sf.oval.configuration.elements.MethodConfiguration.preExecutionConfiguration ->
482 					// MethodPreExecutionConfiguration
483 					xStream.aliasField("preExecution", MethodConfiguration.class, "preExecutionConfiguration");
484 					xStream.addImplicitCollection(MethodPreExecutionConfiguration.class, "checks", PreCheck.class);
485 					xStream.alias("pre", PreCheck.class);
486 
487 					// <post> -> net.sf.oval.configuration.elements.MethodConfiguration.postExecutionConfiguration ->
488 					// MethodPostExecutionConfiguration
489 					xStream.aliasField("postExecution", MethodConfiguration.class, "postExecutionConfiguration");
490 					xStream.addImplicitCollection(MethodPostExecutionConfiguration.class, "checks", PostCheck.class);
491 					xStream.alias("post", PostCheck.class);
492 				}
493 			}
494 		}
495 	}
496 
497 	public void fromXML(final File input) throws IOException
498 	{
499 		final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(input));
500 		try
501 		{
502 			fromXML(bis);
503 		}
504 		finally
505 		{
506 			bis.close();
507 		}
508 	}
509 
510 	public void fromXML(final InputStream input)
511 	{
512 		pojoConfigurer = (POJOConfigurer) xStream.fromXML(input);
513 	}
514 
515 	public void fromXML(final Reader input)
516 	{
517 		pojoConfigurer = (POJOConfigurer) xStream.fromXML(input);
518 	}
519 
520 	public void fromXML(final String input)
521 	{
522 		pojoConfigurer = (POJOConfigurer) xStream.fromXML(input);
523 	}
524 
525 	/**
526 	 * {@inheritDoc}
527 	 */
528 	public ClassConfiguration getClassConfiguration(final Class< ? > clazz) throws InvalidConfigurationException
529 	{
530 		return pojoConfigurer.getClassConfiguration(clazz);
531 	}
532 
533 	/**
534 	 * {@inheritDoc}
535 	 */
536 	public ConstraintSetConfiguration getConstraintSetConfiguration(final String constraintSetId) throws InvalidConfigurationException
537 	{
538 		return pojoConfigurer.getConstraintSetConfiguration(constraintSetId);
539 	}
540 
541 	/**
542 	 * @return the pojoConfigurer
543 	 */
544 	public POJOConfigurer getPojoConfigurer()
545 	{
546 		return pojoConfigurer;
547 	}
548 
549 	/**
550 	 * @return the xStream
551 	 */
552 	public XStream getXStream()
553 	{
554 		return xStream;
555 	}
556 
557 	public boolean removeCheckInitializationListener(final CheckInitializationListener listener)
558 	{
559 		return listeners.remove(listener);
560 	}
561 
562 	/**
563 	 * @param pojoConfigurer the pojoConfigurer to set
564 	 */
565 	public void setPojoConfigurer(final POJOConfigurer pojoConfigurer)
566 	{
567 		this.pojoConfigurer = pojoConfigurer;
568 	}
569 
570 	public synchronized String toXML()
571 	{
572 		return xStream.toXML(pojoConfigurer);
573 	}
574 
575 	public synchronized void toXML(final OutputStream out)
576 	{
577 		xStream.toXML(pojoConfigurer, out);
578 	}
579 
580 	public synchronized void toXML(final Writer out)
581 	{
582 		xStream.toXML(pojoConfigurer, out);
583 	}
584 }