1 16 package org.apache.cocoon.transformation; 17 18 import org.apache.avalon.framework.activity.Initializable; 19 import org.apache.avalon.framework.configuration.Configurable; 20 import org.apache.avalon.framework.configuration.Configuration; 21 import org.apache.avalon.framework.configuration.ConfigurationException; 22 import org.apache.avalon.framework.parameters.Parameters; 23 24 import org.apache.cocoon.ProcessingException; 25 import org.apache.cocoon.ResourceNotFoundException; 26 import org.apache.cocoon.caching.CacheableProcessingComponent; 27 import org.apache.cocoon.environment.SourceResolver; 28 import org.apache.cocoon.util.TraxErrorHandler; 29 30 import org.apache.excalibur.source.SourceValidity; 31 32 import org.xml.sax.Attributes ; 33 import org.xml.sax.SAXException ; 34 import org.xml.sax.helpers.AttributesImpl ; 35 36 import org.xmldb.api.DatabaseManager; 37 import org.xmldb.api.base.Collection; 38 import org.xmldb.api.base.Database; 39 import org.xmldb.api.base.Resource; 40 import org.xmldb.api.base.XMLDBException; 41 import org.xmldb.api.modules.CollectionManagementService; 42 import org.xmldb.api.modules.XUpdateQueryService; 43 44 import java.io.IOException ; 45 import java.io.Serializable ; 46 import java.io.StringWriter ; 47 48 import java.util.HashMap ; 49 import java.util.Iterator ; 50 import java.util.Map ; 51 import java.util.Properties ; 52 53 import javax.xml.transform.OutputKeys ; 54 import javax.xml.transform.TransformerConfigurationException ; 55 import javax.xml.transform.TransformerFactory ; 56 import javax.xml.transform.sax.SAXTransformerFactory ; 57 import javax.xml.transform.sax.TransformerHandler ; 58 import javax.xml.transform.stream.StreamResult ; 59 60 144 public class XMLDBTransformer extends AbstractTransformer 145 implements CacheableProcessingComponent, Configurable, Initializable { 146 147 private static String XMLDB_URI = "http://apache.org/cocoon/xmldb/1.0"; 148 private static String XMLDB_QUERY_ELEMENT = "query"; 149 private static String XMLDB_QUERY_TYPE_ATTRIBUTE = "type"; 150 private static String XMLDB_QUERY_CONTEXT_ATTRIBUTE = "collection"; 151 private static String XMLDB_QUERY_OID_ATTRIBUTE = "oid"; 152 private static String XMLDB_QUERY_RESULT_ATTRIBUTE = "result"; 153 154 155 private SAXTransformerFactory tfactory = null; 156 private Properties format = new Properties (); 157 158 159 private Map prefixMap = new HashMap (); 160 161 162 private String driver = null; 163 164 165 private String default_base; 166 167 168 private String local_base; 169 170 171 private String xbase; 172 173 174 private Collection collection; 175 176 177 private String operation; 178 179 180 private String key; 181 182 183 private String result; 184 185 186 private String message; 187 188 private StringWriter queryWriter; 189 private TransformerHandler queryHandler; 190 191 192 private boolean processing; 193 194 195 public XMLDBTransformer() { 196 format.put(OutputKeys.ENCODING, "utf-8"); 197 format.put(OutputKeys.INDENT, "no"); 198 format.put(OutputKeys.OMIT_XML_DECLARATION, "yes"); 199 } 200 201 public void configure(Configuration configuration) throws ConfigurationException { 202 this.driver = configuration.getChild("driver").getValue(null); 203 if (driver == null) { 204 getLogger().debug("Driver parameter is missing. Transformer will not initialize database."); 205 } 206 207 this.default_base = configuration.getChild("base").getValue(null); 208 } 209 210 213 public void initialize() throws Exception { 214 if (driver != null) { 215 Class c = Class.forName(driver); 216 Database database = (Database)c.newInstance(); 217 DatabaseManager.registerDatabase(database); 218 } 219 } 220 221 222 public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) 223 throws ProcessingException, SAXException , IOException { 224 225 this.local_base = par.getParameter("base", this.default_base); 226 if (this.local_base == null) { 227 throw new ProcessingException("Required base parameter is missing. Syntax is: xmldb:xindice:///db/collection"); 228 } 229 230 try { 231 this.collection = DatabaseManager.getCollection(this.local_base); 232 } catch (XMLDBException e) { 233 throw new ProcessingException("Could not get collection " + this.local_base + ": " + e.errorCode, e); 234 } 235 236 if (this.collection == null) { 237 throw new ResourceNotFoundException("Collection " + this.local_base + " does not exist"); 238 } 239 } 240 241 244 protected SAXTransformerFactory getTransformerFactory() { 245 if (tfactory == null) { 246 tfactory = (SAXTransformerFactory ) TransformerFactory.newInstance(); 247 tfactory.setErrorListener(new TraxErrorHandler(getLogger())); 248 } 249 return tfactory; 250 } 251 252 260 public Serializable getKey() { 261 return null; 262 } 263 264 272 public SourceValidity getValidity() { 273 return null; 274 } 275 276 279 public void startDocument() throws SAXException { 280 super.startDocument(); 281 } 282 283 286 public void endDocument() throws SAXException { 287 super.endDocument(); 288 } 289 290 296 public void startPrefixMapping(String prefix, String uri) throws SAXException { 297 if (!processing) { 298 super.startPrefixMapping(prefix,uri); 299 prefixMap.put(prefix,uri); 300 } else if (this.queryHandler != null) { 301 this.queryHandler.startPrefixMapping(prefix, uri); 302 } 303 } 304 305 310 public void endPrefixMapping(String prefix) throws SAXException { 311 if (!processing) { 312 super.endPrefixMapping(prefix); 313 prefixMap.remove(prefix); 314 } else if (this.queryHandler != null){ 315 this.queryHandler.endPrefixMapping(prefix); 316 } 317 } 318 319 332 public void startElement(String uri, String loc, String raw, Attributes a) 333 throws SAXException { 334 if (!processing) { 335 if (XMLDB_URI.equals(uri) && XMLDB_QUERY_ELEMENT.equals(loc)){ 336 337 this.operation = a.getValue(XMLDB_QUERY_TYPE_ATTRIBUTE); 338 if (!"create".equals(operation) && !"delete".equals(operation) && !"update".equals(operation)) { 339 throw new SAXException ("Supported operation types are: create, delete, update"); 340 } 341 342 this.key = a.getValue(XMLDB_QUERY_OID_ATTRIBUTE); 343 if ("delete".equals(operation) && this.key == null) { 344 throw new SAXException ("Object ID attribute is missing on query element"); 345 } 346 347 this.xbase = a.getValue(XMLDB_QUERY_CONTEXT_ATTRIBUTE); 348 349 result = "failure"; 351 message = null; 352 processing = true; 353 354 if ("create".equals(operation) && this.key != null && this.key.endsWith("/")) { 355 } else if (!"delete".equals(operation)) { 356 queryWriter = new StringWriter (256); 358 try { 359 this.queryHandler = getTransformerFactory().newTransformerHandler(); 360 this.queryHandler.setResult(new StreamResult (queryWriter)); 361 this.queryHandler.getTransformer().setOutputProperties(format); 362 } catch (TransformerConfigurationException e) { 363 throw new SAXException ("Failed to get transformer handler", e); 364 } 365 366 this.queryHandler.startDocument(); 368 Iterator i = prefixMap.entrySet().iterator(); 369 while (i.hasNext()) { 370 Map.Entry entry = (Map.Entry )i.next(); 371 this.queryHandler.startPrefixMapping((String )entry.getKey(), (String )entry.getValue()); 372 } 373 } 374 } else { 375 super.startElement(uri, loc, raw, a); 376 } 377 } else if (this.queryHandler != null) { 378 this.queryHandler.startElement(uri, loc, raw, a); 379 } 380 } 381 382 393 public void endElement(String uri, String loc, String raw) 394 throws SAXException { 395 if (!processing) { 396 super.endElement(uri,loc,raw); 397 } else { 398 if (XMLDB_URI.equals(uri) && XMLDB_QUERY_ELEMENT.equals(loc)) { 399 processing = false; 400 401 String document = null; 402 if (this.queryHandler != null) { 403 Iterator i = prefixMap.entrySet().iterator(); 405 while (i.hasNext()) { 406 Map.Entry entry = (Map.Entry ) i.next(); 407 this.queryHandler.endPrefixMapping((String )entry.getKey()); 408 } 409 this.queryHandler.endDocument(); 410 document = this.queryWriter.toString(); 411 } 412 413 Collection collection = null; 415 try { 416 collection = (xbase != null)? DatabaseManager.getCollection(local_base + "/" + xbase) : this.collection; 418 419 if (collection == null) { 420 message = "Failed to " + operation + " resource " + this.key + ": Collection " + local_base + "/" + xbase + " not found."; 421 getLogger().debug(message); 422 } else if ("create".equals(operation)) { 423 if (key != null && key.endsWith("/")) { 424 try { 425 String k = this.key.substring(0, this.key.length() - 1); 427 CollectionManagementService service = 428 (CollectionManagementService) collection.getService("CollectionManagementService", "1.0"); 429 service.createCollection(k); 430 result = "success"; 431 } catch (XMLDBException e) { 432 message = "Failed to create collection " + this.key + ": " + e.errorCode; 433 getLogger().error(message, e); 434 } 435 } else { 436 try { 437 if (key == null) { 438 key = collection.createId(); 439 } 440 Resource resource = collection.createResource(key, "XMLResource"); 442 resource.setContent(document); 443 collection.storeResource(resource); 444 result = "success"; 445 key = resource.getId(); 446 } catch (XMLDBException e) { 447 message = "Failed to create resource " + key + ": " + e.errorCode; 448 getLogger().debug(message, e); 449 } 450 } 451 } else if ("delete".equals(operation)) { 452 if (key != null && key.endsWith("/")) { 453 try { 454 String k = this.key.substring(0, this.key.length() - 1); 456 CollectionManagementService service = 457 (CollectionManagementService) collection.getService("CollectionManagementService", "1.0"); 458 service.removeCollection(k); 459 result = "success"; 460 } catch (XMLDBException e) { 461 message = "Failed to delete collection " + this.key + ": " + e.errorCode; 462 getLogger().error(message, e); 463 } 464 } else { 465 try { 466 Resource resource = collection.getResource(this.key); 467 if (resource == null) { 468 message = "Resource " + this.key + " does not exist"; 469 getLogger().debug(message); 470 } else { 471 collection.removeResource(resource); 472 result = "success"; 473 } 474 } catch (XMLDBException e) { 475 message = "Failed to delete resource " + key + ": " + e.errorCode; 476 getLogger().debug(message, e); 477 } 478 } 479 } else if ("update".equals(operation)) { 480 try { 481 XUpdateQueryService service = 482 (XUpdateQueryService) collection.getService("XUpdateQueryService", "1.0"); 483 long count = (this.key == null)? 484 service.update(document) : service.updateResource(this.key, document); 485 message = count + " entries updated."; 486 result = "success"; 487 } catch (XMLDBException e) { 488 message = "Failed to update resource " + key + ": " + e.errorCode; 489 getLogger().debug(message, e); 490 } 491 } 492 } catch (XMLDBException e) { 493 message = "Failed to get context collection for the query (base: " + local_base + ", context: " + xbase + "): " + e.errorCode; 494 getLogger().debug(message, e); 495 } finally { 496 if (xbase != null && collection != null) { 497 try { 498 collection.close(); 499 } catch (XMLDBException ignored) { 500 } 501 } 502 } 503 504 505 AttributesImpl attrs = new AttributesImpl (); 507 attrs.addAttribute(null, XMLDB_QUERY_OID_ATTRIBUTE, 508 XMLDB_QUERY_OID_ATTRIBUTE, "CDATA", this.key); 509 attrs.addAttribute(null, XMLDB_QUERY_TYPE_ATTRIBUTE, 510 XMLDB_QUERY_TYPE_ATTRIBUTE, "CDATA", this.operation); 511 attrs.addAttribute(null, XMLDB_QUERY_RESULT_ATTRIBUTE, 512 XMLDB_QUERY_RESULT_ATTRIBUTE, "CDATA", result); 513 super.startElement(uri, loc, raw, attrs); 514 if (message != null) { 515 super.characters(message.toCharArray(), 0, message.length()); 516 } 517 super.endElement(uri, loc, raw); 518 } else if (this.queryHandler != null) { 519 this.queryHandler.endElement(uri, loc, raw); 520 } 521 } 522 } 523 524 531 public void characters(char c[], int start, int len) throws SAXException { 532 if (!processing) { 533 super.characters(c,start,len); 534 } else if (this.queryHandler != null) { 535 this.queryHandler.characters(c,start,len); 536 } 537 } 538 539 546 public void ignorableWhitespace(char c[], int start, int len) throws SAXException { 547 if (!processing) { 548 super.ignorableWhitespace(c,start,len); 549 } else if (this.queryHandler != null) { 550 this.queryHandler.ignorableWhitespace(c,start,len); 551 } 552 } 553 554 561 public void processingInstruction(String target, String data) throws SAXException { 562 if (!processing) { 563 super.processingInstruction(target,data); 564 } else if (this.queryHandler != null) { 565 this.queryHandler.processingInstruction(target,data); 566 } 567 } 568 569 575 public void skippedEntity(String name) throws SAXException { 576 if (!processing) { 577 super.skippedEntity(name); 578 } else if (this.queryHandler != null) { 579 this.queryHandler.skippedEntity(name); 580 } 581 } 582 583 592 public void startDTD(String name, String publicId, String systemId) throws SAXException { 593 if (!processing) { 594 super.startDTD(name, publicId, systemId); 595 } else { 596 throw new SAXException ( 597 "Recieved startDTD after beginning SVG extraction process." 598 ); 599 } 600 } 601 602 605 public void endDTD() throws SAXException { 606 if (!processing) { 607 super.endDTD(); 608 } else { 609 throw new SAXException ("Recieved endDTD after xmldb element."); 610 } 611 } 612 613 619 public void startEntity(String name) throws SAXException { 620 if (!processing) { 621 super.startEntity(name); 622 } else if (this.queryHandler != null) { 623 this.queryHandler.startEntity(name); 624 } 625 } 626 627 632 public void endEntity(String name) throws SAXException { 633 if (!processing) { 634 super.endEntity(name); 635 } else if (this.queryHandler != null) { 636 this.queryHandler.endEntity(name); 637 } 638 } 639 640 643 public void startCDATA() throws SAXException { 644 if (!processing) { 645 super.startCDATA(); 646 } else if (this.queryHandler != null) { 647 this.queryHandler.startCDATA(); 648 } 649 } 650 651 654 public void endCDATA() throws SAXException { 655 if (!processing) { 656 super.endCDATA(); 657 } else if (this.queryHandler != null) { 658 this.queryHandler.endCDATA(); 659 } 660 } 661 662 669 public void comment(char ch[], int start, int len) throws SAXException { 670 if (!processing) { 671 super.comment(ch, start, len); 672 } else if (this.queryHandler != null) { 673 this.queryHandler.comment(ch, start, len); 674 } 675 } 676 677 public void recycle() { 678 this.prefixMap.clear(); 679 this.queryHandler = null; 680 this.queryWriter = null; 681 682 try { 683 if (collection != null) { 684 collection.close(); 685 } 686 } catch (XMLDBException e) { 687 getLogger().error("Failed to close collection " + this.local_base + ". Error " + e.errorCode, e); 688 } 689 collection = null; 690 super.recycle(); 691 } 692 } 693 | Popular Tags |