001    /*******************************************************************************
002     * Portions created by Sebastian Thomschke are copyright (c) 2005-2011 Sebastian
003     * Thomschke.
004     * 
005     * All Rights Reserved. This program and the accompanying materials
006     * are made available under the terms of the Eclipse Public License v1.0
007     * which accompanies this distribution, and is available at
008     * http://www.eclipse.org/legal/epl-v10.html
009     * 
010     * Contributors:
011     *     Sebastian Thomschke - initial implementation.
012     *******************************************************************************/
013    package net.sf.oval.configuration.xml;
014    
015    import java.io.BufferedInputStream;
016    import java.io.File;
017    import java.io.FileInputStream;
018    import java.io.IOException;
019    import java.io.InputStream;
020    import java.io.OutputStream;
021    import java.io.Reader;
022    import java.io.Writer;
023    import java.lang.annotation.Annotation;
024    import java.lang.reflect.Method;
025    import java.lang.reflect.ParameterizedType;
026    import java.lang.reflect.Type;
027    import java.util.ArrayList;
028    import java.util.List;
029    import java.util.Set;
030    import java.util.regex.Pattern;
031    
032    import net.sf.oval.AbstractCheck;
033    import net.sf.oval.Check;
034    import net.sf.oval.CheckExclusion;
035    import net.sf.oval.ConstraintTarget;
036    import net.sf.oval.Validator;
037    import net.sf.oval.configuration.CheckInitializationListener;
038    import net.sf.oval.configuration.Configurer;
039    import net.sf.oval.configuration.annotation.AbstractAnnotationCheck;
040    import net.sf.oval.configuration.annotation.Constraint;
041    import net.sf.oval.configuration.pojo.POJOConfigurer;
042    import net.sf.oval.configuration.pojo.elements.ClassConfiguration;
043    import net.sf.oval.configuration.pojo.elements.ConstraintSetConfiguration;
044    import net.sf.oval.configuration.pojo.elements.ConstructorConfiguration;
045    import net.sf.oval.configuration.pojo.elements.FieldConfiguration;
046    import net.sf.oval.configuration.pojo.elements.MethodConfiguration;
047    import net.sf.oval.configuration.pojo.elements.MethodPostExecutionConfiguration;
048    import net.sf.oval.configuration.pojo.elements.MethodPreExecutionConfiguration;
049    import net.sf.oval.configuration.pojo.elements.MethodReturnValueConfiguration;
050    import net.sf.oval.configuration.pojo.elements.ObjectConfiguration;
051    import net.sf.oval.configuration.pojo.elements.ParameterConfiguration;
052    import net.sf.oval.constraint.AssertCheck;
053    import net.sf.oval.constraint.AssertConstraintSetCheck;
054    import net.sf.oval.constraint.AssertFalseCheck;
055    import net.sf.oval.constraint.AssertFieldConstraintsCheck;
056    import net.sf.oval.constraint.AssertNullCheck;
057    import net.sf.oval.constraint.AssertTrueCheck;
058    import net.sf.oval.constraint.AssertURLCheck;
059    import net.sf.oval.constraint.AssertURLCheck.URIScheme;
060    import net.sf.oval.constraint.AssertValidCheck;
061    import net.sf.oval.constraint.CheckWithCheck;
062    import net.sf.oval.constraint.CheckWithCheck.SimpleCheck;
063    import net.sf.oval.constraint.DateRangeCheck;
064    import net.sf.oval.constraint.DigitsCheck;
065    import net.sf.oval.constraint.EmailCheck;
066    import net.sf.oval.constraint.EqualToFieldCheck;
067    import net.sf.oval.constraint.FutureCheck;
068    import net.sf.oval.constraint.HasSubstringCheck;
069    import net.sf.oval.constraint.InstanceOfAnyCheck;
070    import net.sf.oval.constraint.InstanceOfCheck;
071    import net.sf.oval.constraint.LengthCheck;
072    import net.sf.oval.constraint.MatchPatternCheck;
073    import net.sf.oval.constraint.MaxCheck;
074    import net.sf.oval.constraint.MaxLengthCheck;
075    import net.sf.oval.constraint.MaxSizeCheck;
076    import net.sf.oval.constraint.MemberOfCheck;
077    import net.sf.oval.constraint.MinCheck;
078    import net.sf.oval.constraint.MinLengthCheck;
079    import net.sf.oval.constraint.MinSizeCheck;
080    import net.sf.oval.constraint.NoSelfReferenceCheck;
081    import net.sf.oval.constraint.NotBlankCheck;
082    import net.sf.oval.constraint.NotEmptyCheck;
083    import net.sf.oval.constraint.NotEqualCheck;
084    import net.sf.oval.constraint.NotEqualToFieldCheck;
085    import net.sf.oval.constraint.NotMatchPatternCheck;
086    import net.sf.oval.constraint.NotMemberOfCheck;
087    import net.sf.oval.constraint.NotNegativeCheck;
088    import net.sf.oval.constraint.NotNullCheck;
089    import net.sf.oval.constraint.PastCheck;
090    import net.sf.oval.constraint.RangeCheck;
091    import net.sf.oval.constraint.SizeCheck;
092    import net.sf.oval.constraint.ValidateWithMethodCheck;
093    import net.sf.oval.constraint.exclusion.NullableExclusion;
094    import net.sf.oval.exception.InvalidConfigurationException;
095    import net.sf.oval.guard.PostCheck;
096    import net.sf.oval.guard.PreCheck;
097    import net.sf.oval.internal.Log;
098    import net.sf.oval.internal.util.Assert;
099    import net.sf.oval.internal.util.LinkedSet;
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)
191                                    assertCheck.setSeverity(Integer.parseInt(reader.getAttribute("severity")));
192                            assertCheck.setTarget(reader.getAttribute("target"));
193                            assertCheck.setWhen(reader.getAttribute("when"));
194    
195                            reader.moveDown();
196                            assertCheck.setExpr(reader.getValue());
197                            reader.moveUp();
198                            if (reader.hasMoreChildren())
199                            {
200                                    reader.moveDown();
201                                    if ("appliesTo".equals(reader.getNodeName()))
202                                    {
203                                            final List<ConstraintTarget> targets = new ArrayList<ConstraintTarget>(2);
204                                            while (reader.hasMoreChildren())
205                                            {
206                                                    reader.moveDown();
207                                                    if ("constraintTarget".equals(reader.getNodeName()))
208                                                            targets.add(ConstraintTarget.valueOf(reader.getValue()));
209                                                    reader.moveUp();
210                                            }
211                                            assertCheck.setAppliesTo(targets.toArray(new ConstraintTarget[targets.size()]));
212                                    }
213                                    else if ("profiles".equals(reader.getNodeName()))
214                                    {
215                                            final List<String> profiles = new ArrayList<String>(4);
216                                            while (reader.hasMoreChildren())
217                                            {
218                                                    reader.moveDown();
219                                                    if ("string".equals(reader.getNodeName())) profiles.add(reader.getValue());
220                                                    reader.moveUp();
221                                            }
222                                            assertCheck.setProfiles(profiles.toArray(new String[profiles.size()]));
223                                    }
224                                    reader.moveUp();
225                            }
226                            for (final CheckInitializationListener listener : listeners)
227                                    listener.onCheckInitialized(assertCheck);
228                            return assertCheck;
229                    }
230            }
231    
232            private static final class ListConverter extends CollectionConverter
233            {
234                    protected ListConverter(final Mapper mapper)
235                    {
236                            super(mapper);
237                    }
238    
239                    /**
240                     * {@inheritDoc}
241                     */
242                    @Override
243                    public boolean canConvert(@SuppressWarnings("rawtypes") final Class type)
244                    {
245                            return List.class.isAssignableFrom(type);
246                    }
247            }
248    
249            /**
250             * This reflection provider applies default values declared on constraint annotations to the corresponding check class
251             */
252            protected static final class XStreamReflectionProvider extends Sun14ReflectionProvider
253            {
254                    @SuppressWarnings("unchecked")
255                    @Override
256                    public Object newInstance(@SuppressWarnings("rawtypes") final Class type)
257                    {
258                            final Object instance = super.newInstance(type);
259    
260                            // test if a AnnotationCheck instance is requested 
261                            if (instance instanceof AbstractAnnotationCheck)
262                            {
263                                    // determine the constraint annotation
264                                    Class<Annotation> constraintAnnotation = null;
265                                    final ParameterizedType genericSuperclass = (ParameterizedType) type.getGenericSuperclass();
266                                    for (final Type genericType : genericSuperclass.getActualTypeArguments())
267                                    {
268                                            final Class< ? > genericClass = (Class< ? >) genericType;
269                                            if (genericClass.isAnnotation() && genericClass.isAnnotationPresent(Constraint.class))
270                                            {
271                                                    constraintAnnotation = (Class<Annotation>) genericClass;
272                                                    break;
273                                            }
274                                    }
275                                    // in case we could determine the constraint annotation, read the attributes and 
276                                    // apply the declared default values to the check instance
277                                    if (constraintAnnotation != null) for (final Method m : constraintAnnotation.getMethods())
278                                    {
279                                            final Object defaultValue = m.getDefaultValue();
280                                            if (defaultValue != null) ReflectionUtils.setViaSetter(instance, m.getName(), defaultValue);
281                                    }
282                            }
283                            return instance;
284                    }
285            }
286    
287            private static final Log LOG = Log.getLog(Validator.class);
288    
289            protected final Set<CheckInitializationListener> listeners = new LinkedSet<CheckInitializationListener>(2);
290            private POJOConfigurer pojoConfigurer = new POJOConfigurer();
291            private final XStream xStream;
292    
293            /**
294             * creates an XMLConfigurer instance backed by a new XStream instance 
295             * using the com.thoughtworks.xstream.io.xml.StaxDriver for XML parsing 
296             * if the StAX API is available
297             * @see com.thoughtworks.xstream.io.xml.StaxDriver
298             */
299            public XMLConfigurer()
300            {
301                    final HierarchicalStreamDriver xmlDriver = //
302                    ReflectionUtils.isClassPresent("javax.xml.stream.XMLStreamReader") ? new StaxDriver() : //
303                                    ReflectionUtils.isClassPresent("org.xmlpull.mxp1.MXParser") ? new XppDriver() : //
304                                                    new DomDriver();
305                    LOG.info("XML driver implementation: {1}", xmlDriver.getClass().getName());
306                    xStream = new XStream(new XStreamReflectionProvider(), xmlDriver);
307                    configureXStream();
308            }
309    
310            public XMLConfigurer(final File xmlConfigFile) throws IOException
311            {
312                    this();
313                    fromXML(xmlConfigFile);
314            }
315    
316            public XMLConfigurer(final InputStream xmlConfigStream)
317            {
318                    this();
319                    fromXML(xmlConfigStream);
320            }
321    
322            public XMLConfigurer(final Reader xmlConfigReader)
323            {
324                    this();
325                    fromXML(xmlConfigReader);
326            }
327    
328            public XMLConfigurer(final String xmlConfigAsString)
329            {
330                    this();
331                    fromXML(xmlConfigAsString);
332            }
333    
334            public boolean addCheckInitializationListener(final CheckInitializationListener listener)
335            {
336                    Assert.argumentNotNull("listener", listener);
337                    return listeners.add(listener);
338            }
339    
340            private void configureXStream()
341            {
342                    xStream.registerConverter(new ReflectionConverter(xStream.getMapper(), xStream.getReflectionProvider())
343                            {
344                                    @Override
345                                    public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context)
346                                    {
347                                            final Object instance = super.unmarshal(reader, context);
348                                            if (instance instanceof Check) //
349                                                    for (final CheckInitializationListener listener : listeners)
350                                                            listener.onCheckInitialized((Check) instance);
351                                            return instance;
352                                    }
353                            }, XStream.PRIORITY_VERY_LOW);
354                    xStream.registerConverter(new ListConverter(xStream.getMapper()));
355                    xStream.registerConverter(new AssertCheckConverter());
356    
357                    xStream.omitField(AbstractCheck.class, "messageVariablesUpToDate");
358    
359                    xStream.useAttributeFor(Class.class);
360                    xStream.useAttributeFor(boolean.class);
361                    xStream.useAttributeFor(byte.class);
362                    xStream.useAttributeFor(char.class);
363                    xStream.useAttributeFor(double.class);
364                    xStream.useAttributeFor(float.class);
365                    xStream.useAttributeFor(int.class);
366                    xStream.useAttributeFor(long.class);
367                    xStream.useAttributeFor(Boolean.class);
368                    xStream.useAttributeFor(Byte.class);
369                    xStream.useAttributeFor(Character.class);
370                    xStream.useAttributeFor(Double.class);
371                    xStream.useAttributeFor(Float.class);
372                    xStream.useAttributeFor(Integer.class);
373                    xStream.useAttributeFor(Long.class);
374                    xStream.useAttributeFor(String.class);
375    
376                    xStream.alias("java-type", Class.class);
377                    xStream.alias("constraintTarget", ConstraintTarget.class);
378    
379                    // constraint check short forms
380                    xStream.alias("assert", AssertCheck.class);
381                    xStream.alias("assertConstraintSet", AssertConstraintSetCheck.class);
382                    xStream.alias("assertFalse", AssertFalseCheck.class);
383                    xStream.alias("assertFieldConstraints", AssertFieldConstraintsCheck.class);
384                    xStream.alias("assertNull", AssertNullCheck.class);
385                    xStream.alias("assertTrue", AssertTrueCheck.class);
386                    {
387                            xStream.alias("assertURL", AssertURLCheck.class);
388                            xStream.alias("permittedURIScheme", URIScheme.class);
389                            xStream.addImplicitCollection(AssertURLCheck.class, "permittedURISchemes", URIScheme.class);
390                    }
391                    xStream.alias("assertValid", AssertValidCheck.class);
392                    xStream.alias("checkWith", CheckWithCheck.class);
393                    xStream.alias("dateRange", DateRangeCheck.class);
394                    xStream.alias("digits", DigitsCheck.class);
395                    xStream.alias("email", EmailCheck.class);
396                    xStream.alias("equalToField", EqualToFieldCheck.class);
397                    xStream.alias("future", FutureCheck.class);
398                    xStream.alias("hasSubstring", HasSubstringCheck.class);
399                    xStream.alias("instanceOf", InstanceOfCheck.class);
400                    xStream.alias("instanceOfAny", InstanceOfAnyCheck.class);
401                    xStream.alias("length", LengthCheck.class);
402                    {
403                            xStream.alias("matchPattern", MatchPatternCheck.class);
404                            xStream.alias("pattern", Pattern.class);
405                            xStream.addImplicitCollection(MatchPatternCheck.class, "patterns", Pattern.class);
406                    }
407                    xStream.alias("max", MaxCheck.class);
408                    xStream.alias("maxLength", MaxLengthCheck.class);
409                    xStream.alias("maxSize", MaxSizeCheck.class);
410                    xStream.alias("memberOf", MemberOfCheck.class);
411                    xStream.alias("min", MinCheck.class);
412                    xStream.alias("minLength", MinLengthCheck.class);
413                    xStream.alias("minSize", MinSizeCheck.class);
414                    xStream.alias("noSelfReference", NoSelfReferenceCheck.class);
415                    xStream.alias("notBlank", NotBlankCheck.class);
416                    xStream.alias("notEmpty", NotEmptyCheck.class);
417                    xStream.alias("notEqual", NotEqualCheck.class);
418                    xStream.alias("notEqualToField", NotEqualToFieldCheck.class);
419                    {
420                            xStream.alias("notMatchPattern", NotMatchPatternCheck.class);
421                            xStream.addImplicitCollection(NotMatchPatternCheck.class, "patterns", Pattern.class);
422                    }
423                    xStream.alias("notMemberOf", NotMemberOfCheck.class);
424                    xStream.alias("notNegative", NotNegativeCheck.class);
425                    xStream.alias("notNull", NotNullCheck.class);
426                    xStream.alias("past", PastCheck.class);
427                    xStream.alias("range", RangeCheck.class);
428                    xStream.alias("simpleCheck", SimpleCheck.class);
429                    xStream.alias("size", SizeCheck.class);
430                    xStream.alias("validateWithMethod", ValidateWithMethodCheck.class);
431    
432                    // check exclusions short forms
433                    xStream.alias("nullable", NullableExclusion.class);
434    
435                    // <oval> -> net.sf.oval.configuration.POJOConfigurer
436                    xStream.alias("oval", POJOConfigurer.class);
437                    {
438                            // <constraintSet> -> net.sf.oval.configuration.elements.ConstraintSetConfiguration
439                            xStream.addImplicitCollection(POJOConfigurer.class, "constraintSetConfigurations",
440                                            ConstraintSetConfiguration.class);
441                            xStream.alias("constraintSet", ConstraintSetConfiguration.class);
442                            xStream.addImplicitCollection(ConstraintSetConfiguration.class, "checks");
443    
444                            // <class> -> net.sf.oval.configuration.elements.ClassConfiguration
445                            xStream.addImplicitCollection(POJOConfigurer.class, "classConfigurations", ClassConfiguration.class);
446                            xStream.alias("class", ClassConfiguration.class);
447                            {
448                                    // <object> -> net.sf.oval.configuration.elements.ObjectConfiguration
449                                    xStream.aliasField("object", ClassConfiguration.class, "objectConfiguration");
450                                    {
451                                            xStream.addImplicitCollection(ObjectConfiguration.class, "checks");
452                                    }
453                                    // <field> -> net.sf.oval.configuration.elements.FieldConfiguration
454                                    xStream.addImplicitCollection(ClassConfiguration.class, "fieldConfigurations", FieldConfiguration.class);
455                                    xStream.alias("field", FieldConfiguration.class);
456                                    xStream.addImplicitCollection(FieldConfiguration.class, "checks");
457    
458                                    // <parameter> -> net.sf.oval.configuration.elements.ParameterConfiguration
459                                    // used within ConstructorConfiguration and MethodConfiguration
460                                    xStream.alias("parameter", ParameterConfiguration.class);
461                                    xStream.addImplicitCollection(ParameterConfiguration.class, "checks", Check.class);
462                                    xStream.addImplicitCollection(ParameterConfiguration.class, "checkExclusions", CheckExclusion.class);
463    
464                                    // <constructor> -> net.sf.oval.configuration.elements.ConstructorConfiguration
465                                    xStream.addImplicitCollection(ClassConfiguration.class, "constructorConfigurations",
466                                                    ConstructorConfiguration.class);
467                                    xStream.alias("constructor", ConstructorConfiguration.class);
468                                    {
469                                            // <parameter> -> net.sf.oval.configuration.elements.ParameterConfiguration
470                                            xStream.addImplicitCollection(ConstructorConfiguration.class, "parameterConfigurations",
471                                                            ParameterConfiguration.class);
472                                    }
473    
474                                    // <method> -> net.sf.oval.configuration.elements.MethodConfiguration
475                                    xStream.addImplicitCollection(ClassConfiguration.class, "methodConfigurations",
476                                                    MethodConfiguration.class);
477                                    xStream.alias("method", MethodConfiguration.class);
478                                    {
479                                            // <parameter> -> net.sf.oval.configuration.elements.ParameterConfiguration
480                                            xStream.addImplicitCollection(MethodConfiguration.class, "parameterConfigurations",
481                                                            ParameterConfiguration.class);
482    
483                                            // <returnValue> -> net.sf.oval.configuration.elements.MethodConfiguration.returnValueConfiguration
484                                            // -> MethodReturnValueConfiguration
485                                            xStream.aliasField("returnValue", MethodConfiguration.class, "returnValueConfiguration");
486                                            xStream.addImplicitCollection(MethodReturnValueConfiguration.class, "checks", Check.class);
487    
488                                            // <pre> -> net.sf.oval.configuration.elements.MethodConfiguration.preExecutionConfiguration ->
489                                            // MethodPreExecutionConfiguration
490                                            xStream.aliasField("preExecution", MethodConfiguration.class, "preExecutionConfiguration");
491                                            xStream.addImplicitCollection(MethodPreExecutionConfiguration.class, "checks", PreCheck.class);
492                                            xStream.alias("pre", PreCheck.class);
493    
494                                            // <post> -> net.sf.oval.configuration.elements.MethodConfiguration.postExecutionConfiguration ->
495                                            // MethodPostExecutionConfiguration
496                                            xStream.aliasField("postExecution", MethodConfiguration.class, "postExecutionConfiguration");
497                                            xStream.addImplicitCollection(MethodPostExecutionConfiguration.class, "checks", PostCheck.class);
498                                            xStream.alias("post", PostCheck.class);
499                                    }
500                            }
501                    }
502            }
503    
504            public void fromXML(final File input) throws IOException
505            {
506                    final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(input));
507                    try
508                    {
509                            fromXML(bis);
510                    }
511                    finally
512                    {
513                            bis.close();
514                    }
515            }
516    
517            public void fromXML(final InputStream input)
518            {
519                    pojoConfigurer = (POJOConfigurer) xStream.fromXML(input);
520            }
521    
522            public void fromXML(final Reader input)
523            {
524                    pojoConfigurer = (POJOConfigurer) xStream.fromXML(input);
525            }
526    
527            public void fromXML(final String input)
528            {
529                    pojoConfigurer = (POJOConfigurer) xStream.fromXML(input);
530            }
531    
532            /**
533             * {@inheritDoc}
534             */
535            public ClassConfiguration getClassConfiguration(final Class< ? > clazz) throws InvalidConfigurationException
536            {
537                    return pojoConfigurer.getClassConfiguration(clazz);
538            }
539    
540            /**
541             * {@inheritDoc}
542             */
543            public ConstraintSetConfiguration getConstraintSetConfiguration(final String constraintSetId)
544                            throws InvalidConfigurationException
545            {
546                    return pojoConfigurer.getConstraintSetConfiguration(constraintSetId);
547            }
548    
549            /**
550             * @return the pojoConfigurer
551             */
552            public POJOConfigurer getPojoConfigurer()
553            {
554                    return pojoConfigurer;
555            }
556    
557            /**
558             * @return the xStream
559             */
560            public XStream getXStream()
561            {
562                    return xStream;
563            }
564    
565            public boolean removeCheckInitializationListener(final CheckInitializationListener listener)
566            {
567                    return listeners.remove(listener);
568            }
569    
570            /**
571             * @param pojoConfigurer the pojoConfigurer to set
572             */
573            public void setPojoConfigurer(final POJOConfigurer pojoConfigurer)
574            {
575                    this.pojoConfigurer = pojoConfigurer;
576            }
577    
578            public synchronized String toXML()
579            {
580                    return xStream.toXML(pojoConfigurer);
581            }
582    
583            public synchronized void toXML(final OutputStream out)
584            {
585                    xStream.toXML(pojoConfigurer, out);
586            }
587    
588            public synchronized void toXML(final Writer out)
589            {
590                    xStream.toXML(pojoConfigurer, out);
591            }
592    }