Subversion Repositories XServices

Rev

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