jeremy 2002/07/01 01:53:39 Modified: src/java/org/apache/cocoon/transformation SourceWritingTransformer.java Log: unified the tags style, response and implementation of source:write and source:insert tags Revision Changes Path 1.5 +326 -304 xml-cocoon2/src/java/org/apache/cocoon/transformation/SourceWritingTransformer.java Index: SourceWritingTransformer.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/transformation/SourceWritingTransformer.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- SourceWritingTransformer.java 28 Jun 2002 07:14:36 -0000 1.4 +++ SourceWritingTransformer.java 1 Jul 2002 08:53:39 -0000 1.5 @@ -86,7 +86,8 @@ import java.util.Properties; /** - * This transformer allows you to output to a WritableSource. +/** + * This transformer allows you to output to a WriteableSource. * * <p>Definition:</p> * <pre> @@ -98,67 +99,111 @@ * <p>Invocation:</p> * <pre> * <map:transform type="tofile"> - * <map:parameter name="serializer" value="xml"/> + * <map:parameter name="serializer" value="xml"/> <!-- you can optionally override the serializer here --> * </map:transform> * </pre> * - * <p>Input XML document example:</p> + * <p>The Tags:</p> * <pre> - * <page xmlns:source="http://apache.org/cocoon/source/1.0"> + * <source:write create="[true]|false"> - replaces the entire content of an existing asset, if @create is 'true' (default), a new asset will be created if one does not already exist. + * <source:source>The System ID of the asset to be written to</source:source> - eg: "docs/blah.xml" or "context://blah.xml" etc. + * <source:path>[Optional] XPath to specify how your content is wrapped</source:path> - eg: "doc" (your content is placed inside a <doc/> root tag). NOTE: if this value is omitted, your content MUST have only ONE top-level node. + * <source:fragment>The XML Fragment to be written</source:fragment> - eg: "<foo><bar id="dogcow"/></foo>" or "<foo/><bar><dogcow/><bar/>" etc. NOTE: the second example type, can only be used when the <source:path/> tag has been specified. + * <source:write> + * + * <source:insert create="[true]|false" overwrite="[true]|false"> - inserts content into an existing asset, if @create is 'true' (default), a new asset will be created if one does not already exist. If @overwrite is set to 'true' the data is only inserted if the node specified by the 'replacePath' does not exists. + * <source:source>The System ID of the asset to be written to</source:source> - eg: "docs/blah.xml" or "context://blah.xml" etc. + * <source:path>XPath specifying the node into which the content is inserted</source:path> - eg: "doc" (your content is appended as the last child of the <doc/> root tag), or "doc/section[3]". NOTE: this tag is required in <source:insert/> unlike <source:write/> where it is optional. + * <source:replace>[Optional] XPath (relative to <source:path/>) to the node that is replaced by your new content</source:replace> - eg: "foo/bar/dogcow/@status='cut'" (is equivalent to this in XSLT: select="foo[bar/dogcow/@status='cut']"). + * <source:reinsert>[Optional] The XPath (relative to <source:replace/>) to backup the overwritten node to</source:reinsert> - eg: "foo/versions" or "/doc/versions/foo". NOTE: If specified and a node is replaced, all children of this replaced node will be reinserted at the given path. + * <source:fragment>The XML Fragment to be written</source:fragment> - eg: "<foo><bar id="dogcow"/></foo>" or "<foo/><bar><dogcow/><bar/>" etc. + * <source:insert> + * </pre> + * + * + * <p>Input XML document example (write):</p> + * <pre> + * <page> * ... - * <source:write src="context://doc/editable/my.xml"> - * <page> - * XML Object body - * </page> + * <source:write xmlns:source="http://apache.org/cocoon/source/1.0"> + * <source:source>context://doc/editable/my.xml</source:source> + * <source:fragment><page> + * <title>Hello World</title> + * <content> + * <p>This is my first paragraph.</p> + * </content> + * </page></source:fragment> * </source:write> * ... * </page> * </pre> * - * <p>Output XML document example:</p> + * <p>Input XML document example (insert at end):</p> * <pre> - * <page xmlns:source="http://apache.org/cocoon/source/1.0"> + * <page> * ... - * <source:write src="/source/specific/path/to/context/doc/editable/my.xml" result="success|failure" action="new"> - * source specific error message - * </source:write> + * <source:insert xmlns:source="http://apache.org/cocoon/source/1.0"> + * <source:source>context://doc/editable/my.xml</source:source> + * <source:path>page/content</source:path> + * <source:fragment> + * <p>This paragraph gets <emp>inserted</emp>.</p> + * <p>With this one, at the end of the content.</p> + * </source:fragment> + * </source:insert> * ... * </page> * </pre> * - * <P>Inserting of XML fragments:</p> - * This implementation allows the inserting of an xml fragment into a - * source. + * <p>Input XML document example (insert at beginning):</p> + * <pre> + * <page> + * ... + * <source:insert> + * <source:source>context://doc/editable/my.xml</source:source> + * <source:path>page</source:path> + * <source:replace>content</source:replace> + * <source:reinsert>content</source:reinsert> + * <source:fragment> + * <content> + * <p>This new paragraph gets inserted <emp>before</emp> the other ones.</p> + * </content> + * </source:fragment> + * <source:insert> + * ... + * </page> + * </pre> * + * <p>Input XML document example (replace):</p> * <pre> - * <page xmlns:source="http://apache.org/cocoon/source/1.0"> + * <page> * ... - * <source:insert> - * <source:source>The SRC</source:source> - * <source:path>XPath denoting the position to insert</source:path> - * <source:fragment>the xml fragment</source:fragment> - * </source:insert> + * <source:insert xmlns:source="http://apache.org/cocoon/source/1.0"> + * <source:source>context://doc/editable/my.xml"</source:source> + * <source:path>page/content</source:path> + * <source:replace>p[1]</source:replace> + * <source:fragment> + * <p>This paragraph <emp>replaces</emp> the first paragraph.</p> + * </source:fragment> + * </source:insert> * ... * </page> * </pre> * - * By default, the fragment is always inserted (added). It is possible to specify - * a node (by an XPath) which will be replaced if it exists. + * <p>Output XML document example:</p> * <pre> - * <page xmlns:source="http://apache.org/cocoon/source/1.0"> + * <page> * ... - * <source:insert> - * <source:source>The SRC</source:source> - * <source:path>XPath denoting the position to insert</source:path> - * <source:fragment>the xml fragment</source:fragment> - * <source:replace>XPath denoting a criteria for which node will be replaced</source:replace> - * </source:insert> + * <sourceResult xmlns:source="http://apache.org/cocoon/source/1.0"> + * <action>new|overwritten|none</action> + * <behaviour>write|insert<behaviour> + * <execution>success|failure</execution> + * <serializer>xml</serializer> + * <source>file:/source/specific/path/to/context/doc/editable/my.xml</source> + * </sourceResult> * ... * </page> * </pre> * - * The information for <code>replace</code> has to be relative to path, but can - * specify a subnode of the node the be replaced. * * The XPath specification is very complicated. So here is an example for the sitemap: * <pre> @@ -168,9 +213,9 @@ * <source:source>sitemap.xmap</source:source> * <source:path>/*[namespace-uri()="http://apache.org/cocoon/sitemap/1.0" and local-name()="sitemap"]/*[namespace-uri()="http://apache.org/cocoon/sitemap/1.0" and local-name()="components"]/*[namespace-uri()="http://apache.org/cocoon/sitemap/1.0" and local-name()="generators"]</source:path> * <source:fragment> - * <generator name="file" xmln="http://apache.org/cocoon/sitemap/1.0"> - * <test/> - * </generator> + * <generator name="file" xmln="http://apache.org/cocoon/sitemap/1.0"> + * <test/> + * </generator> * </source:fragment> * <source:replace>*[namespace-uri()="http://apache.org/cocoon/sitemap/1.0" and local-name()="generator" and attribute::name="file"]</source:replace> * </source:insert> @@ -178,23 +223,35 @@ * </page> * </pre> * - * This insert replaces (if it exists) the file generator definition with a new one. + * <p>This insert replaces (if it exists) the file generator definition with a new one. * As the sitemap uses namespaces the XPath for the generator is rather complicated. * Due to this it is necessary that the node specified by path exists if namespaces - * are used! Otherwise a node with the name * would be created... + * are used! Otherwise a node with the name * would be created...</p> * - * The create attribute of insert. If this is set + * <p>The create attribute of insert. If this is set * to true (default is true), the file is created if it does not exists. * If it is set to false, it is not created, making insert a real insert. - * create is only usable for files! - * In addition the overwrite attribute is used to check if replacing is allowed. + * create is only usable for files!</p> + * <p>In addition the overwrite attribute is used to check if replacing is allowed. * If overwrite is true (the default) the node is replaced. If it is false - * the node is not inserted if the replace node is available. + * the node is not inserted if the replace node is available.</p> * - * The <session:reinsert> option can be used to + * <p>[JQ] - the way I understand this, looking at the code: + * <pre> + * if 'replace' is not specified, your 'fragment' is appended as a child of 'path'. + * if 'replace' is specified and it exists and 'overwrite' is true, your 'fragment' is inserted in 'path', before 'replace' and then 'replace' is deleted. + * if 'replace' is specified and it exists and 'overwrite' is false, no action occurs. + * if 'replace' is specified and it does not exist and 'overwrite' is true, your 'fragment' is appended as a child of 'path'. + * if 'replace' is specified and it does not exist and 'overwrite' is false, your 'fragment' is appended as a child of 'path'. + * if 'reinsert' is specified and it does not exist, no action occurs. + * </pre></p> + * + * The <source:reinsert> option can be used to * reinsert a replaced node at a given path in the new fragment. * + * * TODO: Use the serializer instead of the XMLUtils for inserting of fragments + * TODO: Add a <source:before/> tag. * * @author <a href="mailto:[EMAIL PROTECTED]">Carsten Ziegeler</a> * @author <a href="mailto:[EMAIL PROTECTED]">Jeremy Quinn</a> @@ -203,32 +260,34 @@ public class SourceWritingTransformer extends AbstractSAXTransformer { - private static String SWT_URI = "http://apache.org/cocoon/source/1.0"; - private static String SWT_ELEMENT = "write"; - private static String SWT_RESULT_ATTRIBUTE= "result"; - private static String SWT_SRC_ATTRIBUTE = "src"; - private static String SWT_ACTION_ATTRIBUTE = "action"; - private static String SWT_SERIALIZER_ATTRIBUTE = "serializer"; - private static String SWT_RESULT_FAILED = "failed"; - private static String SWT_RESULT_SUCCESS = "success"; - private static String SWT_ACTION_NONE = "none"; - private static String SWT_ACTION_NEW = "new"; - private static String SWT_ACTION_OVER = "overwritten"; - + public static final String SWT_URI = "http://apache.org/cocoon/source/1.0"; + public static final String DEFAULT_SERIALIZER = "xml"; + + /** incoming elements */ + public static final String WRITE_ELEMENT = "write"; public static final String INSERT_ELEMENT = "insert"; - public static final String INSERT_CREATE_ATTRIBUTE = "create"; - public static final String INSERT_OVERWRITE_ATTRIBUTE = "overwrite"; - public static final String PATH_ELEMENT = "path"; - public static final String FRAGMENT_ELEMENT = "fragment"; - public static final String REPLACE_ELEMENT = "replace"; - public static final String SOURCE_ELEMENT = "source"; - public static final String REINSERT_ELEMENT = "reinsert"; - + /** outgoing elements */ + public static final String RESULT_ELEMENT = "sourceResult"; + public static final String EXECUTION_ELEMENT = "execution"; + public static final String BEHAVIOUR_ELEMENT = "behaviour"; + public static final String ACTION_ELEMENT = "action"; + public static final String MESSAGE_ELEMENT = "message"; + public static final String SERIALIZER_ELEMENT = "serializer"; + /** main (write or insert) tag attributes */ + public static final String SERIALIZER_ATTRIBUTE = "serializer"; + public static final String CREATE_ATTRIBUTE = "create"; + public static final String OVERWRITE_ATTRIBUTE = "overwrite"; + /** results */ + public static final String RESULT_FAILED = "failed"; + public static final String RESULT_SUCCESS = "success"; + public static final String ACTION_NONE = "none"; + public static final String ACTION_NEW = "new"; + public static final String ACTION_OVER = "overwritten"; /** The current state */ private static final int STATE_OUTSIDE = 0; private static final int STATE_INSERT = 1; @@ -238,41 +297,13 @@ private static final int STATE_REPLACE = 5; private static final int STATE_FILE = 6; private static final int STATE_REINSERT = 7; + private static final int STATE_WRITE = 8; private int state; + private int parent_state; /** The configured serializer name */ protected String configuredSerializerName; - /** The ContentHandler instance */ - protected XMLConsumer ch; // is XMLConsumer suitable for this purpose? - - - /** Are we using a Serializer? */ - private boolean isSerializer = false; - - /** Current Serializer name. */ - private String serializer_name = null; - - /** Current target name. */ - private String target = null; - - /** Current OutputStream. */ - private OutputStream os = null; - - /** Current status of outputting the file. */ - private boolean failed = true; - - /** Current error message. */ - private String message = null; - - /** Does the file exist, before we try to make it? */ - private boolean exists = false; - - /** the Source. */ - private Source source = null; - - /** the WritableSource. */ - private WriteableSource wsource = null; /** * Constructor @@ -289,7 +320,7 @@ public void configure(Configuration configuration) throws ConfigurationException { super.configure( configuration ); - this.configuredSerializerName = configuration.getChild(SWT_SERIALIZER_ATTRIBUTE).getValue("xml"); + this.configuredSerializerName = configuration.getChild(SERIALIZER_ATTRIBUTE).getValue(DEFAULT_SERIALIZER); } /** @@ -299,10 +330,7 @@ public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) throws ProcessingException, SAXException, IOException { super.setup(resolver, objectModel, src, par); - this.serializer_name = par.getParameter(SWT_SERIALIZER_ATTRIBUTE, this.configuredSerializerName); - if (this.serializer_name != null && this.getLogger().isDebugEnabled() ) { - this.getLogger().debug("Setup, using serializer: " + this.serializer_name); - } + this.configuredSerializerName = par.getParameter(SERIALIZER_ATTRIBUTE, this.configuredSerializerName); this.state = STATE_OUTSIDE; } @@ -329,30 +357,51 @@ if (name.equals(INSERT_ELEMENT) && this.state == STATE_OUTSIDE) { this.state = STATE_INSERT; - if (attr.getValue(INSERT_CREATE_ATTRIBUTE) != null - && attr.getValue(INSERT_CREATE_ATTRIBUTE).equals("false")) { + this.parent_state = STATE_INSERT; + if (attr.getValue(CREATE_ATTRIBUTE) != null + && attr.getValue(CREATE_ATTRIBUTE).equals("false")) { this.stack.push("false"); } else { this.stack.push("true"); } - if (attr.getValue(INSERT_OVERWRITE_ATTRIBUTE) != null - && attr.getValue(INSERT_OVERWRITE_ATTRIBUTE).equals("false")) { + if (attr.getValue(OVERWRITE_ATTRIBUTE) != null + && attr.getValue(OVERWRITE_ATTRIBUTE).equals("false")) { this.stack.push("false"); } else { this.stack.push("true"); } + this.stack.push(attr.getValue(SERIALIZER_ATTRIBUTE)); this.stack.push("INSERT"); + // Element: write + } else if (name.equals(WRITE_ELEMENT) + && this.state == STATE_OUTSIDE) { + this.state = STATE_WRITE; + this.parent_state = STATE_WRITE; + if (attr.getValue(CREATE_ATTRIBUTE) != null + && attr.getValue(CREATE_ATTRIBUTE).equals("false")) { + this.stack.push("false"); + } else { + this.stack.push("true"); // default value + } + if (attr.getValue(OVERWRITE_ATTRIBUTE) != null + && attr.getValue(OVERWRITE_ATTRIBUTE).equals("false")) { + this.stack.push("false"); + } else { + this.stack.push("true"); // default value + } + this.stack.push(attr.getValue(SERIALIZER_ATTRIBUTE)); + this.stack.push("WRITE"); // Element: file } else if (name.equals(SOURCE_ELEMENT) - && this.state == STATE_INSERT) { + && (this.state == STATE_INSERT || this.state == STATE_WRITE)) { this.state = STATE_FILE; this.startTextRecording(); // Element: path } else if (name.equals(PATH_ELEMENT) - && this.state == STATE_INSERT) { + && (this.state == STATE_INSERT || this.state == STATE_WRITE)) { this.state = STATE_PATH; this.startTextRecording(); @@ -364,7 +413,7 @@ // Element: fragment } else if (name.equals(FRAGMENT_ELEMENT) - && this.state == STATE_INSERT) { + && (this.state == STATE_INSERT || this.state == STATE_WRITE)) { this.state = STATE_FRAGMENT; this.startRecording(); @@ -374,63 +423,6 @@ this.state = STATE_REINSERT; this.startTextRecording(); - } else if (name.equals(SWT_ELEMENT)) { - this.failed = false; - this.message = null; - this.target = ""; - - // look for the Source - String src = attr.getValue("",SWT_SRC_ATTRIBUTE); - try { - this.message = "The src attribute could not be resolved"; - this.source = this.resolver.resolveURI(src); - this.target = this.source.getSystemId(); - - this.message = "The src attribute doesn't resolve to a writeable source"; - this.wsource = (WriteableSource)this.source; - this.exists = this.wsource.exists(); - - // has a Serializer been specified? - String local_serializer = attr.getValue("",SWT_SERIALIZER_ATTRIBUTE); - if (local_serializer != null) this.serializer_name = local_serializer; - if (this.serializer_name != null) { - // Lookup the Serializer - this.message = "that Serializer does not exist"; - ComponentSelector selector = null; - try { - selector = (ComponentSelector)manager.lookup(Serializer.ROLE + "Selector"); - this.ch = (Serializer)selector.select(this.serializer_name); - this.message = "Could not open the source for writing"; - this.os = this.wsource.getOutputStream(); - this.message = "could not write the file"; - ((Serializer)this.ch).setOutputStream(this.os); // Is there a way to avoid this casting? - this.isSerializer = true; - } finally { - this.manager.release( selector ); - } - } else { - this.message = "could not get a ContentHandler"; - this.ch = (XMLConsumer)((WriteableSAXSource)wsource).getContentHandler(); - } - this.addRecorder( this.ch ); - this.startDocument(); - this.sendStartPrefixMapping(); - - } catch (Exception e) { - getLogger().warn("failed, " + this.message, e); - this.failed = true; - try { - if (this.isSerializer) { - this.wsource.cancel(this.os); - } else { - ((WriteableSAXSource)this.wsource).cancel(this.ch); - } - } catch (Exception e2) { - getLogger().warn("failed to cancel: " + this.target, e2); - this.message += " and failed to cancel"; - } - } - // default } else { super.startTransformingElement(uri, name, raw, attr); } @@ -460,7 +452,6 @@ ", raw=" + raw); } if (name.equals(INSERT_ELEMENT) == true && this.state == STATE_INSERT) { - this.state = STATE_OUTSIDE; // get the information from the stack String tag; @@ -483,10 +474,45 @@ reinsert = (String)this.stack.pop(); } } while (tag.equals("INSERT") == false); + final String localSerializer = (String)this.stack.pop(); + final boolean overwrite = this.stack.pop().equals("true"); + final boolean create = this.stack.pop().equals("true"); + + this.insertFragment(fileName, + path, + fragment, + replacePath, + create, + overwrite, + reinsert, + localSerializer, + name); + + this.state = STATE_OUTSIDE; + + } else if (name.equals(WRITE_ELEMENT) == true && this.state == STATE_WRITE) { + + // get the information from the stack + String tag; + String fileName = null; + DocumentFragment fragment = null; + String path = "/"; // source:write's path can be empty + String replacePath = null; + String reinsert = null; + do { + tag = (String)this.stack.pop(); + if (tag.equals("PATH") == true) { + path = (String)this.stack.pop(); + } else if (tag.equals("FILE") == true) { + fileName = (String)this.stack.pop(); + } else if (tag.equals("FRAGMENT") == true) { + fragment = (DocumentFragment)this.stack.pop(); + } + } while (tag.equals("WRITE") == false); + final String localSerializer = (String)this.stack.pop(); final boolean overwrite = this.stack.pop().equals("true"); final boolean create = this.stack.pop().equals("true"); - // FIXME (CZ) : Overriding of serializer is not implemented yet! this.insertFragment(fileName, path, fragment, @@ -494,97 +520,41 @@ create, overwrite, reinsert, - null); + localSerializer, + name); + + this.state = STATE_OUTSIDE; // Element: file } else if (name.equals(SOURCE_ELEMENT) == true && this.state == STATE_FILE) { - this.state = STATE_INSERT; + this.state = this.parent_state; this.stack.push(this.endTextRecording()); this.stack.push("FILE"); // Element: path } else if (name.equals(PATH_ELEMENT) == true && this.state == STATE_PATH) { - this.state = STATE_INSERT; + this.state = this.parent_state; this.stack.push(this.endTextRecording()); this.stack.push("PATH"); // Element: replace } else if (name.equals(REPLACE_ELEMENT) == true && this.state == STATE_REPLACE) { - this.state = STATE_INSERT; + this.state = this.parent_state; this.stack.push(this.endTextRecording()); this.stack.push("REPLACE"); // Element: fragment } else if (name.equals(FRAGMENT_ELEMENT) == true && this.state == STATE_FRAGMENT) { - this.state = STATE_INSERT; + this.state = this.parent_state; this.stack.push(this.endRecording()); this.stack.push("FRAGMENT"); // Element: reinsert - } else if (name.equals(REINSERT_ELEMENT) == true - && this.state == STATE_REINSERT) { - this.state = STATE_INSERT; + } else if (name.equals(REINSERT_ELEMENT) == true && this.state == STATE_REINSERT) { + this.state = this.parent_state; this.stack.push(this.endTextRecording()); this.stack.push("REINSERT"); - } else if (name.equals(SWT_ELEMENT)) { - if (!this.failed) { - this.sendEndPrefixMapping(); - this.endDocument(); - this.removeRecorder(); - // close the OutputStream - try { - if (this.os != null) { - this.os.close(); - this.os = null; - } - - } catch(Exception e) { - getLogger().warn("Failed to close source", e); - this.message = "Failed to close source"; - this.failed = true; - try { - this.message = "Failed to cancel source"; - if (this.isSerializer) { - this.wsource.cancel(this.os); - } else { - ((WriteableSAXSource)this.wsource).cancel(this.ch); - } - } catch (Exception e2) { - getLogger().warn("failed to cancel: " + this.target, e2); - } - } finally { - if (this.source != null) { - this.resolver.release( this.source ); - this.source = null; - } - } - if (!this.failed) { - this.wsource = null; - } - - // Report result - String result = (this.failed) ? SWT_RESULT_FAILED : SWT_RESULT_SUCCESS; - String action = SWT_ACTION_NONE; - if (!this.failed){ - if (this.exists) { - action = SWT_ACTION_OVER; - } else { - action = SWT_ACTION_NEW; - } - } - AttributesImpl attrs = new AttributesImpl(); - attrs.addAttribute(null, SWT_SRC_ATTRIBUTE, SWT_SRC_ATTRIBUTE, "CDATA", this.target); - attrs.addAttribute(null, SWT_ACTION_ATTRIBUTE, SWT_ACTION_ATTRIBUTE, "CDATA", action); - attrs.addAttribute(null, SWT_RESULT_ATTRIBUTE, SWT_RESULT_ATTRIBUTE, "CDATA", result); - if (this.serializer_name != null) attrs.addAttribute(null, SWT_SERIALIZER_ATTRIBUTE, SWT_SERIALIZER_ATTRIBUTE, "CDATA", this.serializer_name); - super.contentHandler.startElement(uri, name, raw, attrs); - if (this.message != null && this.failed == true) super.characters(this.message.toCharArray(), 0, this.message.length()); - super.contentHandler.endElement(uri, name, raw); - if (this.getLogger().isDebugEnabled()) { - this.getLogger().debug("Source Written"); - } - } // default } else { super.endTransformingElement(uri, name, raw); @@ -596,29 +566,6 @@ } public void recycle() { - if (this.wsource != null) { - getLogger().error("cancelled by recycle() method"); - if (this.os != null) { - try { - this.wsource.cancel(this.os); - } catch (Exception e) { - getLogger().error("failed to cancel in recycle() method: OutputStream"); - } - } else if (this.ch != null) { - try { - ((WriteableSAXSource)this.wsource).cancel(this.ch); - } catch (Exception e) { - getLogger().error("failed to cancel in recycle() method: ContentHandler"); - } - } - } - if (this.source != null) { - this.resolver.release( this.source ); - this.source = null; - } - - if (isSerializer) this.manager.release((Component)this.ch); - this.ch = null; super.recycle(); } @@ -641,7 +588,8 @@ * does not exists. * @param reinsertPath If specified and a node is replaced , all children of * this replaced node will be reinserted at the given path. - * @param serializer The serializer used to serialize the XML + * @param localSerializer The serializer used to serialize the XML + * @param tagname The name of the tag that triggered me 'insert' or 'write' */ protected void insertFragment(String systemID, String path, @@ -650,7 +598,8 @@ boolean create, boolean overwrite, String reinsertPath, - String localSerializer) + String localSerializer, + String tagname) throws SAXException, IOException, ProcessingException { // no sync req if (this.getLogger().isDebugEnabled() == true) { @@ -677,18 +626,23 @@ // first: read the source as a DOM Source source = null; Document resource = null; + boolean failed = true; + boolean exists = false; + String message = ""; + String target = systemID; try { source = this.resolver.resolveURI( systemID ); if ( ! (source instanceof WriteableSource)) { throw new ProcessingException("Source '"+systemID+"' is not writeable."); } WriteableSource ws = (WriteableSource)source; - if ( ws.exists() ) { - + exists = ws.exists(); + target = source.getSystemId(); + if ( exists == true && this.state == STATE_INSERT ) { + message = "content inserted at: " + path; resource = SourceUtil.toDOM( source, this.manager ); // import the fragment Node importNode = resource.importNode(fragment, true); - // get the node Node parent = XMLUtil.selectSingleNode(resource, path); @@ -696,96 +650,164 @@ if (replacePath != null) { try { Node replaceNode = XMLUtil.getSingleNode(parent, replacePath); - // now get the parent of this node until it is the parent node for insertion while (replaceNode != null && replaceNode.getParentNode().equals(parent) == false) { replaceNode = replaceNode.getParentNode(); } if (replaceNode != null) { if (overwrite == true) { - parent.replaceChild(importNode, replaceNode); + parent.replaceChild(importNode, replaceNode); + message += ", replacing: " + replacePath; if (reinsertPath != null) { Node insertAt = XMLUtil.getSingleNode(importNode, reinsertPath); if (insertAt != null) { while (replaceNode.hasChildNodes() == true) { insertAt.appendChild(replaceNode.getFirstChild()); } + } else { // reinsert point null + message = "replace failed, could not find your reinsert path: " + reinsertPath; + resource = null; } } + } else { // overwrite was false + message = "replace failed, no overwrite allowed."; + resource = null;/**/ } - } else { + } else { // specified replaceNode was not found parent.appendChild(importNode); } } catch (javax.xml.transform.TransformerException sax) { throw new ProcessingException("TransformerException: " + sax, sax); } - } else { // no replace + } else { // no replace path, just do an insert at end parent.appendChild(importNode); } } else if (create == true) { - - Parser parser = (Parser)this.manager.lookup(Parser.ROLE); - try { - resource = parser.createDocument(); - } finally { - this.manager.release( parser ); - } - - // import the fragment - Node importNode = resource.importNode(fragment, true); - // get the node - Node parent = XMLUtil.selectSingleNode(resource, path); - // add fragment - parent.appendChild(importNode); + Parser parser = (Parser)this.manager.lookup(Parser.ROLE); + try { + resource = parser.createDocument(); + } finally { + this.manager.release( parser ); + } + // import the fragment + Node importNode = resource.importNode(fragment, true); + if ( path.equals("") ) { // this is allowed in write + resource.appendChild(importNode); + message = "entire source overwritten"; + + } else { + // get the node + Node parent = XMLUtil.selectSingleNode(resource, path); + // add fragment + parent.appendChild(importNode); + message = "content appended to: " + path; + } + } else { + message = "create not allowed"; + resource = null;/**/ } // write source if ( resource != null) { resource.normalize(); - if (source instanceof WriteableSAXSource) { ContentHandler contentHandler = ((WriteableSAXSource)ws).getContentHandler(); DOMStreamer streamer = new DOMStreamer(contentHandler); streamer.stream(resource); + localSerializer = "null"; + failed = false; } else { // use serializer if (localSerializer == null) localSerializer = this.configuredSerializerName; if (localSerializer != null) { - // Lookup the Serializer - ComponentSelector selector = null; - Serializer serializer = null; - OutputStream oStream = null; - try { - selector = (ComponentSelector)manager.lookup(Serializer.ROLE + "Selector"); - serializer = (Serializer)selector.select(localSerializer); - oStream = ws.getOutputStream(); - serializer.setOutputStream(oStream); - DOMStreamer streamer = new DOMStreamer(serializer); - streamer.stream(resource); - } finally { - if (oStream != null) { - try { - oStream.flush(); - oStream.close(); - } catch (Exception ignore) {} - } - if ( selector != null ) { - selector.release( serializer ); - this.manager.release( selector ); - } - } + // Lookup the Serializer + ComponentSelector selector = null; + Serializer serializer = null; + OutputStream oStream = null; + try { + selector = (ComponentSelector)manager.lookup(Serializer.ROLE + "Selector"); + serializer = (Serializer)selector.select(localSerializer); + oStream = ws.getOutputStream(); + serializer.setOutputStream(oStream); + DOMStreamer streamer = new DOMStreamer(serializer); + streamer.stream(resource); + } finally { + if (oStream != null) { + oStream.flush(); + try { + oStream.close(); + failed = false; + } catch (Throwable t) { + if (this.getLogger().isDebugEnabled() == true) { + this.getLogger().debug("FAIL (oStream.close) exception"+t); + throw new ProcessingException("Could not process your document.", t); + } + } finally { + if ( selector != null ) { + selector.release( serializer ); + this.manager.release( selector ); + } + } + } + } } else { - throw new ProcessingException("No serializer specified for writing to source " + systemID); + if (this.getLogger().isDebugEnabled() == true) { + this.getLogger().debug("ERROR no serializer"); + } + //throw new ProcessingException("No serializer specified for writing to source " + systemID); + message = "That source requires a serializer, please add the appropirate tag to your code."; } } - } + } + } catch (DOMException de) { + if (this.getLogger().isDebugEnabled() == true) { + this.getLogger().debug("FAIL exception: "+de); + } + //throw new ProcessingException("Could not process your document.", de); + message = "There was a problem manipulating your document: " + de; } catch (ComponentException ce) { - throw new ProcessingException("Unable to lookup component.", ce); + if (this.getLogger().isDebugEnabled() == true) { + this.getLogger().debug("FAIL exception: "+ce); + } + //throw new ProcessingException("Unable to lookup component.", ce); + message = "There was a problem looking up a component: " + ce; } catch (SourceException se) { - throw SourceUtil.handle("Error during resolving "+systemID, se); + if (this.getLogger().isDebugEnabled() == true) { + this.getLogger().debug("FAIL exception: "+se); + } + //throw new ProcessingException("Error during resolving "+systemID, se); + message = "There was a problem resolving that source: [" + systemID + "] : " + se; } finally { this.resolver.release( source ); } + + // Report result + String result = (failed) ? RESULT_FAILED : RESULT_SUCCESS; + String action = ACTION_NONE; + if (!failed) { action = (exists) ? ACTION_OVER : ACTION_NEW; } + + sendStartElementEvent(RESULT_ELEMENT); + sendStartElementEvent(EXECUTION_ELEMENT); + sendTextEvent(result); + sendEndElementEvent(EXECUTION_ELEMENT); + sendStartElementEvent(MESSAGE_ELEMENT); + sendTextEvent(message); + sendEndElementEvent(MESSAGE_ELEMENT); + sendStartElementEvent(BEHAVIOUR_ELEMENT); + sendTextEvent(tagname); + sendEndElementEvent(BEHAVIOUR_ELEMENT); + sendStartElementEvent(ACTION_ELEMENT); + sendTextEvent(action); + sendEndElementEvent(ACTION_ELEMENT); + sendStartElementEvent(SOURCE_ELEMENT); + sendTextEvent(target); + sendEndElementEvent(SOURCE_ELEMENT); + if (localSerializer != null) { + sendStartElementEvent(SERIALIZER_ELEMENT); + sendTextEvent(localSerializer); + sendEndElementEvent(SERIALIZER_ELEMENT); + } + sendEndElementEvent(RESULT_ELEMENT); if (this.getLogger().isDebugEnabled() == true) { this.getLogger().debug("END insertFragment");
---------------------------------------------------------------------- In case of troubles, e-mail: [EMAIL PROTECTED] To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]