cziegeler 02/05/07 01:17:46 Modified: src/documentation/xdocs/plan to-avalon.xml src/scratchpad/src/org/apache/cocoon/transformation SourceWritingTransformer.java Log: Start merging SourceWritingTransformer and InsertTransformer Revision Changes Path 1.3 +8 -8 xml-cocoon2/src/documentation/xdocs/plan/to-avalon.xml Index: to-avalon.xml =================================================================== RCS file: /home/cvs/xml-cocoon2/src/documentation/xdocs/plan/to-avalon.xml,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- to-avalon.xml 9 Apr 2002 06:37:55 -0000 1.2 +++ to-avalon.xml 7 May 2002 08:17:46 -0000 1.3 @@ -30,7 +30,7 @@ <li>XMLFragment</li> <li>Parser (done)</li> <li>XMLSerializer/XMLDeserializer</li> - <li>XSLTProcessor</li> + <li>XSLTProcessor (done)</li> </ul> <p>Everything dealing with Source objects. (This is the part @@ -38,11 +38,11 @@ </p> <ul> - <li>SourceResolver</li> - <li>SourceHandler</li> - <li>SourceFactory</li> - <li>Source</li> - <li>ModifiableSource</li> + <li>SourceResolver (done)</li> + <li>SourceHandler (done)</li> + <li>SourceFactory (done)</li> + <li>Source (done)</li> + <li>ModifiableSource (done)</li> </ul> <p>List of Implementations:</p> @@ -50,8 +50,8 @@ <li>AbstractXMLConsumer</li> <li>JaxpParser, XercesParser (done)</li> <li>XMLByteStreamCompiler/XMLByteStreamInterpreter</li> - <li>Everything dealing with Source objects</li> - <li>XSLTProcessorImpl</li> + <li>Everything dealing with Source objects (done)</li> + <li>XSLTProcessorImpl (done)</li> <li><link href="catalog.html">Entity Catalogs </link> - the entity resolver (done)</li> </ul> 1.4 +525 -347 xml-cocoon2/src/scratchpad/src/org/apache/cocoon/transformation/SourceWritingTransformer.java Index: SourceWritingTransformer.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/transformation/SourceWritingTransformer.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- SourceWritingTransformer.java 22 Mar 2002 13:14:55 -0000 1.3 +++ SourceWritingTransformer.java 7 May 2002 08:17:46 -0000 1.4 @@ -63,16 +63,22 @@ import org.apache.cocoon.serialization.Serializer; import org.apache.cocoon.caching.CacheValidity; import org.apache.cocoon.caching.Cacheable; -import org.apache.cocoon.environment.Source; import org.apache.cocoon.environment.SourceResolver; import org.apache.cocoon.environment.WriteableSource; import org.apache.cocoon.ProcessingException; import org.apache.cocoon.ResourceNotFoundException; +import org.apache.cocoon.webapps.session.connector.ResourceConnector; +import org.apache.cocoon.webapps.session.transformation.AbstractSessionTransformer; +import org.apache.cocoon.webapps.session.xml.XMLUtil; import org.apache.cocoon.xml.XMLConsumer; +import org.apache.cocoon.xml.XMLUtils; +import org.apache.excalibur.source.Source; +import org.apache.excalibur.source.SourceException; +import org.w3c.dom.*; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; -import java.lang.SecurityException; +import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.util.Map; @@ -119,11 +125,80 @@ * </page> * </pre> * + * <P>Inserting of XML fragments:</p> + * This implementation allows the inserting of an xml fragment into a + * source. + * + * <pre> + * <page xmlns:source="http://apache.org/cocoon/source/1.0"> + * ... + * <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> + * ... + * </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. + * <pre> + * <page xmlns:source="http://apache.org/cocoon/source/1.0"> + * ... + * <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> + * ... + * </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> + * <page xmlns:source="http://apache.org/cocoon/source/1.0"> + * ... + * <source:insert> + * <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> + * </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> + * ... + * </page> + * </pre> + * + * 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... + * + * 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. + * 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 <session:reinsert> option can be used to + * reinsert a replaced node at a given path in the new fragment. + * + * @author <a href="mailto:[EMAIL PROTECTED]">Carsten Ziegeler</a> * @author <a href="mailto:[EMAIL PROTECTED]">Jeremy Quinn</a> * */ -public class SourceWritingTransformer extends AbstractTransformer - implements Disposable, Configurable, Composable { +public class SourceWritingTransformer + extends AbstractSessionTransformer { private static String SWT_URI = "http://apache.org/cocoon/source/1.0"; private static String SWT_ELEMENT = "write"; @@ -137,12 +212,33 @@ private static String SWT_ACTION_NEW = "new"; private static String SWT_ACTION_OVER = "overwritten"; + public static final String INSERT_ELEMENT = "insert"; + public static final String INSERT_CREATE_ATTRIBUTE = "create"; + public static final String INSERT_OVERWRITE_ATTRIBUTE = "overwrite"; - /** The <code>SourceResolver</code> */ - protected SourceResolver sourceResolver; + public static final String PATH_ELEMENT = "path"; - /** The current <code>ComponentManager</code>. */ - protected ComponentManager manager = null; + public static final String FRAGMENT_ELEMENT = "fragment"; + + public static final String REPLACE_ELEMENT = "replace"; + + public static final String FILE_ELEMENT = "file"; + + public static final String REINSERT_ELEMENT = "reinsert"; + + /** The current state */ + private static final int STATE_OUTSIDE = 0; + private static final int STATE_INSERT = 1; + private static final int STATE_RESOURCE = 2; + private static final int STATE_PATH = 3; + private static final int STATE_FRAGMENT = 4; + private static final int STATE_REPLACE = 5; + private static final int STATE_FILE = 6; + private static final int STATE_REINSERT = 7; + private int state; + + /** The configured serializer name */ + protected String configuredSerializerName; /** The ContentHandler instance */ protected XMLConsumer ch; // is XMLConsumer suitable for this purpose? @@ -169,38 +265,28 @@ /** Does the file exist, before we try to make it? */ private boolean exists = false; - /** True when inside <write> element. */ - private boolean processing; - - /** the Source. */ + /** the Source. */ private Source source = null; - /** the WritableSource. */ + /** the WritableSource. */ private WriteableSource wsource = null; - - - public void WriteableSourceTransformer() { - } - /** - * Set the current <code>ComponentManager</code> instance used by this - * <code>Composable</code>. + * Constructor + * Set the namespace */ - public void compose(ComponentManager manager) throws ComponentException { - this.manager=manager; // We need this later to get the Serializer, if it is required + public SourceWritingTransformer() { + this.namespaceURI = SWT_URI; } /** * Get the current <code>Configuration</code> instance used by this * <code>Configurable</code>. */ - public void configure(Configuration configuration) throws ConfigurationException { - try { - this.serializer_name = configuration.getChild(SWT_SERIALIZER_ATTRIBUTE).getValue(); - } catch (Exception e) { - getLogger().debug("Configuration - no serializer yet"); - } + public void configure(Configuration configuration) + throws ConfigurationException { + super.configure( configuration ); + this.configuredSerializerName = configuration.getChild(SWT_SERIALIZER_ATTRIBUTE).getValue(null); } /** @@ -209,37 +295,12 @@ */ public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) throws ProcessingException, SAXException, IOException { - this.sourceResolver = resolver; // save it for later, when we know the filepath to save to - this.serializer_name = par.getParameter(SWT_SERIALIZER_ATTRIBUTE, this.serializer_name); - if (this.serializer_name != null) - getLogger().debug("Setup, using serializer: " + this.serializer_name); - } - - /** - * Begin the scope of a prefix-URI Namespace mapping. - * - * @param prefix The Namespace prefix being declared. - * @param uri The Namespace URI the prefix is mapped to. - */ - public void startPrefixMapping(String prefix, String uri) throws SAXException { - if (!this.processing) { - super.startPrefixMapping(prefix,uri); - } else if (this.ch != null){ - this.ch.startPrefixMapping(prefix, uri); - } - } - - /** - * End the scope of a prefix-URI mapping. - * - * @param prefix The prefix that was being mapping. - */ - public void endPrefixMapping(String prefix) throws SAXException { - if (!this.processing) { - super.endPrefixMapping(prefix); - } else if (this.ch != null){ - this.ch.endPrefixMapping(prefix); - } + 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.state = STATE_OUTSIDE; } /** @@ -255,65 +316,121 @@ * @param a The attributes attached to the element. If there are no * attributes, it shall be an empty Attributes object. */ - public void startElement(String uri, String loc, String raw, Attributes a) - throws SAXException { - if (!this.processing) { - if (SWT_URI.equals(uri) && SWT_ELEMENT.equals(loc)) { - getLogger().debug("start processing xmlns:source"); - this.failed = false; - this.message = null; - this.target = ""; - - // look for the Source - String src = a.getValue("",SWT_SRC_ATTRIBUTE); - try { - this.message = "The src attribute could not be resolved"; - this.source = this.sourceResolver.resolve(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 = a.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 = (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; - } else { - this.message = "could not get a ContentHandler"; - this.ch = (XMLConsumer)wsource.getContentHandler(); - } - } catch (Exception e) { - getLogger().warn("failed, " + this.message, e); - this.failed = true; - try { - this.wsource.cancel(this.ch); - } catch (Exception e2) { - getLogger().warn("failed to cancel: " + this.target, e2); - this.message += " and failed to cancel"; - } - } - // start the document - if (!this.failed) { - this.ch.startDocument(); - } - this.processing = true; - getLogger().debug("Processing Started"); - } else { - super.startElement(uri,loc,raw,a); - } - } else if (this.ch != null){ - this.ch.startElement(uri,loc,raw,a); - } + public void startTransformingElement(String uri, String name, String raw, Attributes attr) + throws SAXException, IOException, ProcessingException { + if (this.getLogger().isDebugEnabled() == true) { + this.getLogger().debug("BEGIN startTransformingElement uri=" + uri + + ", name=" + name + ", raw=" + raw + ", attr=" + attr); + } + // Element: insert + if (name.equals(INSERT_ELEMENT) + && this.state == STATE_OUTSIDE) { + state = STATE_INSERT; + if (attr.getValue(INSERT_CREATE_ATTRIBUTE) != null + && attr.getValue(INSERT_CREATE_ATTRIBUTE).equals("false")) { + stack.push("false"); + } else { + stack.push("true"); + } + if (attr.getValue(INSERT_OVERWRITE_ATTRIBUTE) != null + && attr.getValue(INSERT_OVERWRITE_ATTRIBUTE).equals("false")) { + stack.push("false"); + } else { + stack.push("true"); + } + stack.push("INSERT"); + + + // Element: file + } else if (name.equals(FILE_ELEMENT) + && this.state == STATE_INSERT) { + state = STATE_FILE; + this.startTextRecording(); + + // Element: path + } else if (name.equals(PATH_ELEMENT) + && this.state == STATE_INSERT) { + state = STATE_PATH; + this.startTextRecording(); + + // Element: replace + } else if (name.equals(REPLACE_ELEMENT) + && this.state == STATE_INSERT) { + state = STATE_REPLACE; + this.startTextRecording(); + + // Element: fragment + } else if (name.equals(FRAGMENT_ELEMENT) + && this.state == STATE_INSERT) { + state = STATE_FRAGMENT; + this.startRecording(); + + // Element: reinsert + } else if (name.equals(REINSERT_ELEMENT) + && this.state == STATE_INSERT) { + 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)wsource.getContentHandler(); + } + this.addRecorder( this.ch ); + this.startDocument(); + this.sendStartPrefixMapping(); + + } catch (Exception e) { + getLogger().warn("failed, " + this.message, e); + this.failed = true; + try { + 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); + } + + if (this.getLogger().isDebugEnabled() == true) { + this.getLogger().debug("END startTransformingElement"); + } } @@ -328,239 +445,300 @@ * @param raw The raw XML 1.0 name (with prefix), or the empty string if * raw names are not available. */ - public void endElement(String uri, String loc, String raw) - throws SAXException { - if (!this.processing) { - super.endElement(uri,loc,raw); - } else { - if (SWT_URI.equals(uri) && SWT_ELEMENT.equals(loc)){ - if (!this.failed) { - this.ch.endDocument(); - } - this.processing = false; - getLogger().debug("Processing Ended"); - // 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"; - this.wsource.cancel(this.ch); - } catch (Exception e2) { - getLogger().warn("failed to cancel: " + this.target, e2); - } - } finally { - if (this.source != null) { - this.source.recycle(); - } - } - 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.startElement(uri, loc, raw, attrs); - if (this.message != null && this.failed == true) super.characters(this.message.toCharArray(), 0, this.message.length()); - super.endElement(uri, loc, raw); - getLogger().debug("Source Written"); - } else if (this.ch != null){ - this.ch.endElement(uri, loc, raw); - } - } - } - - /** - * Receive notification of character data. - * - * @param c The characters from the XML document. - * @param start The start position in the array. - * @param len The number of characters to read from the array. - */ - public void characters(char c[], int start, int len) throws SAXException { - if (!this.processing) { - super.characters(c,start,len); - } else if (this.ch != null){ - this.ch.characters(c,start,len); - } - } - - /** - * Receive notification of ignorable whitespace in element content. - * - * @param c The characters from the XML document. - * @param start The start position in the array. - * @param len The number of characters to read from the array. - */ - public void ignorableWhitespace(char c[], int start, int len) throws SAXException { - if (!this.processing) { - super.ignorableWhitespace(c,start,len); - } else if (this.ch != null){ - this.ch.ignorableWhitespace(c,start,len); - } - } - - /** - * Receive notification of a processing instruction. - * - * @param target The processing instruction target. - * @param data The processing instruction data, or null if none was - * supplied. - */ - public void processingInstruction(String target, String data) throws SAXException { - if (!this.processing) { - super.processingInstruction(target,data); - } else if (this.ch != null){ - this.ch.processingInstruction(target,data); - } - } - - /** - * Receive notification of a skipped entity. - * - * @param name The name of the skipped entity. If it is a parameter - * entity, the name will begin with '%'. - */ - public void skippedEntity(String name) throws SAXException { - if (!this.processing) { - super.skippedEntity(name); - } else if (this.ch != null){ - this.ch.skippedEntity(name); - } - } - - /** - * Report the start of DTD declarations, if any. - * - * @param name The document type name. - * @param publicId The declared public identifier for the external DTD - * subset, or null if none was declared. - * @param systemId The declared system identifier for the external DTD - * subset, or null if none was declared. - */ - public void startDTD(String name, String publicId, String systemId) throws SAXException { - if (!this.processing) - super.startDTD(name,publicId,systemId); - } - - /** - * Report the end of DTD declarations. - */ - public void endDTD() throws SAXException { - if (!this.processing) - super.endDTD(); - } - - /** - * Report the beginning of an entity. - * - * @param name The name of the entity. If it is a parameter entity, the - * name will begin with '%'. - */ - public void startEntity(String name) throws SAXException { - if (!this.processing) { - super.startEntity(name); - } else if (this.ch != null){ - this.ch.startEntity(name); - } - } - - /** - * Report the end of an entity. - * - * @param name The name of the entity that is ending. - */ - public void endEntity(String name) throws SAXException { - if (!this.processing) { - super.endEntity(name); - } else if (this.ch != null){ - this.ch.endEntity(name); - } - } - - /** - * Report the start of a CDATA section. - */ - public void startCDATA() throws SAXException { - if (!this.processing) { - super.startCDATA(); - } else if (this.ch != null){ - this.ch.startCDATA(); - } - } - - /** - * Report the end of a CDATA section. - */ - public void endCDATA() throws SAXException { - if (!this.processing) { - super.endCDATA(); - } else if (this.ch != null){ - this.ch.endCDATA(); - } - } - - /** - * Report an XML comment anywhere in the document. - * - * @param ch An array holding the characters in the comment. - * @param start The starting position in the array. - * @param len The number of characters to use from the array. - */ - public void comment(char ch[], int start, int len) throws SAXException { - if (!this.processing) { - super.comment(ch,start,len); - } else if (this.ch != null){ - this.ch.comment(ch,start,len); - } + public void endTransformingElement(String uri, String name, String raw) + throws SAXException, IOException, ProcessingException { + if (this.getLogger().isDebugEnabled() == true) { + this.getLogger().debug("BEGIN endTransformingElement uri=" + uri + + ", name=" + name + + ", raw=" + raw); + } + if (name.equals(INSERT_ELEMENT) == true && this.state == STATE_INSERT) { + state = STATE_OUTSIDE; + + // get the information from the stack + String tag; + String fileName = null; + DocumentFragment fragment = null; + String path = null; + String replacePath = null; + String reinsert = null; + do { + tag = (String)stack.pop(); + if (tag.equals("PATH") == true) { + path = (String)stack.pop(); + } else if (tag.equals("FILE") == true) { + fileName = (String)stack.pop(); + } else if (tag.equals("FRAGMENT") == true) { + fragment = (DocumentFragment)stack.pop(); + } else if (tag.equals("REPLACE") == true) { + replacePath = (String)stack.pop(); + } else if (tag.equals("REINSERT") == true) { + reinsert = (String)stack.pop(); + } + } while (tag.equals("INSERT") == false); + final boolean overwrite = stack.pop().equals("true"); + final boolean create = stack.pop().equals("true"); + + /**this.insertFragment(fileName, + path, + fragment, + replacePath, + create, + overwrite, + reinsert); + */ + // Element: file + } else if (name.equals(FILE_ELEMENT) == true && this.state == STATE_FILE) { + state = STATE_INSERT; + stack.push(this.endTextRecording()); + stack.push("FILE"); + + // Element: path + } else if (name.equals(PATH_ELEMENT) == true && this.state == STATE_PATH) { + state = STATE_INSERT; + stack.push(this.endTextRecording()); + stack.push("PATH"); + + // Element: replace + } else if (name.equals(REPLACE_ELEMENT) == true && this.state == STATE_REPLACE) { + state = STATE_INSERT; + stack.push(this.endTextRecording()); + stack.push("REPLACE"); + + // Element: fragment + } else if (name.equals(FRAGMENT_ELEMENT) == true && this.state == STATE_FRAGMENT) { + state = STATE_INSERT; + stack.push(this.endRecording()); + stack.push("FRAGMENT"); + + // Element: reinsert + } else if (name.equals(REINSERT_ELEMENT) == true + && this.state == STATE_REINSERT) { + state = STATE_INSERT; + stack.push(this.endTextRecording()); + 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"; + 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.startElement(uri, name, raw, attrs); + if (this.message != null && this.failed == true) super.characters(this.message.toCharArray(), 0, this.message.length()); + super.endElement(uri, name, raw); + getLogger().debug("Source Written"); + } + // default + } else { + super.endTransformingElement(uri, name, raw); + } + + if (this.getLogger().isDebugEnabled() == true) { + this.getLogger().debug("END endTransformingElement"); + } } 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 { - this.wsource.cancel(this.ch); - } catch (Exception e) { - getLogger().error("failed to cancel in recycle() method: ContentHandler"); - } - } - } - - if (isSerializer) this.manager.release((Component)this.ch); - this.sourceResolver = null; + 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 { + 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(); + } + + /** + * Insert a fragment into a file. + * The file is loaded by the resource connector. + * + * @param fileName The name of the xml file. + * @param path The XPath specifying the node under which the data is inserted + * @param fragment The data to be inserted. + * @param replacePath Optional XPath relative to <CODE>path</CODE>. This path + * can specify a node which will be removed if it exists. + * So insertFragment can be used as a replace utility. + * @param create If the file does not exists and this is set to + * <CODE>false</CODE> nothing is inserted. If it is set + * to <CODE>true</CODE> the file is created and the data + * is inserted. + * @param overwrite If this is set to <CODE>true</CODE> the data is only + * inserted if the node specified by the <CODE>replacePath</CODE> + * 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. + */ + public void insertFragment(String fileName, + String path, + DocumentFragment fragment, + String replacePath, + boolean create, + boolean overwrite, + String reinsertPath) + throws SAXException, IOException, ProcessingException { + // no sync req + if (this.getLogger().isDebugEnabled() == true) { + this.getLogger().debug("BEGIN insertFragment fileName="+fileName+ + ", path="+path+ + ", replace="+replacePath+ + ", create="+create+ + ", overwrite="+overwrite+ + ", resinsert="+reinsertPath+ + ", fragment="+(fragment == null ? "null" : XMLUtils.serializeNodeToXML(fragment))); + } + // test parameter + if (fileName == null) { + throw new ProcessingException("insertFragment: file name is required."); + } + if (path == null) { + throw new ProcessingException("insertFragment: path is required."); + } + if (fragment == null) { + throw new ProcessingException("insertFragment: fragment is required."); + } + + Source fileSource = null; + String systemId = null; + try { + fileSource = this.resolver.resolveURI( fileName ); + systemId = fileSource.getSystemId(); + if (systemId.startsWith("file:") == false) { + throw new ProcessingException("insertFragment: this is not a file: " + systemId); + } + } catch (SourceException se) { + throw new ProcessingException("Error during resolving.", se); + } finally { + if (fileSource != null) this.resolver.release(fileSource); + } + if (path.startsWith("/") == true) path = path.substring(1); + + File file = new File(systemId.substring(5)); + DocumentFragment resource = null; + if (file.exists() == true) { + resource = this.getResourceConnector().loadXML(ResourceConnector.RESOURCE_TYPE_FILE, null, + fileName, null); + + // import the fragment + Node importNode = resource.getOwnerDocument().importNode(fragment, true); + + // get the node + Node parent = XMLUtil.selectSingleNode(resource, path); + + // replace? + 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); + if (reinsertPath != null) { + Node insertAt = XMLUtil.getSingleNode(importNode, reinsertPath); + if (insertAt != null) { + while (replaceNode.hasChildNodes() == true) { + insertAt.appendChild(replaceNode.getFirstChild()); + } + } + } + } + } else { + parent.appendChild(importNode); + } + } catch (javax.xml.transform.TransformerException sax) { + throw new ProcessingException("TransformerException: " + sax, sax); + } + } else { // no replace + parent.appendChild(importNode); + } + } else { + if (create == true) { + Document doc = XMLUtil.createDocument(); + resource = doc.createDocumentFragment(); + // import the fragment + Node importNode = resource.getOwnerDocument().importNode(fragment, true); + // get the node + Node parent = XMLUtil.selectSingleNode(resource, path); + // add fragment + parent.appendChild(importNode); + } + } + + if (resource != null) { + // finally: save resource + resource.normalize(); + this.getResourceConnector().saveXML(ResourceConnector.RESOURCE_TYPE_FILE, null, + fileName, null, + resource); + } + + if (this.getLogger().isDebugEnabled() == true) { + this.getLogger().debug("END insertFragment"); + } } - /** - * dispose - */ - public void dispose() { - } + }
---------------------------------------------------------------------- In case of troubles, e-mail: [EMAIL PROTECTED] To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]