Subversion Repositories XServices

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
114 brianR 1
/*
2
 *   Copyright 2013 Brian Rosenberger (Brutex Network)
3
 *
4
 *   Licensed under the Apache License, Version 2.0 (the "License");
5
 *   you may not use this file except in compliance with the License.
6
 *   You may obtain a copy of the License at
7
 *
8
 *       http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 *   Unless required by applicable law or agreed to in writing, software
11
 *   distributed under the License is distributed on an "AS IS" BASIS,
12
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 *   See the License for the specific language governing permissions and
14
 *   limitations under the License.
15
 */
16
 
17
package net.brutex.xservices.ws.impl;
18
 
19
import java.io.ByteArrayInputStream;
20
import java.io.IOException;
21
import java.io.InputStream;
22
import java.io.StringReader;
23
import java.io.StringWriter;
127 brianR 24
import java.io.UnsupportedEncodingException;
25
import java.nio.charset.Charset;
26
import java.nio.charset.IllegalCharsetNameException;
114 brianR 27
import java.util.Iterator;
28
import java.util.List;
29
import javax.jws.WebService;
127 brianR 30
import javax.xml.namespace.QName;
114 brianR 31
import javax.xml.stream.XMLOutputFactory;
32
import javax.xml.stream.XMLStreamException;
33
import javax.xml.stream.XMLStreamWriter;
127 brianR 34
 
35
import net.brutex.xservices.types.AttributeType;
114 brianR 36
import net.brutex.xservices.types.NamespaceListType;
37
import net.brutex.xservices.types.NamespaceType;
127 brianR 38
import net.brutex.xservices.types.StringSplitType;
114 brianR 39
import net.brutex.xservices.types.ant.FileResource;
40
import net.brutex.xservices.ws.XServicesFault;
41
import net.brutex.xservices.ws.XmlService;
158 brianR 42
 
114 brianR 43
import org.apache.axiom.om.OMAbstractFactory;
127 brianR 44
import org.apache.axiom.om.OMAttribute;
114 brianR 45
import org.apache.axiom.om.OMCloneOptions;
127 brianR 46
import org.apache.axiom.om.OMComment;
114 brianR 47
import org.apache.axiom.om.OMContainer;
48
import org.apache.axiom.om.OMDocument;
49
import org.apache.axiom.om.OMElement;
127 brianR 50
import org.apache.axiom.om.OMFactory;
114 brianR 51
import org.apache.axiom.om.OMNode;
127 brianR 52
import org.apache.axiom.om.OMProcessingInstruction;
114 brianR 53
import org.apache.axiom.om.OMText;
54
import org.apache.axiom.om.OMXMLBuilderFactory;
55
import org.apache.axiom.om.xpath.AXIOMXPath;
185 brianR 56
 
57
import org.apache.logging.log4j.LogManager;
58
import org.apache.logging.log4j.Logger;
177 brianR 59
import org.apache.shiro.authz.annotation.RequiresPermissions;
114 brianR 60
import org.jaxen.JaxenException;
61
import org.jaxen.SimpleNamespaceContext;
62
 
63
/**
64
 * @author Brian Rosenberger, bru(at)brutex.de
65
 *
66
 */
67
@WebService(targetNamespace = "http://ws.xservices.brutex.net", endpointInterface = "net.brutex.xservices.ws.XmlService", serviceName = "XmlService")
68
public class XmlServiceImpl implements XmlService {
185 brianR 69
	private static final Logger logger = LogManager.getLogger();
114 brianR 70
 
185 brianR 71
	public String insertNodesFromFile(FileResource res, NamespaceListType nsList, String xpath, String xmlFragment)
72
			throws XServicesFault {
114 brianR 73
		try {
74
			AXIOMXPath axp = new AXIOMXPath(xpath);
75
			InputStream is = res.getAntResource(null).getInputStream();
185 brianR 76
			OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is).getDocument();
114 brianR 77
			OMDocument fragdoc = null;
78
			if ((xmlFragment != null) && (new String(xmlFragment).length() > 0)) {
185 brianR 79
				fragdoc = OMXMLBuilderFactory.createOMBuilder(new StringReader("<XS>" + xmlFragment + "</XS>"))
114 brianR 80
						.getDocument();
81
			} else {
82
				throw new XServicesFault("No xmldata to insert.");
83
			}
84
 
85
			// Initialize XPath context
127 brianR 86
			SimpleNamespaceContext context = createContext(nsList);
114 brianR 87
			axp.setNamespaceContext(context);
88
			axp.addNamespaces(fragdoc.getOMDocumentElement());
89
 
90
			OMDocument document = insertNodes(sourcedoc, axp, fragdoc);
91
 
92
			StringWriter sw = new StringWriter();
93
			XMLOutputFactory xof = XMLOutputFactory.newInstance();
94
			XMLStreamWriter writer = xof.createXMLStreamWriter(sw);
95
			document.serialize(writer);
96
 
97
			this.logger.trace(sw.getBuffer().toString());
98
			return sw.getBuffer().toString();
99
		} catch (JaxenException e) {
100
			e.printStackTrace();
101
			throw new XServicesFault(e);
102
		} catch (IOException e) {
103
			e.printStackTrace();
104
			throw new XServicesFault(e);
105
		} catch (XMLStreamException e) {
106
			e.printStackTrace();
107
			throw new XServicesFault(e);
108
		}
109
	}
110
 
185 brianR 111
	public String replaceNodesFromFile(FileResource res, NamespaceListType nsList, String xpath, String xmlFragment)
112
			throws XServicesFault {
114 brianR 113
		try {
185 brianR 114
			AXIOMXPath axp = new AXIOMXPath(xpath);
115
			InputStream is = res.getAntResource(null).getInputStream();
116
			OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is).getDocument();
117
			OMDocument fragdoc = null;
118
			if ((xmlFragment != null) && (new String(xmlFragment).length() > 0)) {
119
				fragdoc = OMXMLBuilderFactory.createOMBuilder(new StringReader("<XS>" + xmlFragment + "</XS>"))
120
						.getDocument();
121
			} else {
122
				throw new XServicesFault("No xmldata to insert.");
123
			}
114 brianR 124
 
185 brianR 125
			// Initialize XPath context
126
			SimpleNamespaceContext context = createContext(nsList);
127
			axp.setNamespaceContext(context);
128
			axp.addNamespaces(fragdoc.getOMDocumentElement());
114 brianR 129
 
185 brianR 130
			OMDocument document = replaceNodes(sourcedoc, axp, fragdoc);
114 brianR 131
 
185 brianR 132
			StringWriter sw = new StringWriter();
133
			XMLOutputFactory xof = XMLOutputFactory.newInstance();
134
			XMLStreamWriter writer = xof.createXMLStreamWriter(sw);
135
			document.serialize(writer);
114 brianR 136
 
185 brianR 137
			this.logger.trace(sw.getBuffer().toString());
138
			return sw.getBuffer().toString();
139
		} catch (JaxenException e) {
140
			e.printStackTrace();
141
			throw new XServicesFault(e);
142
		} catch (XMLStreamException e) {
143
			e.printStackTrace();
144
			throw new XServicesFault(e);
145
		} catch (IOException e) {
146
			e.printStackTrace();
147
			throw new XServicesFault(e);
148
		}
114 brianR 149
	}
150
 
185 brianR 151
	public String replaceNodes(String source, String encoding, NamespaceListType nsList, String xpath,
152
			String xmlFragment) throws XServicesFault {
127 brianR 153
		encoding = validateEncoding(encoding);
114 brianR 154
		try {
155
			AXIOMXPath axp = new AXIOMXPath(xpath);
127 brianR 156
			InputStream is = new ByteArrayInputStream(source.getBytes(encoding));
185 brianR 157
			OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is).getDocument();
114 brianR 158
			OMDocument fragdoc = null;
159
			if ((xmlFragment != null) && (new String(xmlFragment).length() > 0)) {
185 brianR 160
				fragdoc = OMXMLBuilderFactory.createOMBuilder(new StringReader("<XS>" + xmlFragment + "</XS>"))
114 brianR 161
						.getDocument();
162
			} else {
163
				throw new XServicesFault("No xmldata to insert.");
164
			}
165
 
166
			// Initialize XPath context
127 brianR 167
			SimpleNamespaceContext context = createContext(nsList);
114 brianR 168
			axp.setNamespaceContext(context);
169
			axp.addNamespaces(fragdoc.getOMDocumentElement());
170
 
171
			OMDocument document = replaceNodes(sourcedoc, axp, fragdoc);
172
 
173
			StringWriter sw = new StringWriter();
174
			XMLOutputFactory xof = XMLOutputFactory.newInstance();
175
			XMLStreamWriter writer = xof.createXMLStreamWriter(sw);
176
			document.serialize(writer);
177
 
178
			this.logger.trace(sw.getBuffer().toString());
179
			return sw.getBuffer().toString();
180
		} catch (JaxenException e) {
181
			e.printStackTrace();
182
			throw new XServicesFault(e);
183
		} catch (XMLStreamException e) {
184
			e.printStackTrace();
185
			throw new XServicesFault(e);
127 brianR 186
		} catch (UnsupportedEncodingException e) {
187
			throw new XServicesFault(e);
114 brianR 188
		}
189
	}
185 brianR 190
 
177 brianR 191
	@RequiresPermissions("insertNodes")
185 brianR 192
	public String insertNodes(String source, String encoding, NamespaceListType nsList, String xpath,
193
			String xmlFragment) throws XServicesFault {
127 brianR 194
		encoding = validateEncoding(encoding);
114 brianR 195
		try {
196
			AXIOMXPath axp = new AXIOMXPath(xpath);
127 brianR 197
			InputStream is = new ByteArrayInputStream(source.getBytes(encoding));
185 brianR 198
			OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is).getDocument();
114 brianR 199
			OMDocument fragdoc = null;
200
			if ((xmlFragment != null) && (new String(xmlFragment).length() > 0)) {
185 brianR 201
				fragdoc = OMXMLBuilderFactory.createOMBuilder(new StringReader("<XS>" + xmlFragment + "</XS>"))
114 brianR 202
						.getDocument();
203
			} else {
204
				throw new XServicesFault("No xmldata to insert.");
205
			}
206
 
207
			// Initialize XPath context
127 brianR 208
			SimpleNamespaceContext context = createContext(nsList);
114 brianR 209
			axp.setNamespaceContext(context);
210
			axp.addNamespaces(fragdoc.getOMDocumentElement());
211
 
212
			OMDocument document = insertNodes(sourcedoc, axp, fragdoc);
213
 
214
			StringWriter sw = new StringWriter();
215
			XMLOutputFactory xof = XMLOutputFactory.newInstance();
216
			XMLStreamWriter writer = xof.createXMLStreamWriter(sw);
217
			document.serialize(writer);
218
 
219
			this.logger.trace(sw.getBuffer().toString());
220
			return sw.getBuffer().toString();
221
		} catch (JaxenException e) {
222
			e.printStackTrace();
223
			throw new XServicesFault(e);
224
		} catch (XMLStreamException e) {
225
			e.printStackTrace();
226
			throw new XServicesFault(e);
127 brianR 227
		} catch (UnsupportedEncodingException e) {
228
			throw new XServicesFault(e);
114 brianR 229
		}
230
	}
231
 
232
	public String wrapInCDATA(String data) throws XServicesFault {
185 brianR 233
		String result = "";
114 brianR 234
		String[] tokens = data.split("\\]\\]>", -1);
185 brianR 235
 
236
		for (int i = 0; i < tokens.length; i++) {
237
			result += tokens[i];
238
			if (i + 1 < tokens.length)
239
				result += "]]]]><![CDATA[>";
114 brianR 240
		}
185 brianR 241
 
114 brianR 242
		result = "<![CDATA[" + result + "]]>";
243
		return result;
244
	}
127 brianR 245
 
185 brianR 246
	public StringSplitType selectXPath(String source, String encoding, NamespaceListType nsList, String xpath)
247
			throws XServicesFault {
127 brianR 248
		encoding = validateEncoding(encoding);
249
		try {
250
			StringSplitType rarray = new StringSplitType();
251
			AXIOMXPath axp = new AXIOMXPath(xpath);
252
			InputStream is = new ByteArrayInputStream(source.getBytes(encoding));
253
			OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is).getDocument();
185 brianR 254
 
127 brianR 255
			// Initialize XPath context
256
			SimpleNamespaceContext context = createContext(nsList);
185 brianR 257
 
127 brianR 258
			axp.setNamespaceContext(context);
259
			List results = axp.selectNodes(sourcedoc);
185 brianR 260
			for (Object o : results) {
127 brianR 261
				String text = null;
185 brianR 262
 
263
				if (o instanceof OMNode) {
264
					switch (((OMNode) o).getType()) {
265
					case OMNode.TEXT_NODE:
266
						text = ((OMText) o).getText();
267
						break;
268
					case OMNode.COMMENT_NODE:
269
						text = ((OMComment) o).getValue();
270
						break;
271
					case OMNode.PI_NODE:
272
						text = ((OMProcessingInstruction) o).getValue();
273
						break;
274
					default:
275
						StringWriter sw = new StringWriter();
276
						XMLOutputFactory xof = XMLOutputFactory.newInstance();
277
						XMLStreamWriter writer = xof.createXMLStreamWriter(sw);
278
						((OMNode) o).serialize(writer);
279
						writer.flush();
280
						text = sw.toString();
281
					}
282
				} else if (o instanceof OMAttribute) {
283
					text = ((OMAttribute) o).getAttributeValue();
127 brianR 284
				} else {
285
					text = String.valueOf(o);
286
				}
287
				rarray.addStringMatch(text);
288
			}
289
 
290
			return rarray;
185 brianR 291
		} catch (JaxenException e) {
127 brianR 292
			e.printStackTrace();
293
			throw new XServicesFault(e);
294
		} catch (XMLStreamException e) {
185 brianR 295
			// TODO Auto-generated catch block
127 brianR 296
			throw new XServicesFault(e.getMessage());
185 brianR 297
		} catch (UnsupportedEncodingException e) {
298
			throw new XServicesFault(e);
127 brianR 299
		}
300
	}
185 brianR 301
 
302
	public String setAttribute(String source, String encoding, NamespaceListType nsList, String xpath,
303
			AttributeType attr) throws XServicesFault {
127 brianR 304
		encoding = validateEncoding(encoding);
305
		try {
306
			StringSplitType rarray = new StringSplitType();
307
			AXIOMXPath axp = new AXIOMXPath(xpath);
308
			InputStream is = new ByteArrayInputStream(source.getBytes(encoding));
309
			OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is).getDocument();
310
			OMFactory fac = OMAbstractFactory.getOMFactory();
185 brianR 311
 
127 brianR 312
			// Initialize XPath context
313
			SimpleNamespaceContext context = createContext(nsList);
185 brianR 314
 
127 brianR 315
			axp.setNamespaceContext(context);
316
			List results = axp.selectNodes(sourcedoc);
185 brianR 317
			for (Object o : results) {
127 brianR 318
				String text = null;
185 brianR 319
 
320
				if (o instanceof OMNode) {
321
					switch (((OMNode) o).getType()) {
322
					case OMNode.ELEMENT_NODE:
323
						OMElement node = ((OMElement) o);
324
						if (attr.value == null) {
325
							node.removeAttribute(node.getAttribute(new QName(attr.name)));
326
						} else {
327
							node.addAttribute(attr.name, attr.value, node.getNamespace());
328
						}
329
						break;
330
					default:
331
						throw new XServicesFault("XPath expression did not match an element node.");
127 brianR 332
					}
333
				} else {
334
					throw new XServicesFault("XPath expression did not match a node.");
335
				}
336
			}
185 brianR 337
 
127 brianR 338
			StringWriter sw = new StringWriter();
339
			XMLOutputFactory xof = XMLOutputFactory.newInstance();
340
			XMLStreamWriter writer = xof.createXMLStreamWriter(sw);
341
			sourcedoc.serialize(writer);
342
			writer.flush();
185 brianR 343
			return sw.toString();
344
		} catch (JaxenException e) {
127 brianR 345
			e.printStackTrace();
346
			throw new XServicesFault(e);
347
		} catch (XMLStreamException e) {
185 brianR 348
			// TODO Auto-generated catch block
127 brianR 349
			throw new XServicesFault(e.getMessage());
185 brianR 350
		} catch (UnsupportedEncodingException e) {
351
			throw new XServicesFault(e);
127 brianR 352
		}
353
	}
185 brianR 354
 
355
	private OMDocument insertNodes(OMDocument xmldocument, AXIOMXPath axp, OMDocument xmlfragment)
356
			throws XServicesFault {
114 brianR 357
		List<?> olist = null;
358
		try {
359
			olist = axp.selectNodes(xmldocument.getOMDocumentElement());
185 brianR 360
			this.logger.debug("XPath '" + axp.toString() + "' has " + olist.size() + " matches.");
361
			this.logger.trace("XPath root expression is: '" + axp.debug() + "'.");
114 brianR 362
		} catch (JaxenException e) {
363
			throw new XServicesFault(e.getMessage(), e);
364
		}
365
		if (olist.size() == 0)
185 brianR 366
			throw new XServicesFault(Messages.getString("XmlService.no_match", new Object[] { axp.toString() }));
114 brianR 367
 
368
		// Prepare children to insert
369
		xmlfragment.build();
370
 
371
		// Determine what has been matched
372
		OMContainer match = null;
373
		for (Object o : olist) {
185 brianR 374
			Iterator<?> children = xmlfragment.getOMDocumentElement().getChildren();
114 brianR 375
			if ((o instanceof OMNode)) {
376
				OMNode node = (OMNode) o;
377
				switch (node.getType()) {
378
				case OMNode.ELEMENT_NODE:
379
					if ((o instanceof OMElement))
380
						match = (OMElement) o;
381
					if ((o instanceof OMDocument))
382
						match = ((OMDocument) o).getOMDocumentElement();
383
					this.logger.debug(Messages.getString("XmlService.8"));
384
					break;
385
				case OMNode.TEXT_NODE:
386
					match = ((OMText) o).getParent();
387
					this.logger.debug(Messages.getString("XmlService.9"));
388
					break;
389
				case OMNode.COMMENT_NODE:
390
					// match = node.getParent();
391
					match = (OMContainer) node;
392
					this.logger.debug(Messages.getString("XmlService.10"));
393
					break;
394
				default:
185 brianR 395
					this.logger
396
							.error("XPath matched " + o.getClass().getCanonicalName() + " Node Type:" + node.getType());
114 brianR 397
					this.logger.error(Messages.getString("XmlService.11"));
185 brianR 398
					throw new XServicesFault(Messages.getString("XmlService.12"));
114 brianR 399
				}
400
			} else {
185 brianR 401
				this.logger.error("XPath matched " + o.getClass().getCanonicalName());
114 brianR 402
				this.logger.error(Messages.getString("XmlService.11"));
403
				throw new XServicesFault(Messages.getString("XmlService.12"));
404
			}
405
 
406
			while (children.hasNext()) {
407
				OMNode container = (OMNode) children.next();
408
				match.addChild((OMNode) container.clone(new OMCloneOptions()));
409
			}
410
		}
411
 
412
		xmldocument.build();
413
		return xmldocument;
414
	}
415
 
185 brianR 416
	private OMDocument replaceNodes(OMDocument xmldocument, AXIOMXPath axp, OMDocument xmlfragment)
417
			throws XServicesFault {
114 brianR 418
 
419
		List<?> olist = null;
420
		try {
421
			olist = axp.selectNodes(xmldocument.getOMDocumentElement());
185 brianR 422
			this.logger.debug("XPath '" + axp.toString() + "' has " + olist.size() + " matches.");
423
			this.logger.trace("XPath root expression is: '" + axp.debug() + "'.");
114 brianR 424
		} catch (JaxenException e) {
425
			throw new XServicesFault(e.getMessage(), e);
426
		}
427
		if (olist.size() == 0)
185 brianR 428
			throw new XServicesFault(Messages.getString("XmlService.no_match", new Object[] { axp.toString() }));
114 brianR 429
 
430
		// Prepare children to insert
431
		xmlfragment.build();
432
 
433
		// Determine what has been matched
434
		OMNode match = null;
435
		for (Object o : olist) {
185 brianR 436
			Iterator<?> children = xmlfragment.getOMDocumentElement().getChildren();
114 brianR 437
			if ((o instanceof OMNode)) {
438
				OMNode node = (OMNode) o;
439
				switch (node.getType()) {
440
				case OMNode.ELEMENT_NODE:
441
					if ((o instanceof OMElement))
442
						match = (OMElement) o;
443
					if ((o instanceof OMDocument))
444
						match = ((OMDocument) o).getOMDocumentElement();
445
					this.logger.debug(Messages.getString("XmlService.8"));
446
					break;
447
				default:
185 brianR 448
					this.logger
449
							.error("XPath matched " + o.getClass().getCanonicalName() + " Node Type:" + node.getType());
114 brianR 450
					this.logger.error(Messages.getString("XmlService.11"));
185 brianR 451
					throw new XServicesFault(Messages.getString("XmlService.12"));
114 brianR 452
				}
453
			} else {
185 brianR 454
				this.logger.error("XPath matched " + o.getClass().getCanonicalName());
114 brianR 455
				this.logger.error(Messages.getString("XmlService.11"));
456
				throw new XServicesFault(Messages.getString("XmlService.12"));
457
			}
458
 
459
			while (children.hasNext()) {
460
				OMNode container = (OMNode) children.next();
158 brianR 461
				match.insertSiblingBefore((OMNode) container.clone(new OMCloneOptions()));
114 brianR 462
			}
463
			match.detach();
464
		}
465
		xmldocument.build();
466
		return xmldocument;
467
	}
127 brianR 468
 
469
	private SimpleNamespaceContext createContext(NamespaceListType nsList) {
470
		// Initialize XPath context
471
		SimpleNamespaceContext context = new SimpleNamespaceContext();
185 brianR 472
		if (nsList != null) {
127 brianR 473
			for (NamespaceType ns : nsList.getNamespaces()) {
474
				context.addNamespace(ns.getPrefix(), ns.getUri().toString());
185 brianR 475
				this.logger.debug(
476
						Messages.getString("XmlService.0") + ns.getPrefix() + "=\"" + ns.getUri().toString() + "\"'");
127 brianR 477
			}
478
		} else {
479
			logger.debug("No namespaces defined.");
480
		}
481
		return context;
482
	}
483
 
484
	private String validateEncoding(String encoding) throws XServicesFault {
185 brianR 485
		if (encoding == null || encoding.equals("")) {
486
			encoding = Charset.defaultCharset().displayName();
487
		}
488
		try {
127 brianR 489
			Charset.isSupported(encoding);
490
		} catch (IllegalCharsetNameException e) {
185 brianR 491
			throw new XServicesFault("Endcoding '" + encoding + "' is not supported by this JRE.");
127 brianR 492
		}
185 brianR 493
		logger.debug("Setting source xml string encoding to '" + encoding + "'");
127 brianR 494
		return encoding;
495
	}
158 brianR 496
 
114 brianR 497
}