|
1
|
|
/*
|
|
2
|
|
* JBind
|
|
3
|
|
*
|
|
4
|
|
* Copyright (c) by Stefan Wachter. All rights reserved.
|
|
5
|
|
*
|
|
6
|
|
* Usage, modification, and redistribution is subject to license terms that are
|
|
7
|
|
* available at 'http://www.jbind.org'. The JBind license is like the
|
|
8
|
|
* 'Apache Software License V 1.1'.
|
|
9
|
|
*/
|
|
10
|
|
package org.jbind.xml.facade;
|
|
11
|
|
|
|
12
|
|
import java.io.IOException;
|
|
13
|
|
import java.io.OutputStream;
|
|
14
|
|
import java.io.OutputStreamWriter;
|
|
15
|
|
import java.io.StringWriter;
|
|
16
|
|
import java.io.UnsupportedEncodingException;
|
|
17
|
|
import java.io.Writer;
|
|
18
|
|
import java.net.URL;
|
|
19
|
|
import java.util.ArrayList;
|
|
20
|
|
import java.util.Iterator;
|
|
21
|
|
import java.util.List;
|
|
22
|
|
import java.util.Map;
|
|
23
|
|
|
|
24
|
|
import javax.xml.transform.sax.SAXSource;
|
|
25
|
|
|
|
26
|
|
import org.jbind.base.UnexpectedException;
|
|
27
|
|
import org.jbind.xml.Config;
|
|
28
|
|
import org.jbind.xml.code.IApplicationCode;
|
|
29
|
|
import org.jbind.xml.code.IConfigurationCode;
|
|
30
|
|
import org.jbind.xml.core.bridge.EqualsVisitor;
|
|
31
|
|
import org.jbind.xml.core.bridge.IDataImpl;
|
|
32
|
|
import org.jbind.xml.core.bridge.IDocumentImpl;
|
|
33
|
|
import org.jbind.xml.core.bridge.IElementImpl;
|
|
34
|
|
import org.jbind.xml.core.bridge.ImplReader;
|
|
35
|
|
import org.jbind.xml.core.bridge.MarshalVisitor;
|
|
36
|
|
import org.jbind.xml.core.bridge.SaxVisitor;
|
|
37
|
|
import org.jbind.xml.core.cmp.ISchema;
|
|
38
|
|
import org.jbind.xml.core.data.IAnyTypeData;
|
|
39
|
|
import org.jbind.xml.core.data.IDataContext;
|
|
40
|
|
import org.jbind.xml.instance.builder.DataBuilder;
|
|
41
|
|
import org.jbind.xml.instance.builder.IImplBuilder;
|
|
42
|
|
import org.jbind.xml.instance.builder.ImplBuilder;
|
|
43
|
|
import org.jbind.xml.instance.builder.ValidationVisitor;
|
|
44
|
|
import org.jbind.xml.msg.IConstraintViolations;
|
|
45
|
|
import org.jbind.xml.msg.XmlException;
|
|
46
|
|
import org.jbind.xml.msg.XmlMessages;
|
|
47
|
|
import org.jbind.xml.schema.element.SchemaParser;
|
|
48
|
|
import org.jbind.xml.schema.instantiation.ISchemaParser;
|
|
49
|
|
import org.jbind.xml.schema.instantiation.ISchemaReader;
|
|
50
|
|
import org.jbind.xml.schema.reader.Instantiator;
|
|
51
|
|
import org.xml.sax.ContentHandler;
|
|
52
|
|
import org.xml.sax.InputSource;
|
|
53
|
|
import org.xml.sax.XMLReader;
|
|
54
|
|
|
|
55
|
|
/**
|
|
56
|
|
* Facade of the JBind framework that provides easy access to its core functionalities.
|
|
57
|
|
*/
|
|
58
|
|
public class JBindFacade {
|
|
59
|
|
|
|
60
|
|
/**
|
|
61
|
|
* Default encoding ({@value}).
|
|
62
|
|
*/
|
|
63
|
|
public static final String DEFAULT_ENCODING = "UTF-8";
|
|
64
|
|
|
|
65
|
|
/**
|
|
66
|
|
* Creates a schema reader.
|
|
67
|
|
*
|
|
68
|
|
* @return <i>(required)</i>.
|
|
69
|
|
*/
|
|
70
|
175
|
public static ISchemaReader createSchemaReader() {
|
|
71
|
|
// ISchemaParser parser = new SaxSchemaParser(ourEntityResolver, ourXPathFactory, ourRegExFactory);
|
|
72
|
175
|
ISchemaParser parser = new SchemaParser(Config.instance.getEntityResolver(), Config.instance.getXPathFactory(), Config.instance.getRegExFactory());
|
|
73
|
175
|
ISchemaReader reader = new Instantiator(parser, Config.instance.getDataImplFactory());
|
|
74
|
175
|
return reader;
|
|
75
|
|
}
|
|
76
|
|
|
|
77
|
|
/**
|
|
78
|
|
* Reads a schema.
|
|
79
|
|
* <p>
|
|
80
|
|
* The schema will use generated classes and their package must
|
|
81
|
|
* be configured in the schema itself or by the {@link org.jbind.xml.Config Config}
|
|
82
|
|
* class.
|
|
83
|
|
*
|
|
84
|
|
* @param aUrl <i>(required)</i>.
|
|
85
|
|
* @return <i>(required)</i>.
|
|
86
|
|
*/
|
|
87
|
0
|
public static ISchema readSchema(URL aUrl) throws XmlException {
|
|
88
|
0
|
return createSchemaReader().readSchema(aUrl, false, null);
|
|
89
|
|
}
|
|
90
|
|
|
|
91
|
|
/**
|
|
92
|
|
* Creates a data builder.
|
|
93
|
|
*
|
|
94
|
|
* @param aContext <i>(optional)</i>.
|
|
95
|
|
* @return <i>(required)</i>.
|
|
96
|
|
*/
|
|
97
|
222
|
public static IImplBuilder createImplBuilder(IDataContext aContext) {
|
|
98
|
222
|
return createImplBuilder(aContext, false);
|
|
99
|
|
}
|
|
100
|
|
|
|
101
|
222
|
public static IImplBuilder createImplBuilder(IDataContext aContext, boolean aUseBuiltInClassesOnly) {
|
|
102
|
222
|
DataBuilder datBuilder = new DataBuilder(aUseBuiltInClassesOnly);
|
|
103
|
222
|
ValidationVisitor dataValidator = new ValidationVisitor(false);
|
|
104
|
222
|
return new ImplBuilder(Config.instance.getEntityResolver(), Config.instance.getDataImplFactory(), datBuilder, dataValidator, aContext);
|
|
105
|
|
// return new SaxImplBuilder(ourEntityResolver, ourDataFactory, datBuilder, dataValidator, aContext);
|
|
106
|
|
}
|
|
107
|
|
|
|
108
|
|
/**
|
|
109
|
|
* Validates a data object.
|
|
110
|
|
*
|
|
111
|
|
* @param aData <i>(required)</i>.
|
|
112
|
|
* @param aContext <i>(optional)</i>.
|
|
113
|
|
* @throws XmlException Raised iff the data object is not valid.
|
|
114
|
|
*/
|
|
115
|
0
|
public static void validateData(IAnyTypeData aData, IDataContext aContext) throws XmlException {
|
|
116
|
0
|
ValidationVisitor dataValidator = new ValidationVisitor(true);
|
|
117
|
0
|
IConstraintViolations violations = XmlMessages.constraintViolations();
|
|
118
|
0
|
dataValidator.validate(aData, aContext, violations);
|
|
119
|
0
|
if (!violations.isEmpty()) {
|
|
120
|
0
|
throw new XmlException(violations);
|
|
121
|
|
}
|
|
122
|
|
}
|
|
123
|
|
|
|
124
|
|
/**
|
|
125
|
|
* Unmarshals a list of instance documents.
|
|
126
|
|
*
|
|
127
|
|
* @param aUrls <i>(required)</i>. A list of {@link URL URL}s.
|
|
128
|
|
* @param aContext <i>(optional)</i>.
|
|
129
|
|
*
|
|
130
|
|
* @return <i>(required)</i>. A list of {@link IAnyTypeData IAnyTypeData} -
|
|
131
|
|
* the root data of the unmarshalled documents in the same sequence as the supplied URLs.
|
|
132
|
|
*
|
|
133
|
|
* @throws XmlException Raised iff an instance document could not be unmarshalled.
|
|
134
|
|
*/
|
|
135
|
1
|
public static List unmarshal(List aUrls, IDataContext aContext) throws XmlException {
|
|
136
|
1
|
ArrayList res = new ArrayList();
|
|
137
|
1
|
IImplBuilder builder = createImplBuilder(aContext);
|
|
138
|
1
|
for (Iterator i = aUrls.iterator(); i.hasNext(); ) {
|
|
139
|
2
|
URL url = (URL)i.next();
|
|
140
|
2
|
IDocumentImpl doc = builder.buildDocument(url);
|
|
141
|
2
|
IAnyTypeData data = doc.getRootData();
|
|
142
|
2
|
if (null == data) {
|
|
143
|
0
|
throw new XmlException(XmlMessages.noRootValueInXmlCodeInstance(url, null));
|
|
144
|
|
}
|
|
145
|
2
|
res.add(data);
|
|
146
|
|
}
|
|
147
|
1
|
return res;
|
|
148
|
|
}
|
|
149
|
|
|
|
150
|
|
/**
|
|
151
|
|
* Unmarshals an instance document.
|
|
152
|
|
*
|
|
153
|
|
* @param aUrl <i>(required)</i>.
|
|
154
|
|
* @param aContext <i>(optional)</i>.
|
|
155
|
|
*
|
|
156
|
|
* @return <i>(required)</i>. The root data oj the instance.
|
|
157
|
|
*
|
|
158
|
|
* @throws XmlException Raised iff the instance document could not be unmarshalled.
|
|
159
|
|
*/
|
|
160
|
215
|
public static IAnyTypeData unmarshal(URL aUrl, IDataContext aContext) throws XmlException {
|
|
161
|
215
|
return unmarshal(new InputSource(aUrl.toString()), aContext);
|
|
162
|
|
}
|
|
163
|
|
|
|
164
|
|
/**
|
|
165
|
|
* Unmarshals an instance document.
|
|
166
|
|
*
|
|
167
|
|
* @param anInputSource <i>(required)</i>.
|
|
168
|
|
* @param aContext <i>(optional)</i>.
|
|
169
|
|
* @return <i>(required)</i>.
|
|
170
|
|
*
|
|
171
|
|
* @throws XmlException Raised iff the instance document could not be unmarshalled.
|
|
172
|
|
*/
|
|
173
|
221
|
public static IAnyTypeData unmarshal(InputSource anInputSource, IDataContext aContext) throws XmlException {
|
|
174
|
221
|
IImplBuilder builder = createImplBuilder(aContext);
|
|
175
|
221
|
IDocumentImpl doc = builder.buildDocument(anInputSource);
|
|
176
|
75
|
IAnyTypeData data = doc.getRootData();
|
|
177
|
75
|
if (null == data) {
|
|
178
|
0
|
throw new XmlException(XmlMessages.noRootValueInXmlCodeInstance(anInputSource.getSystemId(), null));
|
|
179
|
|
}
|
|
180
|
75
|
return data;
|
|
181
|
|
}
|
|
182
|
|
|
|
183
|
|
|
|
184
|
0
|
public static IConfigurationCode createConfigurationCode(URL aUrl, IDataContext aContext) {
|
|
185
|
0
|
return new ConfigurationCode(aUrl, aContext);
|
|
186
|
|
}
|
|
187
|
0
|
public static IConfigurationCode createConfigurationCode(InputSource anInputSource, IDataContext aContext) {
|
|
188
|
0
|
return new ConfigurationCode(anInputSource, aContext);
|
|
189
|
|
}
|
|
190
|
|
|
|
191
|
0
|
public static IApplicationCode createApplicationCode(InputSource anInputSource, IDataContext aContext) {
|
|
192
|
0
|
return new ApplicationCode(anInputSource, aContext);
|
|
193
|
|
}
|
|
194
|
1
|
public static IApplicationCode createApplicationCode(URL aUrl, IDataContext aContext) {
|
|
195
|
1
|
return new ApplicationCode(aUrl, aContext);
|
|
196
|
|
}
|
|
197
|
0
|
public static int execute(InputSource anInputSource, IDataContext aContext) throws XmlException {
|
|
198
|
0
|
return createApplicationCode(anInputSource, aContext).execute();
|
|
199
|
|
}
|
|
200
|
0
|
public static int execute(URL aUrl, IDataContext aContext) throws XmlException {
|
|
201
|
0
|
return createApplicationCode(aUrl, aContext).execute();
|
|
202
|
|
}
|
|
203
|
|
|
|
204
|
|
/**
|
|
205
|
|
* Marshals a data object. No initial XML declaration (<?xml ... ?>) is output.
|
|
206
|
|
*
|
|
207
|
|
* @param aData <i>(required)</i>.
|
|
208
|
|
* @param aWriter <i>(required)</i>.
|
|
209
|
|
* @param aNamespaceToPrefixMapping <i>(optional)</i>. An initial mapping that
|
|
210
|
|
* is output as "xmlns" attributes. If the data object that is unmarshalled
|
|
211
|
|
* uses namespaces that are not contained in the initial mapping then new mappings
|
|
212
|
|
* are created.
|
|
213
|
|
* @param aTopLevelAttributes <i>(optional)</i>. A set of attributes that is
|
|
214
|
|
* output as additional attributes of the root element. This feature can be used
|
|
215
|
|
* to supply schema location attributes.
|
|
216
|
|
*
|
|
217
|
|
* @throws XmlException Raised iff the data object could not be unmarshalled.
|
|
218
|
|
*/
|
|
219
|
6
|
public static void marshal(Writer aWriter, IAnyTypeData aData, Map aNamespaceToPrefixMapping, Map aTopLevelAttributes) throws XmlException {
|
|
220
|
6
|
MarshalVisitor visitor = new MarshalVisitor();
|
|
221
|
6
|
visitor.marshal(aData.getImpl_(), aWriter, aNamespaceToPrefixMapping, aTopLevelAttributes);
|
|
222
|
|
}
|
|
223
|
|
|
|
224
|
|
/**
|
|
225
|
|
* Marshals a data object. No initial XML declaration (<?xml ... ?>) is output.
|
|
226
|
|
*
|
|
227
|
|
* @param aData <i>(required)</i>. The data that is marshalled.
|
|
228
|
|
* @param aNamespaceToPrefixMapping <i>(optional)</i>. (cf. {@link #marshal(Writer, IAnyTypeData, Map, Map)})
|
|
229
|
|
* @param aTopLevelAttributes <i>(optional)</i>. (cf. {@link #marshal(Writer, IAnyTypeData, Map, Map)})
|
|
230
|
|
*/
|
|
231
|
6
|
public static String marshal(IAnyTypeData aData, Map aNamespaceToPrefixMapping, Map aTopLevelAttributes) throws XmlException {
|
|
232
|
6
|
StringWriter writer = new StringWriter();
|
|
233
|
6
|
marshal(writer, aData, aNamespaceToPrefixMapping, aTopLevelAttributes);
|
|
234
|
6
|
return writer.toString();
|
|
235
|
|
}
|
|
236
|
|
|
|
237
|
|
/**
|
|
238
|
|
* Marshals a data object.
|
|
239
|
|
*
|
|
240
|
|
* @param anOutputStream <i>(required)</i>. The stream that is used for output.
|
|
241
|
|
* @param anEncoding <i>(optional)</i>. If no encoding is specified then
|
|
242
|
|
* the {@link #DEFAULT_ENCODING DEFAULT_ENCODING} is used.
|
|
243
|
|
* @param anOutputXmlDeclaration Controls whether the initial XML declaration
|
|
244
|
|
* <?xml version="1.0" encoding="..."?> or not.
|
|
245
|
|
* @param aData <i>(required)</i>. The data that is marshalled.
|
|
246
|
|
* @param aNamespaceToPrefixMapping <i>(optional)</i>. (cf. {@link #marshal(Writer, IAnyTypeData, Map, Map)})
|
|
247
|
|
* @param aTopLevelAttributes <i>(optional)</i>. (cf. {@link #marshal(Writer, IAnyTypeData, Map, Map)})
|
|
248
|
|
*/
|
|
249
|
0
|
public static void marshal(OutputStream anOutputStream, String anEncoding, boolean anOutputXmlDeclaration, IAnyTypeData aData, Map aNamespaceToPrefixMapping, Map aTopLevelAttributes) throws XmlException {
|
|
250
|
0
|
String encoding = (null == anEncoding) ? DEFAULT_ENCODING : anEncoding;
|
|
251
|
0
|
try {
|
|
252
|
0
|
OutputStreamWriter writer = new OutputStreamWriter(anOutputStream, encoding);
|
|
253
|
0
|
outputXmlDeclaration(writer, anEncoding);
|
|
254
|
0
|
marshal(writer, aData, aNamespaceToPrefixMapping, aTopLevelAttributes);
|
|
255
|
|
} catch (UnsupportedEncodingException e) {
|
|
256
|
0
|
throw new XmlException(XmlMessages.wrappedException(e, null));
|
|
257
|
|
}
|
|
258
|
|
}
|
|
259
|
|
|
|
260
|
|
/**
|
|
261
|
|
* Outputs the XML declaration "<?xml version ... ?>"
|
|
262
|
|
*
|
|
263
|
|
* @param aWriter <i>(required)</i>.
|
|
264
|
|
* @param anEncoding <i>(required)</i>.
|
|
265
|
|
*/
|
|
266
|
0
|
public static void outputXmlDeclaration(Writer aWriter, String anEncoding) throws XmlException {
|
|
267
|
0
|
try {
|
|
268
|
0
|
aWriter.write("<?xml version=\"1.0\" encoding=\"" + anEncoding + "\"?>\n");
|
|
269
|
|
} catch (IOException e) {
|
|
270
|
0
|
throw new XmlException(XmlMessages.wrappedException(e, null));
|
|
271
|
|
}
|
|
272
|
|
}
|
|
273
|
|
|
|
274
|
0
|
public static void outputSaxEvents(IAnyTypeData aData, ContentHandler aHandler) throws XmlException {
|
|
275
|
0
|
SaxVisitor visitor = new SaxVisitor();
|
|
276
|
0
|
visitor.outputSaxEvents(aData.getImpl_(), aHandler, null, null);
|
|
277
|
|
}
|
|
278
|
|
|
|
279
|
|
/**
|
|
280
|
|
* Check value equality of two data objects. For simple data objects their
|
|
281
|
|
* simple content is compared whereas for complex data object the whole
|
|
282
|
|
* data trees (including attributes) are compared.
|
|
283
|
|
*
|
|
284
|
|
* @param aData1 <i>(optional)</i>.
|
|
285
|
|
* @param aData2 <i>(optional)</i>.
|
|
286
|
|
* @return Returns <code>true</code> if the two data objects have the same value.
|
|
287
|
|
*/
|
|
288
|
5
|
public static boolean valueEquals(IAnyTypeData aData1, IAnyTypeData aData2) {
|
|
289
|
5
|
boolean res;
|
|
290
|
5
|
IDataImpl impl1 = aData1.getImpl_();
|
|
291
|
5
|
IDataImpl impl2 = aData2.getImpl_();
|
|
292
|
5
|
if ((impl1 instanceof IElementImpl) && (impl2 instanceof IElementImpl)) {
|
|
293
|
5
|
EqualsVisitor visitor = new EqualsVisitor();
|
|
294
|
5
|
try {
|
|
295
|
5
|
res = visitor.equals((IElementImpl)aData1.getImpl_(), (IElementImpl)aData2.getImpl_());
|
|
296
|
|
} catch (XmlException e) {
|
|
297
|
0
|
throw new UnexpectedException(e);
|
|
298
|
|
}
|
|
299
|
|
} else {
|
|
300
|
0
|
res = aData1 == aData2;
|
|
301
|
|
}
|
|
302
|
5
|
return res;
|
|
303
|
|
}
|
|
304
|
|
|
|
305
|
|
/**
|
|
306
|
|
* Creates a SAXSource that can be supplied to a stylesheet processor.
|
|
307
|
|
*
|
|
308
|
|
* @param aData <i>(required)</i>. The data that is output by SAX.
|
|
309
|
|
* @return <i>(required)</i>.
|
|
310
|
|
*/
|
|
311
|
0
|
public static SAXSource createSaxSource(IAnyTypeData aData) {
|
|
312
|
0
|
XMLReader reader = new ImplReader(aData.getImpl_());
|
|
313
|
0
|
InputSource inputSource = new InputSource("");
|
|
314
|
0
|
return new SAXSource(reader, inputSource);
|
|
315
|
|
}
|
|
316
|
|
|
|
317
|
0
|
private JBindFacade() {}
|
|
318
|
|
|
|
319
|
|
}
|
|
320
|
|
|