Subversion Repositories XServices

Rev

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