001: /*******************************************************************************
002: * Portions created by Sebastian Thomschke are copyright (c) 2005-2007 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: *******************************************************************************/package net.sf.oval.configuration.xml;
013:
014: import java.io.BufferedInputStream;
015: import java.io.File;
016: import java.io.FileInputStream;
017: import java.io.IOException;
018: import java.io.InputStream;
019: import java.io.OutputStream;
020: import java.io.Reader;
021: import java.io.Writer;
022: import java.util.ArrayList;
023: import java.util.List;
024:
025: import net.sf.oval.Check;
026: import net.sf.oval.configuration.Configurer;
027: import net.sf.oval.configuration.pojo.POJOConfigurer;
028: import net.sf.oval.configuration.pojo.elements.ClassConfiguration;
029: import net.sf.oval.configuration.pojo.elements.ConstraintSetConfiguration;
030: import net.sf.oval.configuration.pojo.elements.ConstructorConfiguration;
031: import net.sf.oval.configuration.pojo.elements.FieldConfiguration;
032: import net.sf.oval.configuration.pojo.elements.MethodConfiguration;
033: import net.sf.oval.configuration.pojo.elements.MethodPostExecutionConfiguration;
034: import net.sf.oval.configuration.pojo.elements.MethodPreExecutionConfiguration;
035: import net.sf.oval.configuration.pojo.elements.MethodReturnValueConfiguration;
036: import net.sf.oval.configuration.pojo.elements.ObjectConfiguration;
037: import net.sf.oval.configuration.pojo.elements.ParameterConfiguration;
038: import net.sf.oval.constraint.AssertCheck;
039: import net.sf.oval.constraint.AssertConstraintSetCheck;
040: import net.sf.oval.constraint.AssertFalseCheck;
041: import net.sf.oval.constraint.AssertFieldConstraintsCheck;
042: import net.sf.oval.constraint.AssertTrueCheck;
043: import net.sf.oval.constraint.AssertValidCheck;
044: import net.sf.oval.constraint.CheckWithCheck;
045: import net.sf.oval.constraint.FutureCheck;
046: import net.sf.oval.constraint.HasSubstringCheck;
047: import net.sf.oval.constraint.InstanceOfAnyCheck;
048: import net.sf.oval.constraint.InstanceOfCheck;
049: import net.sf.oval.constraint.LengthCheck;
050: import net.sf.oval.constraint.MatchPatternCheck;
051: import net.sf.oval.constraint.MaxCheck;
052: import net.sf.oval.constraint.MaxLengthCheck;
053: import net.sf.oval.constraint.MaxSizeCheck;
054: import net.sf.oval.constraint.MemberOfCheck;
055: import net.sf.oval.constraint.MinCheck;
056: import net.sf.oval.constraint.MinLengthCheck;
057: import net.sf.oval.constraint.MinSizeCheck;
058: import net.sf.oval.constraint.NoSelfReferenceCheck;
059: import net.sf.oval.constraint.NotBlankCheck;
060: import net.sf.oval.constraint.NotEmptyCheck;
061: import net.sf.oval.constraint.NotEqualCheck;
062: import net.sf.oval.constraint.NotMemberOfCheck;
063: import net.sf.oval.constraint.NotNegativeCheck;
064: import net.sf.oval.constraint.NotNullCheck;
065: import net.sf.oval.constraint.PastCheck;
066: import net.sf.oval.constraint.RangeCheck;
067: import net.sf.oval.constraint.SizeCheck;
068: import net.sf.oval.constraint.ValidateWithMethodCheck;
069: import net.sf.oval.exception.OValException;
070: import net.sf.oval.guard.PostCheck;
071: import net.sf.oval.guard.PreCheck;
072: import net.sf.oval.internal.util.ReflectionUtils;
073:
074: import com.thoughtworks.xstream.XStream;
075: import com.thoughtworks.xstream.converters.Converter;
076: import com.thoughtworks.xstream.converters.MarshallingContext;
077: import com.thoughtworks.xstream.converters.UnmarshallingContext;
078: import com.thoughtworks.xstream.io.HierarchicalStreamDriver;
079: import com.thoughtworks.xstream.io.HierarchicalStreamReader;
080: import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
081: import com.thoughtworks.xstream.io.xml.DomDriver;
082: import com.thoughtworks.xstream.io.xml.StaxDriver;
083: import com.thoughtworks.xstream.io.xml.XppDriver;
084:
085: /**
086: * XStream (http://xstream.codehaus.org/) based XML configuration class.
087: *
088: * @author Sebastian Thomschke
089: *
090: */
091: public class XMLConfigurer implements Configurer {
092: private final static class AssertCheckConverter implements
093: Converter {
094: public boolean canConvert(final Class clazz) {
095: return clazz.equals(AssertCheck.class);
096: }
097:
098: public void marshal(final Object value,
099: final HierarchicalStreamWriter writer,
100: final MarshallingContext context) {
101: final AssertCheck assertCheck = (AssertCheck) value;
102: writer.addAttribute("lang", assertCheck.getLang());
103: writer.addAttribute("message", assertCheck.getMessage());
104: writer
105: .addAttribute("errorCode", assertCheck
106: .getErrorCode());
107: writer.addAttribute("severity", Integer
108: .toString(assertCheck.getSeverity()));
109: writer.startNode("expr");
110: writer.setValue(assertCheck.getExpression());
111: writer.endNode();
112: final String[] profiles = assertCheck.getProfiles();
113: if (profiles != null && profiles.length > 0) {
114: writer.startNode("profiles");
115: for (final String profile : profiles) {
116: writer.startNode("string");
117: writer.setValue(profile);
118: writer.endNode();
119: }
120: writer.endNode();
121: }
122: }
123:
124: public Object unmarshal(final HierarchicalStreamReader reader,
125: final UnmarshallingContext context) {
126: final AssertCheck assertCheck = new AssertCheck();
127: assertCheck.setLang(reader.getAttribute("lang"));
128: assertCheck.setMessage(reader.getAttribute("message"));
129: assertCheck.setErrorCode(reader.getAttribute("errorCode"));
130: if (reader.getAttribute("severity") != null)
131: assertCheck.setSeverity(Integer.parseInt(reader
132: .getAttribute("severity")));
133:
134: reader.moveDown();
135: assertCheck.setExpression(reader.getValue());
136: reader.moveUp();
137: if (reader.hasMoreChildren()) {
138: reader.moveDown();
139: final List<String> profiles = new ArrayList<String>(4);
140: while (reader.hasMoreChildren()) {
141: reader.moveDown();
142: if ("string".equals(reader.getNodeName()))
143: profiles.add(reader.getValue());
144: reader.moveUp();
145: }
146: reader.moveUp();
147: assertCheck.setProfiles(profiles
148: .toArray(new String[profiles.size()]));
149: }
150: return assertCheck;
151: }
152: }
153:
154: private static final long serialVersionUID = 1L;
155:
156: private POJOConfigurer pojoConfigurer = new POJOConfigurer();
157:
158: private final XStream xStream;
159:
160: /**
161: * creates an XMLConfigurer instance backed by a new XStream instance
162: * using the com.thoughtworks.xstream.io.xml.StaxDriver for XML parsing
163: * if the StAX API is available
164: * @see com.thoughtworks.xstream.io.xml.StaxDriver
165: */
166: public XMLConfigurer() {
167: // new com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider()
168:
169: final HierarchicalStreamDriver xmlDriver = //
170: ReflectionUtils
171: .isClassPresent("javax.xml.stream.XMLStreamReader") ? new StaxDriver()
172: : //
173: ReflectionUtils
174: .isClassPresent("org.xmlpull.mxp1.MXParser") ? new XppDriver()
175: : //
176: new DomDriver();
177:
178: xStream = new XStream(xmlDriver);
179: configureXStream();
180: }
181:
182: protected final void configureXStream() {
183: xStream.registerConverter(new AssertCheckConverter());
184:
185: xStream.useAttributeFor(Class.class);
186: xStream.useAttributeFor(boolean.class);
187: xStream.useAttributeFor(byte.class);
188: xStream.useAttributeFor(char.class);
189: xStream.useAttributeFor(double.class);
190: xStream.useAttributeFor(float.class);
191: xStream.useAttributeFor(int.class);
192: xStream.useAttributeFor(long.class);
193: xStream.useAttributeFor(Boolean.class);
194: xStream.useAttributeFor(Byte.class);
195: xStream.useAttributeFor(Character.class);
196: xStream.useAttributeFor(Double.class);
197: xStream.useAttributeFor(Float.class);
198: xStream.useAttributeFor(Integer.class);
199: xStream.useAttributeFor(Long.class);
200: xStream.useAttributeFor(String.class);
201:
202: xStream.alias("java-type", Class.class);
203:
204: // constraint check short forms
205: xStream.alias("assert", AssertCheck.class);
206: xStream.alias("assertConstraintSet",
207: AssertConstraintSetCheck.class);
208: xStream.alias("assertFalse", AssertFalseCheck.class);
209: xStream.alias("assertFieldConstraints",
210: AssertFieldConstraintsCheck.class);
211: xStream.alias("assertTrue", AssertTrueCheck.class);
212: xStream.alias("assertValid", AssertValidCheck.class);
213: xStream.alias("checkWith", CheckWithCheck.class);
214: xStream.alias("future", FutureCheck.class);
215: xStream.alias("hasSubstring", HasSubstringCheck.class);
216: xStream.alias("instanceOf", InstanceOfCheck.class);
217: xStream.alias("instanceOfAny", InstanceOfAnyCheck.class);
218: xStream.alias("length", LengthCheck.class);
219: xStream.alias("matchPattern", MatchPatternCheck.class);
220: xStream.alias("max", MaxCheck.class);
221: xStream.alias("maxLength", MaxLengthCheck.class);
222: xStream.alias("maxSize", MaxSizeCheck.class);
223: xStream.alias("memberOf", MemberOfCheck.class);
224: xStream.alias("min", MinCheck.class);
225: xStream.alias("minLength", MinLengthCheck.class);
226: xStream.alias("minSize", MinSizeCheck.class);
227: xStream.alias("noSelfReference", NoSelfReferenceCheck.class);
228: xStream.alias("notBlank", NotBlankCheck.class);
229: xStream.alias("notEmpty", NotEmptyCheck.class);
230: xStream.alias("notEqual", NotEqualCheck.class);
231: xStream.alias("notMemberOf", NotMemberOfCheck.class);
232: xStream.alias("notNegative", NotNegativeCheck.class);
233: xStream.alias("notNull", NotNullCheck.class);
234: xStream.alias("past", PastCheck.class);
235: xStream.alias("range", RangeCheck.class);
236: xStream.alias("size", SizeCheck.class);
237: xStream.alias("validateWithMethod",
238: ValidateWithMethodCheck.class);
239:
240: // <oval> -> net.sf.oval.configuration.POJOConfigurer
241: xStream.alias("oval", POJOConfigurer.class);
242: {
243: // <constraintSet> -> net.sf.oval.configuration.elements.ConstraintSetConfiguration
244: xStream.addImplicitCollection(POJOConfigurer.class,
245: "constraintSetConfigurations",
246: ConstraintSetConfiguration.class);
247: xStream.alias("constraintSet",
248: ConstraintSetConfiguration.class);
249: xStream.addImplicitCollection(
250: ConstraintSetConfiguration.class, "checks");
251:
252: // <class> -> net.sf.oval.configuration.elements.ClassConfiguration
253: xStream.addImplicitCollection(POJOConfigurer.class,
254: "classConfigurations", ClassConfiguration.class);
255: xStream.alias("class", ClassConfiguration.class);
256: {
257: xStream.alias("object", ObjectConfiguration.class);
258:
259: // <field> -> net.sf.oval.configuration.elements.FieldConfiguration
260: xStream
261: .addImplicitCollection(
262: ClassConfiguration.class,
263: "fieldConfigurations",
264: FieldConfiguration.class);
265: xStream.alias("field", FieldConfiguration.class);
266: xStream.addImplicitCollection(FieldConfiguration.class,
267: "checks");
268:
269: // <parameter> -> net.sf.oval.configuration.elements.ParameterConfiguration
270: // used within ConstructorConfiguration and MethodConfiguration
271: xStream
272: .alias("parameter",
273: ParameterConfiguration.class);
274: xStream.addImplicitCollection(
275: ParameterConfiguration.class, "checks",
276: Check.class);
277:
278: // <constructor> -> net.sf.oval.configuration.elements.ConstructorConfiguration
279: xStream.addImplicitCollection(ClassConfiguration.class,
280: "constructorConfigurations",
281: ConstructorConfiguration.class);
282: xStream.alias("constructor",
283: ConstructorConfiguration.class);
284: {
285: // <parameter> -> net.sf.oval.configuration.elements.ParameterConfiguration
286: xStream.addImplicitCollection(
287: ConstructorConfiguration.class,
288: "parameterConfigurations",
289: ParameterConfiguration.class);
290: }
291:
292: // <method> -> net.sf.oval.configuration.elements.MethodConfiguration
293: xStream.addImplicitCollection(ClassConfiguration.class,
294: "methodConfigurations",
295: MethodConfiguration.class);
296: xStream.alias("method", MethodConfiguration.class);
297: {
298: // <parameter> -> net.sf.oval.configuration.elements.ParameterConfiguration
299: xStream.addImplicitCollection(
300: MethodConfiguration.class,
301: "parameterConfigurations",
302: ParameterConfiguration.class);
303:
304: // <returnValue> -> net.sf.oval.configuration.elements.MethodConfiguration.returnValueConfiguration
305: // -> MethodReturnValueConfiguration
306: xStream.aliasField("returnValue",
307: MethodConfiguration.class,
308: "returnValueConfiguration");
309: xStream.addImplicitCollection(
310: MethodReturnValueConfiguration.class,
311: "checks", Check.class);
312:
313: // <pre> -> net.sf.oval.configuration.elements.MethodConfiguration.preExecutionConfiguration ->
314: // MethodPreExecutionConfiguration
315: xStream.aliasField("pre",
316: MethodConfiguration.class,
317: "preExecutionConfiguration");
318: xStream.addImplicitCollection(
319: MethodPostExecutionConfiguration.class,
320: "checks", PreCheck.class);
321: xStream.alias("preCheck", PreCheck.class);
322:
323: // <post> -> net.sf.oval.configuration.elements.MethodConfiguration.postExecutionConfiguration ->
324: // MethodPpstExecutionConfiguration
325: xStream.aliasField("post",
326: MethodConfiguration.class,
327: "postExecutionConfiguration");
328: xStream.addImplicitCollection(
329: MethodPreExecutionConfiguration.class,
330: "checks", PostCheck.class);
331: xStream.alias("postCheck", PostCheck.class);
332: }
333: }
334: }
335: }
336:
337: public synchronized void fromXML(final File input)
338: throws IOException {
339: final BufferedInputStream bis = new BufferedInputStream(
340: new FileInputStream(input));
341: try {
342: fromXML(bis);
343: } finally {
344: bis.close();
345: }
346: }
347:
348: public synchronized void fromXML(final InputStream input) {
349: pojoConfigurer = (POJOConfigurer) xStream.fromXML(input);
350: }
351:
352: public synchronized void fromXML(final Reader input) {
353: pojoConfigurer = (POJOConfigurer) xStream.fromXML(input);
354: }
355:
356: public synchronized void fromXML(final String input) {
357: pojoConfigurer = (POJOConfigurer) xStream.fromXML(input);
358: }
359:
360: public ClassConfiguration getClassConfiguration(final Class<?> clazz)
361: throws OValException {
362: return pojoConfigurer.getClassConfiguration(clazz);
363: }
364:
365: public ConstraintSetConfiguration getConstraintSetConfiguration(
366: final String constraintSetId) throws OValException {
367: return pojoConfigurer
368: .getConstraintSetConfiguration(constraintSetId);
369: }
370:
371: /**
372: * @return the pojoConfigurer
373: */
374: public POJOConfigurer getPojoConfigurer() {
375: return pojoConfigurer;
376: }
377:
378: /**
379: * @return the xStream
380: */
381: public XStream getXStream() {
382: return xStream;
383: }
384:
385: /**
386: * @param pojoConfigurer the pojoConfigurer to set
387: */
388: public void setPojoConfigurer(final POJOConfigurer pojoConfigurer) {
389: this .pojoConfigurer = pojoConfigurer;
390: }
391:
392: public synchronized String toXML() {
393: return xStream.toXML(pojoConfigurer);
394: }
395:
396: public synchronized void toXML(final OutputStream out) {
397: xStream.toXML(pojoConfigurer, out);
398: }
399:
400: public synchronized void toXML(final Writer out) {
401: xStream.toXML(pojoConfigurer, out);
402: }
403: }
|